From f7780d692a742eab58e03e9cd9e7aa1a64543c76 Mon Sep 17 00:00:00 2001 From: inovindasari Date: Tue, 20 Jan 2026 15:51:29 +0100 Subject: [PATCH 01/17] Add support for pg18 and remove pg13 --- README.md | 6 +-- .../templates/deployment.yaml | 2 +- .../crds/operatorconfigurations.yaml | 6 +-- .../postgres-operator/crds/postgresqls.yaml | 2 +- charts/postgres-operator/values.yaml | 8 ++-- docs/administrator.md | 2 +- docs/reference/cluster_manifest.md | 4 +- docs/reference/operator_parameters.md | 4 +- docs/user.md | 18 ++++---- e2e/Makefile | 2 +- e2e/run.sh | 2 +- e2e/tests/test_e2e.py | 46 +++++++++---------- logical-backup/Dockerfile | 2 +- manifests/complete-postgres-manifest.yaml | 4 +- manifests/configmap.yaml | 6 +-- .../minimal-master-replica-svcmonitor.yaml | 2 +- ...imal-postgres-lowest-version-manifest.yaml | 2 +- manifests/minimal-postgres-manifest.yaml | 2 +- manifests/operatorconfiguration.crd.yaml | 6 +-- ...gresql-operator-default-configuration.yaml | 6 +-- manifests/postgresql.crd.yaml | 2 +- manifests/standby-manifest.yaml | 2 +- .../v1/operator_configuration_type.go | 4 +- pkg/apis/acid.zalan.do/v1/postgresql_type.go | 2 +- pkg/apis/acid.zalan.do/v1/util_test.go | 10 ++-- pkg/cluster/k8sres_test.go | 38 +++++++-------- pkg/cluster/majorversionupgrade.go | 4 +- pkg/controller/operator_config.go | 6 +-- pkg/util/config/config.go | 6 +-- ui/manifests/deployment.yaml | 2 +- ui/operator_ui/main.py | 2 +- ui/run_local.sh | 2 +- 32 files changed, 105 insertions(+), 107 deletions(-) diff --git a/README.md b/README.md index 7d54e9fd9..9e5bc886b 100644 --- a/README.md +++ b/README.md @@ -29,13 +29,13 @@ pipelines with no access to Kubernetes API directly, promoting infrastructure as ### PostgreSQL features -* Supports PostgreSQL 17, starting from 13+ +* Supports PostgreSQL 18, starting from 14+ * Streaming replication cluster via Patroni * Point-In-Time-Recovery with -[pg_basebackup](https://www.postgresql.org/docs/17/app-pgbasebackup.html) / +[pg_basebackup](https://www.postgresql.org/docs/18/app-pgbasebackup.html) / [WAL-G](https://github.com/wal-g/wal-g) or [WAL-E](https://github.com/wal-e/wal-e) via [Spilo](https://github.com/zalando/spilo) * Preload libraries: [bg_mon](https://github.com/CyberDem0n/bg_mon), -[pg_stat_statements](https://www.postgresql.org/docs/17/pgstatstatements.html), +[pg_stat_statements](https://www.postgresql.org/docs/18/pgstatstatements.html), [pgextwlist](https://github.com/dimitri/pgextwlist), [pg_auth_mon](https://github.com/RafiaSabih/pg_auth_mon) * Incl. popular Postgres extensions such as diff --git a/charts/postgres-operator-ui/templates/deployment.yaml b/charts/postgres-operator-ui/templates/deployment.yaml index fbb9ee086..c8797e42e 100644 --- a/charts/postgres-operator-ui/templates/deployment.yaml +++ b/charts/postgres-operator-ui/templates/deployment.yaml @@ -84,11 +84,11 @@ spec: "limit_iops": 16000, "limit_throughput": 1000, "postgresql_versions": [ + "18", "17", "16", "15", "14", - "13" ] } {{- if .Values.extraEnvs }} diff --git a/charts/postgres-operator/crds/operatorconfigurations.yaml b/charts/postgres-operator/crds/operatorconfigurations.yaml index c903a9319..0d0be3d25 100644 --- a/charts/postgres-operator/crds/operatorconfigurations.yaml +++ b/charts/postgres-operator/crds/operatorconfigurations.yaml @@ -68,7 +68,7 @@ spec: type: string docker_image: type: string - default: "ghcr.io/zalando/spilo-17:4.0-p3" + default: "container-registry-test.zalando.net/acid/spilo-cdp-pr1156-18:4.1-p18" enable_crd_registration: type: boolean default: true @@ -169,10 +169,10 @@ spec: type: string minimal_major_version: type: string - default: "13" + default: "14" target_major_version: type: string - default: "17" + default: "18" kubernetes: type: object properties: diff --git a/charts/postgres-operator/crds/postgresqls.yaml b/charts/postgres-operator/crds/postgresqls.yaml index cbf5c98ef..c801346e4 100644 --- a/charts/postgres-operator/crds/postgresqls.yaml +++ b/charts/postgres-operator/crds/postgresqls.yaml @@ -374,11 +374,11 @@ spec: version: type: string enum: - - "13" - "14" - "15" - "16" - "17" + - "18" parameters: type: object additionalProperties: diff --git a/charts/postgres-operator/values.yaml b/charts/postgres-operator/values.yaml index 4e5d9b7cb..2b061e1b5 100644 --- a/charts/postgres-operator/values.yaml +++ b/charts/postgres-operator/values.yaml @@ -31,14 +31,12 @@ configGeneral: enable_pgversion_env_var: true # start any new database pod without limitations on shm memory enable_shm_volume: true - # enables backwards compatible path between Spilo 12 and Spilo 13+ images - enable_spilo_wal_path_compat: false # operator will sync only clusters where name starts with teamId prefix enable_team_id_clustername_prefix: false # etcd connection string for Patroni. Empty uses K8s-native DCS. etcd_host: "" # Spilo docker image - docker_image: ghcr.io/zalando/spilo-17:4.0-p3 + docker_image: container-registry-test.zalando.net/acid/spilo-cdp-pr1156-18:4.1-p18 # key name for annotation to ignore globally configured instance limits # ignore_instance_limits_annotation_key: "" @@ -92,9 +90,9 @@ configMajorVersionUpgrade: # - acid # minimal Postgres major version that will not automatically be upgraded - minimal_major_version: "13" + minimal_major_version: "14" # target Postgres major version when upgrading clusters automatically - target_major_version: "17" + target_major_version: "18" configKubernetes: # list of additional capabilities for postgres container diff --git a/docs/administrator.md b/docs/administrator.md index fe36e3744..60db0f3f1 100644 --- a/docs/administrator.md +++ b/docs/administrator.md @@ -1312,7 +1312,7 @@ aws_or_gcp: If cluster members have to be (re)initialized restoring physical backups happens automatically either from the backup location or by running -[pg_basebackup](https://www.postgresql.org/docs/17/app-pgbasebackup.html) +[pg_basebackup](https://www.postgresql.org/docs/18/app-pgbasebackup.html) on one of the other running instances (preferably replicas if they do not lag behind). You can test restoring backups by [cloning](user.md#how-to-clone-an-existing-postgresql-cluster) clusters. diff --git a/docs/reference/cluster_manifest.md b/docs/reference/cluster_manifest.md index 7b4ef7ada..7bf35e416 100644 --- a/docs/reference/cluster_manifest.md +++ b/docs/reference/cluster_manifest.md @@ -647,7 +647,7 @@ the global configuration before adding the `tls` section'. ## Change data capture streams This sections enables change data capture (CDC) streams via Postgres' -[logical decoding](https://www.postgresql.org/docs/17/logicaldecoding.html) +[logical decoding](https://www.postgresql.org/docs/18/logicaldecoding.html) feature and `pgoutput` plugin. While the Postgres operator takes responsibility for providing the setup to publish change events, it relies on external tools to consume them. At Zalando, we are using a workflow based on @@ -680,7 +680,7 @@ can have the following properties: The CDC operator is following the [outbox pattern](https://debezium.io/blog/2019/02/19/reliable-microservices-data-exchange-with-the-outbox-pattern/). The application is responsible for putting events into a (JSON/B or VARCHAR) payload column of the outbox table in the structure of the specified target - event type. The operator will create a [PUBLICATION](https://www.postgresql.org/docs/17/logical-replication-publication.html) + event type. The operator will create a [PUBLICATION](https://www.postgresql.org/docs/18/logical-replication-publication.html) in Postgres for all tables specified for one `database` and `applicationId`. The CDC operator will consume from it shortly after transactions are committed to the outbox table. The `idColumn` will be used in telemetry for diff --git a/docs/reference/operator_parameters.md b/docs/reference/operator_parameters.md index 4327dc45f..7a4fdb04b 100644 --- a/docs/reference/operator_parameters.md +++ b/docs/reference/operator_parameters.md @@ -260,12 +260,12 @@ CRD-configuration, they are grouped under the `major_version_upgrade` key. * **minimal_major_version** The minimal Postgres major version that will not automatically be upgraded - when `major_version_upgrade_mode` is set to `"full"`. The default is `"13"`. + when `major_version_upgrade_mode` is set to `"full"`. The default is `"14"`. * **target_major_version** The target Postgres major version when upgrading clusters automatically which violate the configured allowed `minimal_major_version` when - `major_version_upgrade_mode` is set to `"full"`. The default is `"17"`. + `major_version_upgrade_mode` is set to `"full"`. The default is `"18"`. ## Kubernetes resources diff --git a/docs/user.md b/docs/user.md index db33d0bd6..236b439a8 100644 --- a/docs/user.md +++ b/docs/user.md @@ -30,7 +30,7 @@ spec: databases: foo: zalando postgresql: - version: "17" + version: "18" ``` Once you cloned the Postgres Operator [repository](https://github.com/zalando/postgres-operator) @@ -109,7 +109,7 @@ metadata: spec: [...] postgresql: - version: "17" + version: "18" parameters: password_encryption: scram-sha-256 ``` @@ -517,7 +517,7 @@ Postgres Operator will create the following NOLOGIN roles: The `_owner` role is the database owner and should be used when creating new database objects. All members of the `admin` role, e.g. teams API roles, can -become the owner with the `SET ROLE` command. [Default privileges](https://www.postgresql.org/docs/17/sql-alterdefaultprivileges.html) +become the owner with the `SET ROLE` command. [Default privileges](https://www.postgresql.org/docs/18/sql-alterdefaultprivileges.html) are configured for the owner role so that the `_reader` role automatically gets read-access (SELECT) to new tables and sequences and the `_writer` receives write-access (INSERT, UPDATE, DELETE on tables, @@ -594,7 +594,7 @@ spec: ### Schema `search_path` for default roles -The schema [`search_path`](https://www.postgresql.org/docs/17/ddl-schemas.html#DDL-SCHEMAS-PATH) +The schema [`search_path`](https://www.postgresql.org/docs/18/ddl-schemas.html#DDL-SCHEMAS-PATH) for each role will include the role name and the schemas, this role should have access to. So `foo_bar_writer` does not have to schema-qualify tables from schemas `foo_bar_writer, bar`, while `foo_writer` can look up `foo_writer` and @@ -695,7 +695,7 @@ handle it. ### HugePages support -The operator supports [HugePages](https://www.postgresql.org/docs/17/kernel-resources.html#LINUX-HUGEPAGES). +The operator supports [HugePages](https://www.postgresql.org/docs/18/kernel-resources.html#LINUX-HUGEPAGES). To enable HugePages, set the matching resource requests and/or limits in the manifest: ```yaml @@ -757,7 +757,7 @@ If you need to define a `nodeAffinity` for all your Postgres clusters use the ## In-place major version upgrade -Starting with Spilo 13, operator supports in-place major version upgrade to a +Starting with Spilo 14, operator supports in-place major version upgrade to a higher major version (e.g. from PG 14 to PG 16). To trigger the upgrade, simply increase the version in the manifest. It is your responsibility to test your applications against the new version before the upgrade; downgrading is @@ -792,7 +792,7 @@ spec: clone: uid: "efd12e58-5786-11e8-b5a7-06148230260c" cluster: "acid-minimal-cluster" - timestamp: "2017-12-19T12:40:33+01:00" + timestamp: "2025-12-19T12:40:33+01:00" ``` Here `cluster` is a name of a source cluster that is going to be cloned. A new @@ -827,7 +827,7 @@ spec: clone: uid: "efd12e58-5786-11e8-b5a7-06148230260c" cluster: "acid-minimal-cluster" - timestamp: "2017-12-19T12:40:33+01:00" + timestamp: "2025-12-19T12:40:33+01:00" s3_wal_path: "s3://custom/path/to/bucket" s3_endpoint: https://s3.acme.org s3_access_key_id: 0123456789abcdef0123456789abcdef @@ -838,7 +838,7 @@ spec: ### Clone directly Another way to get a fresh copy of your source DB cluster is via -[pg_basebackup](https://www.postgresql.org/docs/17/app-pgbasebackup.html). To +[pg_basebackup](https://www.postgresql.org/docs/18/app-pgbasebackup.html). To use this feature simply leave out the timestamp field from the clone section. The operator will connect to the service of the source cluster by name. If the cluster is called test, then the connection string will look like host=test diff --git a/e2e/Makefile b/e2e/Makefile index 5fa0de471..992491f9c 100644 --- a/e2e/Makefile +++ b/e2e/Makefile @@ -46,7 +46,7 @@ tools: # install pinned version of 'kind' # go install must run outside of a dir with a (module-based) Go project ! # otherwise go install updates project's dependencies and/or behaves differently - cd "/tmp" && GO111MODULE=on go install sigs.k8s.io/kind@v0.27.0 + cd "/tmp" && GO111MODULE=on go install sigs.k8s.io/kind@v0.31.0 e2etest: tools copy clean ./run.sh main diff --git a/e2e/run.sh b/e2e/run.sh index b0f13f92e..5a80f1966 100755 --- a/e2e/run.sh +++ b/e2e/run.sh @@ -8,7 +8,7 @@ IFS=$'\n\t' readonly cluster_name="postgres-operator-e2e-tests" readonly kubeconfig_path="/tmp/kind-config-${cluster_name}" -readonly spilo_image="registry.opensource.zalan.do/acid/spilo-17-e2e:0.3" +readonly spilo_image="container-registry-test.zalando.net/acid/spilo-cdp-pr1156-18:4.1-p18" readonly e2e_test_runner_image="ghcr.io/zalando/postgres-operator-e2e-tests-runner:latest" export GOPATH=${GOPATH-~/go} diff --git a/e2e/tests/test_e2e.py b/e2e/tests/test_e2e.py index f473b5cc4..083b4a937 100644 --- a/e2e/tests/test_e2e.py +++ b/e2e/tests/test_e2e.py @@ -12,9 +12,9 @@ from tests.k8s_api import K8s from kubernetes.client.rest import ApiException -SPILO_CURRENT = "registry.opensource.zalan.do/acid/spilo-17-e2e:0.3" -SPILO_LAZY = "registry.opensource.zalan.do/acid/spilo-17-e2e:0.4" -SPILO_FULL_IMAGE = "ghcr.io/zalando/spilo-17:4.0-p3" +SPILO_CURRENT = "container-registry-test.zalando.net/acid/spilo-cdp-pr1156-18:4.1-p18" +SPILO_LAZY = "container-registry-test.zalando.net/acid/spilo-cdp-pr1156-18:4.1-p19" +SPILO_FULL_IMAGE = "container-registry-test.zalando.net/acid/spilo-cdp-pr1156-18:4.1-p18" def to_selector(labels): return ",".join(["=".join(lbl) for lbl in labels.items()]) @@ -1211,25 +1211,25 @@ def get_annotations(): k8s.create_with_kubectl("manifests/minimal-postgres-lowest-version-manifest.yaml") self.eventuallyEqual(lambda: k8s.count_running_pods(labels=cluster_label), 2, "No 2 pods running") self.eventuallyEqual(lambda: k8s.get_operator_state(), {"0": "idle"}, "Operator does not get in sync") - self.eventuallyEqual(check_version, 13, "Version is not correct") + self.eventuallyEqual(check_version, 14, "Version is not correct") master_nodes, _ = k8s.get_cluster_nodes(cluster_labels=cluster_label) # should upgrade immediately - pg_patch_version_14 = { + pg_patch_version_higher_version = { "spec": { "postgresql": { - "version": "14" + "version": "15" } } } k8s.api.custom_objects_api.patch_namespaced_custom_object( - "acid.zalan.do", "v1", "default", "postgresqls", "acid-upgrade-test", pg_patch_version_14) + "acid.zalan.do", "v1", "default", "postgresqls", "acid-upgrade-test", pg_patch_version_higher_version) self.eventuallyEqual(lambda: k8s.get_operator_state(), {"0": "idle"}, "Operator does not get in sync") k8s.wait_for_pod_failover(master_nodes, 'spilo-role=replica,' + cluster_label) k8s.wait_for_pod_start('spilo-role=master,' + cluster_label) k8s.wait_for_pod_start('spilo-role=replica,' + cluster_label) - self.eventuallyEqual(check_version, 14, "Version should be upgraded from 13 to 14") + self.eventuallyEqual(check_version, 15, "Version should be upgraded from 14 to 15") # check if annotation for last upgrade's success is set annotations = get_annotations() @@ -1238,10 +1238,10 @@ def get_annotations(): # should not upgrade because current time is not in maintenanceWindow current_time = datetime.now() maintenance_window_future = f"{(current_time+timedelta(minutes=60)).strftime('%H:%M')}-{(current_time+timedelta(minutes=120)).strftime('%H:%M')}" - pg_patch_version_15_outside_mw = { + pg_patch_version_higher_version_outside_mw = { "spec": { "postgresql": { - "version": "15" + "version": "16" }, "maintenanceWindows": [ maintenance_window_future @@ -1249,23 +1249,23 @@ def get_annotations(): } } k8s.api.custom_objects_api.patch_namespaced_custom_object( - "acid.zalan.do", "v1", "default", "postgresqls", "acid-upgrade-test", pg_patch_version_15_outside_mw) + "acid.zalan.do", "v1", "default", "postgresqls", "acid-upgrade-test", pg_patch_version_higher_version_outside_mw) self.eventuallyEqual(lambda: k8s.get_operator_state(), {"0": "idle"}, "Operator does not get in sync") # no pod replacement outside of the maintenance window k8s.wait_for_pod_start('spilo-role=master,' + cluster_label) k8s.wait_for_pod_start('spilo-role=replica,' + cluster_label) - self.eventuallyEqual(check_version, 14, "Version should not be upgraded") + self.eventuallyEqual(check_version, 15, "Version should not be upgraded") second_annotations = get_annotations() self.assertIsNone(second_annotations.get("last-major-upgrade-failure"), "Annotation for last upgrade's failure should not be set") # change maintenanceWindows to current maintenance_window_current = f"{(current_time-timedelta(minutes=30)).strftime('%H:%M')}-{(current_time+timedelta(minutes=30)).strftime('%H:%M')}" - pg_patch_version_15_in_mw = { + pg_patch_version_higher_version_in_mw = { "spec": { "postgresql": { - "version": "15" + "version": "16" }, "maintenanceWindows": [ maintenance_window_current @@ -1274,13 +1274,13 @@ def get_annotations(): } k8s.api.custom_objects_api.patch_namespaced_custom_object( - "acid.zalan.do", "v1", "default", "postgresqls", "acid-upgrade-test", pg_patch_version_15_in_mw) + "acid.zalan.do", "v1", "default", "postgresqls", "acid-upgrade-test", pg_patch_version_higher_version_in_mw) self.eventuallyEqual(lambda: k8s.get_operator_state(), {"0": "idle"}, "Operator does not get in sync") k8s.wait_for_pod_failover(master_nodes, 'spilo-role=master,' + cluster_label) k8s.wait_for_pod_start('spilo-role=master,' + cluster_label) k8s.wait_for_pod_start('spilo-role=replica,' + cluster_label) - self.eventuallyEqual(check_version, 15, "Version should be upgraded from 14 to 15") + self.eventuallyEqual(check_version, 16, "Version should be upgraded from 15 to 16") # check if annotation for last upgrade's success is updated after second upgrade third_annotations = get_annotations() @@ -1288,7 +1288,7 @@ def get_annotations(): self.assertNotEqual(annotations.get("last-major-upgrade-success"), third_annotations.get("last-major-upgrade-success"), "Annotation for last upgrade's success is not updated") # test upgrade with failed upgrade annotation - pg_patch_version_17 = { + pg_patch_version_highest_version = { "metadata": { "annotations": { "last-major-upgrade-failure": "2024-01-02T15:04:05Z" @@ -1296,28 +1296,28 @@ def get_annotations(): }, "spec": { "postgresql": { - "version": "17" + "version": "18" }, }, } k8s.api.custom_objects_api.patch_namespaced_custom_object( - "acid.zalan.do", "v1", "default", "postgresqls", "acid-upgrade-test", pg_patch_version_17) + "acid.zalan.do", "v1", "default", "postgresqls", "acid-upgrade-test", pg_patch_version_highest_version) self.eventuallyEqual(lambda: k8s.get_operator_state(), {"0": "idle"}, "Operator does not get in sync") k8s.wait_for_pod_failover(master_nodes, 'spilo-role=replica,' + cluster_label) k8s.wait_for_pod_start('spilo-role=master,' + cluster_label) k8s.wait_for_pod_start('spilo-role=replica,' + cluster_label) - self.eventuallyEqual(check_version, 15, "Version should not be upgraded because annotation for last upgrade's failure is set") + self.eventuallyEqual(check_version, 16, "Version should not be upgraded because annotation for last upgrade's failure is set") - # change the version back to 15 and should remove failure annotation + # change the version back to 16 and should remove failure annotation k8s.api.custom_objects_api.patch_namespaced_custom_object( - "acid.zalan.do", "v1", "default", "postgresqls", "acid-upgrade-test", pg_patch_version_15_in_mw) + "acid.zalan.do", "v1", "default", "postgresqls", "acid-upgrade-test", pg_patch_version_higher_version_in_mw) self.eventuallyEqual(lambda: k8s.get_operator_state(), {"0": "idle"}, "Operator does not get in sync") k8s.wait_for_pod_start('spilo-role=master,' + cluster_label) k8s.wait_for_pod_start('spilo-role=replica,' + cluster_label) - self.eventuallyEqual(check_version, 15, "Version should not be upgraded from 15") + self.eventuallyEqual(check_version, 16, "Version should not be upgraded from 16") fourth_annotations = get_annotations() self.assertIsNone(fourth_annotations.get("last-major-upgrade-failure"), "Annotation for last upgrade's failure is not removed") diff --git a/logical-backup/Dockerfile b/logical-backup/Dockerfile index 137f4efa8..94b8f1a35 100644 --- a/logical-backup/Dockerfile +++ b/logical-backup/Dockerfile @@ -25,11 +25,11 @@ RUN apt-get update \ && curl --silent https://www.postgresql.org/media/keys/ACCC4CF8.asc | apt-key add - \ && apt-get update \ && apt-get install --no-install-recommends -y \ + postgresql-client-18 \ postgresql-client-17 \ postgresql-client-16 \ postgresql-client-15 \ postgresql-client-14 \ - postgresql-client-13 \ && apt-get clean \ && rm -rf /var/lib/apt/lists/* diff --git a/manifests/complete-postgres-manifest.yaml b/manifests/complete-postgres-manifest.yaml index 7677dca62..8cfbda28f 100644 --- a/manifests/complete-postgres-manifest.yaml +++ b/manifests/complete-postgres-manifest.yaml @@ -10,7 +10,7 @@ metadata: # "delete-date": "2020-08-31" # can only be deleted on that day if "delete-date "key is configured # "delete-clustername": "acid-test-cluster" # can only be deleted when name matches if "delete-clustername" key is configured spec: - dockerImage: ghcr.io/zalando/spilo-17:4.0-p3 + dockerImage: container-registry-test.zalando.net/acid/spilo-cdp-pr1156-18:4.1-p18 teamId: "acid" numberOfInstances: 2 users: # Application/Robot users @@ -48,7 +48,7 @@ spec: defaultRoles: true defaultUsers: false postgresql: - version: "17" + version: "18" parameters: # Expert section shared_buffers: "32MB" max_connections: "10" diff --git a/manifests/configmap.yaml b/manifests/configmap.yaml index 6d51053bb..db98ac302 100644 --- a/manifests/configmap.yaml +++ b/manifests/configmap.yaml @@ -34,7 +34,7 @@ data: default_memory_request: 100Mi # delete_annotation_date_key: delete-date # delete_annotation_name_key: delete-clustername - docker_image: ghcr.io/zalando/spilo-17:4.0-p3 + docker_image: container-registry-test.zalando.net/acid/spilo-cdp-pr1156-18:4.1-p18 # downscaler_annotations: "deployment-time,downscaler/*" enable_admin_role_for_users: "true" enable_crd_registration: "true" @@ -113,7 +113,7 @@ data: min_cpu_limit: 250m min_instances: "-1" min_memory_limit: 250Mi - minimal_major_version: "13" + minimal_major_version: "14" # node_readiness_label: "status:ready" # node_readiness_label_merge: "OR" oauth_token_secret_name: postgresql-operator @@ -163,7 +163,7 @@ data: spilo_privileged: "false" storage_resize_mode: "pvc" super_username: postgres - target_major_version: "17" + target_major_version: "18" team_admin_role: "admin" team_api_role_configuration: "log_statement:all" teams_api_url: http://fake-teams-api.default.svc.cluster.local diff --git a/manifests/minimal-master-replica-svcmonitor.yaml b/manifests/minimal-master-replica-svcmonitor.yaml index 049ea12eb..57bbd01d1 100644 --- a/manifests/minimal-master-replica-svcmonitor.yaml +++ b/manifests/minimal-master-replica-svcmonitor.yaml @@ -28,7 +28,7 @@ spec: preparedDatabases: bar: {} postgresql: - version: "13" + version: "18" sidecars: - name: "exporter" image: "quay.io/prometheuscommunity/postgres-exporter:v0.15.0" diff --git a/manifests/minimal-postgres-lowest-version-manifest.yaml b/manifests/minimal-postgres-lowest-version-manifest.yaml index 40abf0c9c..897925c56 100644 --- a/manifests/minimal-postgres-lowest-version-manifest.yaml +++ b/manifests/minimal-postgres-lowest-version-manifest.yaml @@ -17,4 +17,4 @@ spec: preparedDatabases: bar: {} postgresql: - version: "13" + version: "14" diff --git a/manifests/minimal-postgres-manifest.yaml b/manifests/minimal-postgres-manifest.yaml index 8b1ed275d..086ce553a 100644 --- a/manifests/minimal-postgres-manifest.yaml +++ b/manifests/minimal-postgres-manifest.yaml @@ -17,4 +17,4 @@ spec: preparedDatabases: bar: {} postgresql: - version: "17" + version: "18" diff --git a/manifests/operatorconfiguration.crd.yaml b/manifests/operatorconfiguration.crd.yaml index c78ceb77a..8249bf114 100644 --- a/manifests/operatorconfiguration.crd.yaml +++ b/manifests/operatorconfiguration.crd.yaml @@ -66,7 +66,7 @@ spec: type: string docker_image: type: string - default: "ghcr.io/zalando/spilo-17:4.0-p3" + default: "container-registry-test.zalando.net/acid/spilo-cdp-pr1156-18:4.1-p18" enable_crd_registration: type: boolean default: true @@ -167,10 +167,10 @@ spec: type: string minimal_major_version: type: string - default: "13" + default: "14" target_major_version: type: string - default: "17" + default: "18" kubernetes: type: object properties: diff --git a/manifests/postgresql-operator-default-configuration.yaml b/manifests/postgresql-operator-default-configuration.yaml index d4f9fc812..6037acc73 100644 --- a/manifests/postgresql-operator-default-configuration.yaml +++ b/manifests/postgresql-operator-default-configuration.yaml @@ -3,7 +3,7 @@ kind: OperatorConfiguration metadata: name: postgresql-operator-default-configuration configuration: - docker_image: ghcr.io/zalando/spilo-17:4.0-p3 + docker_image: container-registry-test.zalando.net/acid/spilo-cdp-pr1156-18:4.1-p18 # enable_crd_registration: true # crd_categories: # - all @@ -40,8 +40,8 @@ configuration: major_version_upgrade_mode: "manual" # major_version_upgrade_team_allow_list: # - acid - minimal_major_version: "13" - target_major_version: "17" + minimal_major_version: "14" + target_major_version: "18" kubernetes: # additional_pod_capabilities: # - "SYS_NICE" diff --git a/manifests/postgresql.crd.yaml b/manifests/postgresql.crd.yaml index c8bf1b07d..d50e0393b 100644 --- a/manifests/postgresql.crd.yaml +++ b/manifests/postgresql.crd.yaml @@ -3523,11 +3523,11 @@ spec: type: object version: enum: - - "13" - "14" - "15" - "16" - "17" + - "18" type: string required: - version diff --git a/manifests/standby-manifest.yaml b/manifests/standby-manifest.yaml index b06956a1b..de4f9edaf 100644 --- a/manifests/standby-manifest.yaml +++ b/manifests/standby-manifest.yaml @@ -8,7 +8,7 @@ spec: size: 1Gi numberOfInstances: 1 postgresql: - version: "17" + version: "18" # Make this a standby cluster. You can specify s3_wal_path or gs_wal_path for WAL archive, # standby_host for remote primary streaming, or combine standby_host with either WAL path. # Note: s3_wal_path and gs_wal_path are mutually exclusive. diff --git a/pkg/apis/acid.zalan.do/v1/operator_configuration_type.go b/pkg/apis/acid.zalan.do/v1/operator_configuration_type.go index 80cfbbcd7..28d5a5172 100644 --- a/pkg/apis/acid.zalan.do/v1/operator_configuration_type.go +++ b/pkg/apis/acid.zalan.do/v1/operator_configuration_type.go @@ -49,8 +49,8 @@ type PostgresUsersConfiguration struct { type MajorVersionUpgradeConfiguration struct { MajorVersionUpgradeMode string `json:"major_version_upgrade_mode" default:"manual"` // off - no actions, manual - manifest triggers action, full - manifest and minimal version violation trigger upgrade MajorVersionUpgradeTeamAllowList []string `json:"major_version_upgrade_team_allow_list,omitempty"` - MinimalMajorVersion string `json:"minimal_major_version" default:"13"` - TargetMajorVersion string `json:"target_major_version" default:"17"` + MinimalMajorVersion string `json:"minimal_major_version" default:"14"` + TargetMajorVersion string `json:"target_major_version" default:"18"` } // KubernetesMetaConfiguration defines k8s conf required for all Postgres clusters and the operator itself diff --git a/pkg/apis/acid.zalan.do/v1/postgresql_type.go b/pkg/apis/acid.zalan.do/v1/postgresql_type.go index b304db652..1dadfd06c 100644 --- a/pkg/apis/acid.zalan.do/v1/postgresql_type.go +++ b/pkg/apis/acid.zalan.do/v1/postgresql_type.go @@ -185,7 +185,7 @@ type AdditionalVolume struct { // PostgresqlParam describes PostgreSQL version and pairs of configuration parameter name - values. type PostgresqlParam struct { - // +kubebuilder:validation:Enum="13";"14";"15";"16";"17" + // +kubebuilder:validation:Enum="14";"15";"16";"17";"18" PgVersion string `json:"version"` Parameters map[string]string `json:"parameters,omitempty"` } diff --git a/pkg/apis/acid.zalan.do/v1/util_test.go b/pkg/apis/acid.zalan.do/v1/util_test.go index 9f3fe9bde..7d643857a 100644 --- a/pkg/apis/acid.zalan.do/v1/util_test.go +++ b/pkg/apis/acid.zalan.do/v1/util_test.go @@ -219,7 +219,7 @@ var unmarshalCluster = []struct { "127.0.0.1/32" ], "postgresql": { - "version": "17", + "version": "18", "parameters": { "shared_buffers": "32MB", "max_connections": "10", @@ -279,7 +279,7 @@ var unmarshalCluster = []struct { }, Spec: PostgresSpec{ PostgresqlParam: PostgresqlParam{ - PgVersion: "17", + PgVersion: "18", Parameters: map[string]string{ "shared_buffers": "32MB", "max_connections": "10", @@ -339,7 +339,7 @@ var unmarshalCluster = []struct { }, Error: "", }, - marshal: []byte(`{"kind":"Postgresql","apiVersion":"acid.zalan.do/v1","metadata":{"name":"acid-testcluster1","creationTimestamp":null},"spec":{"postgresql":{"version":"17","parameters":{"log_statement":"all","max_connections":"10","shared_buffers":"32MB"}},"pod_priority_class_name":"spilo-pod-priority","volume":{"size":"5Gi","storageClass":"SSD", "subPath": "subdir"},"enableShmVolume":false,"patroni":{"initdb":{"data-checksums":"true","encoding":"UTF8","locale":"en_US.UTF-8"},"pg_hba":["hostssl all all 0.0.0.0/0 md5","host all all 0.0.0.0/0 md5"],"ttl":30,"loop_wait":10,"retry_timeout":10,"maximum_lag_on_failover":33554432,"slots":{"permanent_logical_1":{"database":"foo","plugin":"pgoutput","type":"logical"}}},"resources":{"requests":{"cpu":"10m","memory":"50Mi"},"limits":{"cpu":"300m","memory":"3000Mi"}},"teamId":"acid","allowedSourceRanges":["127.0.0.1/32"],"numberOfInstances":2,"users":{"zalando":["superuser","createdb"]},"maintenanceWindows":["Mon:01:00-06:00","Sat:00:00-04:00","05:00-05:15"],"clone":{"cluster":"acid-batman"}},"status":{"PostgresClusterStatus":""}}`), + marshal: []byte(`{"kind":"Postgresql","apiVersion":"acid.zalan.do/v1","metadata":{"name":"acid-testcluster1","creationTimestamp":null},"spec":{"postgresql":{"version":"18","parameters":{"log_statement":"all","max_connections":"10","shared_buffers":"32MB"}},"pod_priority_class_name":"spilo-pod-priority","volume":{"size":"5Gi","storageClass":"SSD", "subPath": "subdir"},"enableShmVolume":false,"patroni":{"initdb":{"data-checksums":"true","encoding":"UTF8","locale":"en_US.UTF-8"},"pg_hba":["hostssl all all 0.0.0.0/0 md5","host all all 0.0.0.0/0 md5"],"ttl":30,"loop_wait":10,"retry_timeout":10,"maximum_lag_on_failover":33554432,"slots":{"permanent_logical_1":{"database":"foo","plugin":"pgoutput","type":"logical"}}},"resources":{"requests":{"cpu":"10m","memory":"50Mi"},"limits":{"cpu":"300m","memory":"3000Mi"}},"teamId":"acid","allowedSourceRanges":["127.0.0.1/32"],"numberOfInstances":2,"users":{"zalando":["superuser","createdb"]},"maintenanceWindows":["Mon:01:00-06:00","Sat:00:00-04:00","05:00-05:15"],"clone":{"cluster":"acid-batman"}},"status":{"PostgresClusterStatus":""}}`), err: nil}, { about: "example with clone", @@ -404,7 +404,7 @@ var postgresqlList = []struct { out PostgresqlList err error }{ - {"expect success", []byte(`{"apiVersion":"v1","items":[{"apiVersion":"acid.zalan.do/v1","kind":"Postgresql","metadata":{"labels":{"team":"acid"},"name":"acid-testcluster42","namespace":"default","resourceVersion":"30446957","selfLink":"/apis/acid.zalan.do/v1/namespaces/default/postgresqls/acid-testcluster42","uid":"857cd208-33dc-11e7-b20a-0699041e4b03"},"spec":{"allowedSourceRanges":["185.85.220.0/22"],"numberOfInstances":1,"postgresql":{"version":"17"},"teamId":"acid","volume":{"size":"10Gi"}},"status":{"PostgresClusterStatus":"Running"}}],"kind":"List","metadata":{},"resourceVersion":"","selfLink":""}`), + {"expect success", []byte(`{"apiVersion":"v1","items":[{"apiVersion":"acid.zalan.do/v1","kind":"Postgresql","metadata":{"labels":{"team":"acid"},"name":"acid-testcluster42","namespace":"default","resourceVersion":"30446957","selfLink":"/apis/acid.zalan.do/v1/namespaces/default/postgresqls/acid-testcluster42","uid":"857cd208-33dc-11e7-b20a-0699041e4b03"},"spec":{"allowedSourceRanges":["185.85.220.0/22"],"numberOfInstances":1,"postgresql":{"version":"18"},"teamId":"acid","volume":{"size":"10Gi"}},"status":{"PostgresClusterStatus":"Running"}}],"kind":"List","metadata":{},"resourceVersion":"","selfLink":""}`), PostgresqlList{ TypeMeta: metav1.TypeMeta{ Kind: "List", @@ -425,7 +425,7 @@ var postgresqlList = []struct { }, Spec: PostgresSpec{ ClusterName: "testcluster42", - PostgresqlParam: PostgresqlParam{PgVersion: "17"}, + PostgresqlParam: PostgresqlParam{PgVersion: "18"}, Volume: Volume{Size: "10Gi"}, TeamID: "acid", AllowedSourceRanges: []string{"185.85.220.0/22"}, diff --git a/pkg/cluster/k8sres_test.go b/pkg/cluster/k8sres_test.go index e39e18cd5..04f6476a6 100644 --- a/pkg/cluster/k8sres_test.go +++ b/pkg/cluster/k8sres_test.go @@ -72,18 +72,18 @@ func TestGenerateSpiloJSONConfiguration(t *testing.T) { }{ { subtest: "Patroni default configuration", - pgParam: &acidv1.PostgresqlParam{PgVersion: "17"}, + pgParam: &acidv1.PostgresqlParam{PgVersion: "18"}, patroni: &acidv1.Patroni{}, opConfig: &config.Config{ Auth: config.Auth{ PamRoleName: "zalandos", }, }, - result: `{"postgresql":{"bin_dir":"/usr/lib/postgresql/17/bin"},"bootstrap":{"initdb":[{"auth-host":"md5"},{"auth-local":"trust"}],"dcs":{}}}`, + result: `{"postgresql":{"bin_dir":"/usr/lib/postgresql/18/bin"},"bootstrap":{"initdb":[{"auth-host":"md5"},{"auth-local":"trust"}],"dcs":{}}}`, }, { subtest: "Patroni configured", - pgParam: &acidv1.PostgresqlParam{PgVersion: "17"}, + pgParam: &acidv1.PostgresqlParam{PgVersion: "18"}, patroni: &acidv1.Patroni{ InitDB: map[string]string{ "encoding": "UTF8", @@ -102,38 +102,38 @@ func TestGenerateSpiloJSONConfiguration(t *testing.T) { FailsafeMode: util.True(), }, opConfig: &config.Config{}, - result: `{"postgresql":{"bin_dir":"/usr/lib/postgresql/17/bin","pg_hba":["hostssl all all 0.0.0.0/0 md5","host all all 0.0.0.0/0 md5"]},"bootstrap":{"initdb":[{"auth-host":"md5"},{"auth-local":"trust"},"data-checksums",{"encoding":"UTF8"},{"locale":"en_US.UTF-8"}],"dcs":{"ttl":30,"loop_wait":10,"retry_timeout":10,"maximum_lag_on_failover":33554432,"synchronous_mode":true,"synchronous_mode_strict":true,"synchronous_node_count":1,"slots":{"permanent_logical_1":{"database":"foo","plugin":"pgoutput","type":"logical"}},"failsafe_mode":true}}}`, + result: `{"postgresql":{"bin_dir":"/usr/lib/postgresql/18/bin","pg_hba":["hostssl all all 0.0.0.0/0 md5","host all all 0.0.0.0/0 md5"]},"bootstrap":{"initdb":[{"auth-host":"md5"},{"auth-local":"trust"},"data-checksums",{"encoding":"UTF8"},{"locale":"en_US.UTF-8"}],"dcs":{"ttl":30,"loop_wait":10,"retry_timeout":10,"maximum_lag_on_failover":33554432,"synchronous_mode":true,"synchronous_mode_strict":true,"synchronous_node_count":1,"slots":{"permanent_logical_1":{"database":"foo","plugin":"pgoutput","type":"logical"}},"failsafe_mode":true}}}`, }, { subtest: "Patroni failsafe_mode configured globally", - pgParam: &acidv1.PostgresqlParam{PgVersion: "17"}, + pgParam: &acidv1.PostgresqlParam{PgVersion: "18"}, patroni: &acidv1.Patroni{}, opConfig: &config.Config{ EnablePatroniFailsafeMode: util.True(), }, - result: `{"postgresql":{"bin_dir":"/usr/lib/postgresql/17/bin"},"bootstrap":{"initdb":[{"auth-host":"md5"},{"auth-local":"trust"}],"dcs":{"failsafe_mode":true}}}`, + result: `{"postgresql":{"bin_dir":"/usr/lib/postgresql/18/bin"},"bootstrap":{"initdb":[{"auth-host":"md5"},{"auth-local":"trust"}],"dcs":{"failsafe_mode":true}}}`, }, { subtest: "Patroni failsafe_mode configured globally, disabled for cluster", - pgParam: &acidv1.PostgresqlParam{PgVersion: "17"}, + pgParam: &acidv1.PostgresqlParam{PgVersion: "18"}, patroni: &acidv1.Patroni{ FailsafeMode: util.False(), }, opConfig: &config.Config{ EnablePatroniFailsafeMode: util.True(), }, - result: `{"postgresql":{"bin_dir":"/usr/lib/postgresql/17/bin"},"bootstrap":{"initdb":[{"auth-host":"md5"},{"auth-local":"trust"}],"dcs":{"failsafe_mode":false}}}`, + result: `{"postgresql":{"bin_dir":"/usr/lib/postgresql/18/bin"},"bootstrap":{"initdb":[{"auth-host":"md5"},{"auth-local":"trust"}],"dcs":{"failsafe_mode":false}}}`, }, { subtest: "Patroni failsafe_mode disabled globally, configured for cluster", - pgParam: &acidv1.PostgresqlParam{PgVersion: "17"}, + pgParam: &acidv1.PostgresqlParam{PgVersion: "18"}, patroni: &acidv1.Patroni{ FailsafeMode: util.True(), }, opConfig: &config.Config{ EnablePatroniFailsafeMode: util.False(), }, - result: `{"postgresql":{"bin_dir":"/usr/lib/postgresql/17/bin"},"bootstrap":{"initdb":[{"auth-host":"md5"},{"auth-local":"trust"}],"dcs":{"failsafe_mode":true}}}`, + result: `{"postgresql":{"bin_dir":"/usr/lib/postgresql/18/bin"},"bootstrap":{"initdb":[{"auth-host":"md5"},{"auth-local":"trust"}],"dcs":{"failsafe_mode":true}}}`, }, } for _, tt := range tests { @@ -164,15 +164,15 @@ func TestExtractPgVersionFromBinPath(t *testing.T) { }, { subTest: "test current bin path against hard coded template", - binPath: "/usr/lib/postgresql/17/bin", + binPath: "/usr/lib/postgresql/18/bin", template: pgBinariesLocationTemplate, - expected: "17", + expected: "18", }, { subTest: "test alternative bin path against a matching template", - binPath: "/usr/pgsql-17/bin", + binPath: "/usr/pgsql-18/bin", template: "/usr/pgsql-%v/bin", - expected: "17", + expected: "18", }, } @@ -2188,7 +2188,7 @@ func TestSidecars(t *testing.T) { spec = acidv1.PostgresSpec{ PostgresqlParam: acidv1.PostgresqlParam{ - PgVersion: "17", + PgVersion: "18", Parameters: map[string]string{ "max_connections": "100", }, @@ -2381,7 +2381,7 @@ func TestContainerValidation(t *testing.T) { name: "init container without image", spec: acidv1.PostgresSpec{ PostgresqlParam: acidv1.PostgresqlParam{ - PgVersion: "17", + PgVersion: "18", }, TeamID: "myapp", NumberOfInstances: 1, @@ -2410,7 +2410,7 @@ func TestContainerValidation(t *testing.T) { name: "sidecar without name", spec: acidv1.PostgresSpec{ PostgresqlParam: acidv1.PostgresqlParam{ - PgVersion: "17", + PgVersion: "18", }, TeamID: "myapp", NumberOfInstances: 1, @@ -2439,7 +2439,7 @@ func TestContainerValidation(t *testing.T) { name: "sidecar without image", spec: acidv1.PostgresSpec{ PostgresqlParam: acidv1.PostgresqlParam{ - PgVersion: "17", + PgVersion: "18", }, TeamID: "myapp", NumberOfInstances: 1, @@ -2468,7 +2468,7 @@ func TestContainerValidation(t *testing.T) { name: "valid containers pass validation", spec: acidv1.PostgresSpec{ PostgresqlParam: acidv1.PostgresqlParam{ - PgVersion: "17", + PgVersion: "18", }, TeamID: "myapp", NumberOfInstances: 1, diff --git a/pkg/cluster/majorversionupgrade.go b/pkg/cluster/majorversionupgrade.go index b80cbaa09..5c391647c 100644 --- a/pkg/cluster/majorversionupgrade.go +++ b/pkg/cluster/majorversionupgrade.go @@ -16,11 +16,11 @@ import ( // VersionMap Map of version numbers var VersionMap = map[string]int{ - "13": 130000, "14": 140000, "15": 150000, "16": 160000, "17": 170000, + "18": 180000, } const ( @@ -44,7 +44,7 @@ func (c *Cluster) GetDesiredMajorVersionAsInt() int { func (c *Cluster) GetDesiredMajorVersion() string { if c.Config.OpConfig.MajorVersionUpgradeMode == "full" { - // e.g. current is 13, minimal is 13 allowing 13 to 17 clusters, everything below is upgraded + // e.g. current is 18, minimal is 18 allowing 18 to 18 clusters, everything below is upgraded if IsBiggerPostgresVersion(c.Spec.PgVersion, c.Config.OpConfig.MinimalMajorVersion) { c.logger.Infof("overwriting configured major version %s to %s", c.Spec.PgVersion, c.Config.OpConfig.TargetMajorVersion) return c.Config.OpConfig.TargetMajorVersion diff --git a/pkg/controller/operator_config.go b/pkg/controller/operator_config.go index 24d4ffcd3..6769cc16d 100644 --- a/pkg/controller/operator_config.go +++ b/pkg/controller/operator_config.go @@ -39,7 +39,7 @@ func (c *Controller) importConfigurationFromCRD(fromCRD *acidv1.OperatorConfigur result.EnableTeamIdClusternamePrefix = fromCRD.EnableTeamIdClusternamePrefix result.EtcdHost = fromCRD.EtcdHost result.KubernetesUseConfigMaps = fromCRD.KubernetesUseConfigMaps - result.DockerImage = util.Coalesce(fromCRD.DockerImage, "ghcr.io/zalando/spilo-17:4.0-p3") + result.DockerImage = util.Coalesce(fromCRD.DockerImage, "container-registry-test.zalando.net/acid/spilo-cdp-pr1156-18:4.1-p18") result.Workers = util.CoalesceUInt32(fromCRD.Workers, 8) result.MinInstances = fromCRD.MinInstances result.MaxInstances = fromCRD.MaxInstances @@ -63,8 +63,8 @@ func (c *Controller) importConfigurationFromCRD(fromCRD *acidv1.OperatorConfigur // major version upgrade config result.MajorVersionUpgradeMode = util.Coalesce(fromCRD.MajorVersionUpgrade.MajorVersionUpgradeMode, "manual") result.MajorVersionUpgradeTeamAllowList = fromCRD.MajorVersionUpgrade.MajorVersionUpgradeTeamAllowList - result.MinimalMajorVersion = util.Coalesce(fromCRD.MajorVersionUpgrade.MinimalMajorVersion, "13") - result.TargetMajorVersion = util.Coalesce(fromCRD.MajorVersionUpgrade.TargetMajorVersion, "17") + result.MinimalMajorVersion = util.Coalesce(fromCRD.MajorVersionUpgrade.MinimalMajorVersion, "14") + result.TargetMajorVersion = util.Coalesce(fromCRD.MajorVersionUpgrade.TargetMajorVersion, "18") // kubernetes config result.EnableOwnerReferences = util.CoalesceBool(fromCRD.Kubernetes.EnableOwnerReferences, util.False()) diff --git a/pkg/util/config/config.go b/pkg/util/config/config.go index 858a58b8c..855898e81 100644 --- a/pkg/util/config/config.go +++ b/pkg/util/config/config.go @@ -177,7 +177,7 @@ type Config struct { WatchedNamespace string `name:"watched_namespace"` // special values: "*" means 'watch all namespaces', the empty string "" means 'watch a namespace where operator is deployed to' KubernetesUseConfigMaps bool `name:"kubernetes_use_configmaps" default:"false"` EtcdHost string `name:"etcd_host" default:""` // special values: the empty string "" means Patroni will use K8s as a DCS - DockerImage string `name:"docker_image" default:"ghcr.io/zalando/spilo-17:4.0-p3"` + DockerImage string `name:"docker_image" default:"container-registry-test.zalando.net/acid/spilo-cdp-pr1156-18:4.1-p18"` SidecarImages map[string]string `name:"sidecar_docker_images"` // deprecated in favour of SidecarContainers SidecarContainers []v1.Container `name:"sidecars"` PodServiceAccountName string `name:"pod_service_account_name" default:"postgres-pod"` @@ -248,8 +248,8 @@ type Config struct { EnableTeamIdClusternamePrefix bool `name:"enable_team_id_clustername_prefix" default:"false"` MajorVersionUpgradeMode string `name:"major_version_upgrade_mode" default:"manual"` MajorVersionUpgradeTeamAllowList []string `name:"major_version_upgrade_team_allow_list" default:""` - MinimalMajorVersion string `name:"minimal_major_version" default:"13"` - TargetMajorVersion string `name:"target_major_version" default:"17"` + MinimalMajorVersion string `name:"minimal_major_version" default:"14"` + TargetMajorVersion string `name:"target_major_version" default:"18"` PatroniAPICheckInterval time.Duration `name:"patroni_api_check_interval" default:"1s"` PatroniAPICheckTimeout time.Duration `name:"patroni_api_check_timeout" default:"5s"` EnablePatroniFailsafeMode *bool `name:"enable_patroni_failsafe_mode" default:"false"` diff --git a/ui/manifests/deployment.yaml b/ui/manifests/deployment.yaml index 8c664de22..ad41c38c7 100644 --- a/ui/manifests/deployment.yaml +++ b/ui/manifests/deployment.yaml @@ -73,11 +73,11 @@ spec: "limit_iops": 16000, "limit_throughput": 1000, "postgresql_versions": [ + "18", "17", "16", "15", "14", - "13" ] } # Exemple of settings to make snapshot view working in the ui when using AWS diff --git a/ui/operator_ui/main.py b/ui/operator_ui/main.py index bf28df6eb..c91450d4c 100644 --- a/ui/operator_ui/main.py +++ b/ui/operator_ui/main.py @@ -259,7 +259,7 @@ def index(): 'users_visible': True, 'databases_visible': True, 'resources_visible': RESOURCES_VISIBLE, - 'postgresql_versions': ['13', '14', '15', '16', '17'], + 'postgresql_versions': ['14', '15', '16', '17', '18'], 'dns_format_string': '{0}.{1}', 'pgui_link': '', 'static_network_whitelist': {}, diff --git a/ui/run_local.sh b/ui/run_local.sh index 37f8b1747..59729a92a 100755 --- a/ui/run_local.sh +++ b/ui/run_local.sh @@ -31,11 +31,11 @@ default_operator_ui_config='{ "limit_iops": 16000, "limit_throughput": 1000, "postgresql_versions": [ + "18", "17", "16", "15", "14", - "13" ], "static_network_whitelist": { "localhost": ["172.0.0.1/32"] From 4da5efebedbefade3b7cb1eb4197d47faba33a06 Mon Sep 17 00:00:00 2001 From: inovindasari Date: Fri, 23 Jan 2026 11:58:13 +0100 Subject: [PATCH 02/17] use spilo oss image for e2e test --- e2e/tests/test_e2e.py | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/e2e/tests/test_e2e.py b/e2e/tests/test_e2e.py index 083b4a937..6f01006eb 100644 --- a/e2e/tests/test_e2e.py +++ b/e2e/tests/test_e2e.py @@ -12,9 +12,9 @@ from tests.k8s_api import K8s from kubernetes.client.rest import ApiException -SPILO_CURRENT = "container-registry-test.zalando.net/acid/spilo-cdp-pr1156-18:4.1-p18" -SPILO_LAZY = "container-registry-test.zalando.net/acid/spilo-cdp-pr1156-18:4.1-p19" -SPILO_FULL_IMAGE = "container-registry-test.zalando.net/acid/spilo-cdp-pr1156-18:4.1-p18" +SPILO_CURRENT = "ghcr.io/zalando/spilo-18-dev:6a722f01" +SPILO_LAZY = "ghcr.io/zalando/spilo-17:4.0-p3" +SPILO_FULL_IMAGE = "ghcr.io/zalando/spilo-18-dev:6a722f01" def to_selector(labels): return ",".join(["=".join(lbl) for lbl in labels.items()]) From 895e86dd405597f88f678b47aa52dd29f32363ac Mon Sep 17 00:00:00 2001 From: inovindasari Date: Fri, 23 Jan 2026 13:31:30 +0100 Subject: [PATCH 03/17] use older kind --- e2e/Makefile | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/e2e/Makefile b/e2e/Makefile index 992491f9c..5fa0de471 100644 --- a/e2e/Makefile +++ b/e2e/Makefile @@ -46,7 +46,7 @@ tools: # install pinned version of 'kind' # go install must run outside of a dir with a (module-based) Go project ! # otherwise go install updates project's dependencies and/or behaves differently - cd "/tmp" && GO111MODULE=on go install sigs.k8s.io/kind@v0.31.0 + cd "/tmp" && GO111MODULE=on go install sigs.k8s.io/kind@v0.27.0 e2etest: tools copy clean ./run.sh main From a1855f47eb025027b954c7c3508b0ab3f753f492 Mon Sep 17 00:00:00 2001 From: inovindasari Date: Fri, 23 Jan 2026 13:38:49 +0100 Subject: [PATCH 04/17] change to ghcr spilo image --- e2e/run.sh | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/e2e/run.sh b/e2e/run.sh index 5a80f1966..5675c8c73 100755 --- a/e2e/run.sh +++ b/e2e/run.sh @@ -8,7 +8,7 @@ IFS=$'\n\t' readonly cluster_name="postgres-operator-e2e-tests" readonly kubeconfig_path="/tmp/kind-config-${cluster_name}" -readonly spilo_image="container-registry-test.zalando.net/acid/spilo-cdp-pr1156-18:4.1-p18" +readonly spilo_image="ghcr.io/zalando/spilo-18-dev:6a722f01" readonly e2e_test_runner_image="ghcr.io/zalando/postgres-operator-e2e-tests-runner:latest" export GOPATH=${GOPATH-~/go} From 0fa6f619c5bf84541c1f58c06fa1166d34a1ac5a Mon Sep 17 00:00:00 2001 From: inovindasari Date: Fri, 23 Jan 2026 13:40:53 +0100 Subject: [PATCH 05/17] remove container registry image --- charts/postgres-operator/crds/operatorconfigurations.yaml | 2 +- charts/postgres-operator/values.yaml | 2 +- manifests/complete-postgres-manifest.yaml | 2 +- manifests/configmap.yaml | 2 +- manifests/operatorconfiguration.crd.yaml | 2 +- manifests/postgresql-operator-default-configuration.yaml | 2 +- pkg/controller/operator_config.go | 2 +- pkg/util/config/config.go | 2 +- 8 files changed, 8 insertions(+), 8 deletions(-) diff --git a/charts/postgres-operator/crds/operatorconfigurations.yaml b/charts/postgres-operator/crds/operatorconfigurations.yaml index 0d0be3d25..437366b33 100644 --- a/charts/postgres-operator/crds/operatorconfigurations.yaml +++ b/charts/postgres-operator/crds/operatorconfigurations.yaml @@ -68,7 +68,7 @@ spec: type: string docker_image: type: string - default: "container-registry-test.zalando.net/acid/spilo-cdp-pr1156-18:4.1-p18" + default: "ghcr.io/zalando/spilo-18-dev:6a722f01" enable_crd_registration: type: boolean default: true diff --git a/charts/postgres-operator/values.yaml b/charts/postgres-operator/values.yaml index 2b061e1b5..55da6681e 100644 --- a/charts/postgres-operator/values.yaml +++ b/charts/postgres-operator/values.yaml @@ -36,7 +36,7 @@ configGeneral: # etcd connection string for Patroni. Empty uses K8s-native DCS. etcd_host: "" # Spilo docker image - docker_image: container-registry-test.zalando.net/acid/spilo-cdp-pr1156-18:4.1-p18 + docker_image: ghcr.io/zalando/spilo-18-dev:6a722f01 # key name for annotation to ignore globally configured instance limits # ignore_instance_limits_annotation_key: "" diff --git a/manifests/complete-postgres-manifest.yaml b/manifests/complete-postgres-manifest.yaml index 8cfbda28f..715bab94b 100644 --- a/manifests/complete-postgres-manifest.yaml +++ b/manifests/complete-postgres-manifest.yaml @@ -10,7 +10,7 @@ metadata: # "delete-date": "2020-08-31" # can only be deleted on that day if "delete-date "key is configured # "delete-clustername": "acid-test-cluster" # can only be deleted when name matches if "delete-clustername" key is configured spec: - dockerImage: container-registry-test.zalando.net/acid/spilo-cdp-pr1156-18:4.1-p18 + dockerImage: ghcr.io/zalando/spilo-18-dev:6a722f01 teamId: "acid" numberOfInstances: 2 users: # Application/Robot users diff --git a/manifests/configmap.yaml b/manifests/configmap.yaml index db98ac302..15b4f1dff 100644 --- a/manifests/configmap.yaml +++ b/manifests/configmap.yaml @@ -34,7 +34,7 @@ data: default_memory_request: 100Mi # delete_annotation_date_key: delete-date # delete_annotation_name_key: delete-clustername - docker_image: container-registry-test.zalando.net/acid/spilo-cdp-pr1156-18:4.1-p18 + docker_image: ghcr.io/zalando/spilo-18-dev:6a722f01 # downscaler_annotations: "deployment-time,downscaler/*" enable_admin_role_for_users: "true" enable_crd_registration: "true" diff --git a/manifests/operatorconfiguration.crd.yaml b/manifests/operatorconfiguration.crd.yaml index 8249bf114..c5ada7462 100644 --- a/manifests/operatorconfiguration.crd.yaml +++ b/manifests/operatorconfiguration.crd.yaml @@ -66,7 +66,7 @@ spec: type: string docker_image: type: string - default: "container-registry-test.zalando.net/acid/spilo-cdp-pr1156-18:4.1-p18" + default: "ghcr.io/zalando/spilo-18-dev:6a722f01" enable_crd_registration: type: boolean default: true diff --git a/manifests/postgresql-operator-default-configuration.yaml b/manifests/postgresql-operator-default-configuration.yaml index 6037acc73..293c554cc 100644 --- a/manifests/postgresql-operator-default-configuration.yaml +++ b/manifests/postgresql-operator-default-configuration.yaml @@ -3,7 +3,7 @@ kind: OperatorConfiguration metadata: name: postgresql-operator-default-configuration configuration: - docker_image: container-registry-test.zalando.net/acid/spilo-cdp-pr1156-18:4.1-p18 + docker_image: ghcr.io/zalando/spilo-18-dev:6a722f01 # enable_crd_registration: true # crd_categories: # - all diff --git a/pkg/controller/operator_config.go b/pkg/controller/operator_config.go index 6769cc16d..7d2e7ebc2 100644 --- a/pkg/controller/operator_config.go +++ b/pkg/controller/operator_config.go @@ -39,7 +39,7 @@ func (c *Controller) importConfigurationFromCRD(fromCRD *acidv1.OperatorConfigur result.EnableTeamIdClusternamePrefix = fromCRD.EnableTeamIdClusternamePrefix result.EtcdHost = fromCRD.EtcdHost result.KubernetesUseConfigMaps = fromCRD.KubernetesUseConfigMaps - result.DockerImage = util.Coalesce(fromCRD.DockerImage, "container-registry-test.zalando.net/acid/spilo-cdp-pr1156-18:4.1-p18") + result.DockerImage = util.Coalesce(fromCRD.DockerImage, "ghcr.io/zalando/spilo-18-dev:6a722f01") result.Workers = util.CoalesceUInt32(fromCRD.Workers, 8) result.MinInstances = fromCRD.MinInstances result.MaxInstances = fromCRD.MaxInstances diff --git a/pkg/util/config/config.go b/pkg/util/config/config.go index 855898e81..b8b62f56b 100644 --- a/pkg/util/config/config.go +++ b/pkg/util/config/config.go @@ -177,7 +177,7 @@ type Config struct { WatchedNamespace string `name:"watched_namespace"` // special values: "*" means 'watch all namespaces', the empty string "" means 'watch a namespace where operator is deployed to' KubernetesUseConfigMaps bool `name:"kubernetes_use_configmaps" default:"false"` EtcdHost string `name:"etcd_host" default:""` // special values: the empty string "" means Patroni will use K8s as a DCS - DockerImage string `name:"docker_image" default:"container-registry-test.zalando.net/acid/spilo-cdp-pr1156-18:4.1-p18"` + DockerImage string `name:"docker_image" default:"ghcr.io/zalando/spilo-18-dev:6a722f01"` SidecarImages map[string]string `name:"sidecar_docker_images"` // deprecated in favour of SidecarContainers SidecarContainers []v1.Container `name:"sidecars"` PodServiceAccountName string `name:"pod_service_account_name" default:"postgres-pod"` From 608d45a14c5444dfc0c8a75019cc18066a7480d4 Mon Sep 17 00:00:00 2001 From: idanovinda Date: Mon, 26 Jan 2026 15:16:04 +0100 Subject: [PATCH 06/17] update run.sh for e2e test --- e2e/run.sh | 11 +++++++---- 1 file changed, 7 insertions(+), 4 deletions(-) diff --git a/e2e/run.sh b/e2e/run.sh index 5675c8c73..7e84fb2d7 100755 --- a/e2e/run.sh +++ b/e2e/run.sh @@ -7,7 +7,7 @@ set -o pipefail IFS=$'\n\t' readonly cluster_name="postgres-operator-e2e-tests" -readonly kubeconfig_path="/tmp/kind-config-${cluster_name}" +readonly kubeconfig_path="${HOME}/kind-config-${cluster_name}" readonly spilo_image="ghcr.io/zalando/spilo-18-dev:6a722f01" readonly e2e_test_runner_image="ghcr.io/zalando/postgres-operator-e2e-tests-runner:latest" @@ -19,11 +19,14 @@ echo "Kubeconfig path: ${kubeconfig_path}" function pull_images(){ operator_tag=$(git describe --tags --always --dirty) - if [[ -z $(docker images -q ghcr.io/zalando/postgres-operator:${operator_tag}) ]] + target_image=docker.io/library/postgres-operator:${operator_tag} + if [[ -z $(docker images -q "${target_image}") ]] then docker pull ghcr.io/zalando/postgres-operator:latest + docker tag ghcr.io/zalando/postgres-operator:latest "${target_image}" fi - operator_image=$(docker images --filter=reference="ghcr.io/zalando/postgres-operator" --format "{{.Repository}}:{{.Tag}}" | head -1) + operator_image=${target_image} + echo "Using operator image: ${operator_image}" } function start_kind(){ @@ -52,7 +55,7 @@ function set_kind_api_server_ip(){ # but update the IP address of the API server to the one from the Docker 'bridge' network readonly local kind_api_server_port=6443 # well-known in the 'kind' codebase readonly local kind_api_server=$(docker inspect --format "{{ .NetworkSettings.Networks.kind.IPAddress }}:${kind_api_server_port}" "${cluster_name}"-control-plane) - sed -i "s/server.*$/server: https:\/\/$kind_api_server/g" "${kubeconfig_path}" + sed "s/server.*$/server: https:\/\/$kind_api_server/g" "${kubeconfig_path}" > "${kubeconfig_path}".tmp && mv "${kubeconfig_path}".tmp "${kubeconfig_path}" } function generate_certificate(){ From dde8a5536b7d2f726960873923a93219c70526e0 Mon Sep 17 00:00:00 2001 From: Polina Bungina Date: Wed, 28 Jan 2026 11:33:29 +0100 Subject: [PATCH 07/17] debug --- e2e/run.sh | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/e2e/run.sh b/e2e/run.sh index 7e84fb2d7..2cd2b450b 100755 --- a/e2e/run.sh +++ b/e2e/run.sh @@ -20,8 +20,9 @@ echo "Kubeconfig path: ${kubeconfig_path}" function pull_images(){ operator_tag=$(git describe --tags --always --dirty) target_image=docker.io/library/postgres-operator:${operator_tag} - if [[ -z $(docker images -q "${target_image}") ]] + if [[ -z $(docker images -q "postgres-operator:${operator_tag}") ]] then + echo "Local image not found. Pulling operator image from ghcr.io and tagging it as ${target_image}" docker pull ghcr.io/zalando/postgres-operator:latest docker tag ghcr.io/zalando/postgres-operator:latest "${target_image}" fi From 95cf0e496754212112f59929fbd21a1f9341287f Mon Sep 17 00:00:00 2001 From: idanovinda Date: Thu, 29 Jan 2026 16:59:25 +0100 Subject: [PATCH 08/17] update controller gen version --- manifests/postgresql.crd.yaml | 11 +++++------ manifests/postgresteam.crd.yaml | 2 +- 2 files changed, 6 insertions(+), 7 deletions(-) diff --git a/manifests/postgresql.crd.yaml b/manifests/postgresql.crd.yaml index d50e0393b..28aa5b96a 100644 --- a/manifests/postgresql.crd.yaml +++ b/manifests/postgresql.crd.yaml @@ -3,7 +3,7 @@ apiVersion: apiextensions.k8s.io/v1 kind: CustomResourceDefinition metadata: annotations: - controller-gen.kubebuilder.io/version: v0.17.3 + controller-gen.kubebuilder.io/version: v0.20.0 name: postgresqls.acid.zalan.do spec: group: acid.zalan.do @@ -3935,11 +3935,10 @@ spec: required: - s3_wal_path - gs_wal_path - description: StandbyDescription contains remote primary config and/or - s3/gs wal path. standby_host can be specified alone or together with - either s3_wal_path OR gs_wal_path (mutually exclusive). At least - one field must be specified. s3_wal_path and gs_wal_path are mutually - exclusive. + description: |- + StandbyDescription contains remote primary config and/or s3/gs wal path. + standby_host can be specified alone or together with either s3_wal_path OR gs_wal_path (mutually exclusive). + At least one field must be specified. s3_wal_path and gs_wal_path are mutually exclusive. properties: gs_wal_path: type: string diff --git a/manifests/postgresteam.crd.yaml b/manifests/postgresteam.crd.yaml index 2245c6253..5a7c9c6d6 100644 --- a/manifests/postgresteam.crd.yaml +++ b/manifests/postgresteam.crd.yaml @@ -3,7 +3,7 @@ apiVersion: apiextensions.k8s.io/v1 kind: CustomResourceDefinition metadata: annotations: - controller-gen.kubebuilder.io/version: v0.17.3 + controller-gen.kubebuilder.io/version: v0.20.0 name: postgresteams.acid.zalan.do spec: group: acid.zalan.do From 04159a302c91a9c2b3bc39c5eb283d2f4903d3f3 Mon Sep 17 00:00:00 2001 From: idanovinda Date: Fri, 30 Jan 2026 11:42:09 +0100 Subject: [PATCH 09/17] add more time to setUpClass --- e2e/tests/test_e2e.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/e2e/tests/test_e2e.py b/e2e/tests/test_e2e.py index 6f01006eb..15358087b 100644 --- a/e2e/tests/test_e2e.py +++ b/e2e/tests/test_e2e.py @@ -72,7 +72,7 @@ def eventuallyTrue(self, f, m, retries=60, interval=2): time.sleep(interval) @classmethod - @timeout_decorator.timeout(TEST_TIMEOUT_SEC) + @timeout_decorator.timeout(1800) def setUpClass(cls): ''' Deploy operator to a "kind" cluster created by run.sh using examples from /manifests. From 8cb2741858d727225d46ebc76b4d74991d23b2cd Mon Sep 17 00:00:00 2001 From: idanovinda Date: Fri, 30 Jan 2026 13:19:37 +0100 Subject: [PATCH 10/17] keep old generator version --- manifests/postgresql.crd.yaml | 2 +- manifests/postgresteam.crd.yaml | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/manifests/postgresql.crd.yaml b/manifests/postgresql.crd.yaml index 28aa5b96a..39811824e 100644 --- a/manifests/postgresql.crd.yaml +++ b/manifests/postgresql.crd.yaml @@ -3,7 +3,7 @@ apiVersion: apiextensions.k8s.io/v1 kind: CustomResourceDefinition metadata: annotations: - controller-gen.kubebuilder.io/version: v0.20.0 + controller-gen.kubebuilder.io/version: v0.17.3 name: postgresqls.acid.zalan.do spec: group: acid.zalan.do diff --git a/manifests/postgresteam.crd.yaml b/manifests/postgresteam.crd.yaml index 5a7c9c6d6..2245c6253 100644 --- a/manifests/postgresteam.crd.yaml +++ b/manifests/postgresteam.crd.yaml @@ -3,7 +3,7 @@ apiVersion: apiextensions.k8s.io/v1 kind: CustomResourceDefinition metadata: annotations: - controller-gen.kubebuilder.io/version: v0.20.0 + controller-gen.kubebuilder.io/version: v0.17.3 name: postgresteams.acid.zalan.do spec: group: acid.zalan.do From 6de02bfd40980ed0ef40b7058af8d18e9de21811 Mon Sep 17 00:00:00 2001 From: inovindasari Date: Wed, 4 Feb 2026 16:31:45 +0100 Subject: [PATCH 11/17] debug master pod --- e2e/tests/test_e2e.py | 5 ++++- 1 file changed, 4 insertions(+), 1 deletion(-) diff --git a/e2e/tests/test_e2e.py b/e2e/tests/test_e2e.py index 15358087b..bca81c277 100644 --- a/e2e/tests/test_e2e.py +++ b/e2e/tests/test_e2e.py @@ -72,7 +72,7 @@ def eventuallyTrue(self, f, m, retries=60, interval=2): time.sleep(interval) @classmethod - @timeout_decorator.timeout(1800) + @timeout_decorator.timeout(TEST_TIMEOUT_SEC) def setUpClass(cls): ''' Deploy operator to a "kind" cluster created by run.sh using examples from /manifests. @@ -158,6 +158,9 @@ def setUpClass(cls): k8s.wait_for_pod_start('spilo-role=replica,' + cluster_label) except timeout_decorator.TimeoutError: print('Operator log: {}'.format(k8s.get_operator_log())) + master_pod = k8s.api.core_v1.list_namespaced_pod('default', label_selector='spilo-role=master,' + cluster_label).items + if master_pod: + print('Master pod log: {}'.format(k8s.api.core_v1.read_namespaced_pod_log(master_pod[0].metadata.name, 'default'))) raise @timeout_decorator.timeout(TEST_TIMEOUT_SEC) From 32c2204d1963f2ff52496c0eeabdafb59c707be3 Mon Sep 17 00:00:00 2001 From: inovindasari Date: Wed, 4 Feb 2026 16:54:19 +0100 Subject: [PATCH 12/17] debug master pod --- e2e/tests/k8s_api.py | 13 +++++++++++++ e2e/tests/test_e2e.py | 6 ++---- 2 files changed, 15 insertions(+), 4 deletions(-) diff --git a/e2e/tests/k8s_api.py b/e2e/tests/k8s_api.py index 1f42ad4bc..85aa1975f 100644 --- a/e2e/tests/k8s_api.py +++ b/e2e/tests/k8s_api.py @@ -92,6 +92,19 @@ def get_operator_log(self): namespace='default' ) + def get_pod_log(self, pod_labels, namespace='default'): + pods = self.api.core_v1.list_namespaced_pod( + namespace, label_selector=pod_labels + ).items + + if pods: + pod_name = pods[0].metadata.name + return self.api.core_v1.read_namespaced_pod_log( + name=pod_name, + namespace=namespace + ) + return None + def pg_get_status(self, name="acid-minimal-cluster", namespace="default"): pg = self.api.custom_objects_api.get_namespaced_custom_object( "acid.zalan.do", "v1", namespace, "postgresqls", name) diff --git a/e2e/tests/test_e2e.py b/e2e/tests/test_e2e.py index bca81c277..3be141d40 100644 --- a/e2e/tests/test_e2e.py +++ b/e2e/tests/test_e2e.py @@ -72,7 +72,7 @@ def eventuallyTrue(self, f, m, retries=60, interval=2): time.sleep(interval) @classmethod - @timeout_decorator.timeout(TEST_TIMEOUT_SEC) + @timeout_decorator.timeout(1200) def setUpClass(cls): ''' Deploy operator to a "kind" cluster created by run.sh using examples from /manifests. @@ -158,9 +158,7 @@ def setUpClass(cls): k8s.wait_for_pod_start('spilo-role=replica,' + cluster_label) except timeout_decorator.TimeoutError: print('Operator log: {}'.format(k8s.get_operator_log())) - master_pod = k8s.api.core_v1.list_namespaced_pod('default', label_selector='spilo-role=master,' + cluster_label).items - if master_pod: - print('Master pod log: {}'.format(k8s.api.core_v1.read_namespaced_pod_log(master_pod[0].metadata.name, 'default'))) + print('Master pod log: {}'.format(k8s.get_pod_log('spilo-role=master,' + cluster_label))) raise @timeout_decorator.timeout(TEST_TIMEOUT_SEC) From decc31e6c504156b2a6df48935ac11d0ab8d14b1 Mon Sep 17 00:00:00 2001 From: inovindasari Date: Wed, 4 Feb 2026 17:29:20 +0100 Subject: [PATCH 13/17] add more debugging resources --- e2e/tests/test_e2e.py | 5 +++++ 1 file changed, 5 insertions(+) diff --git a/e2e/tests/test_e2e.py b/e2e/tests/test_e2e.py index 3be141d40..35973537c 100644 --- a/e2e/tests/test_e2e.py +++ b/e2e/tests/test_e2e.py @@ -136,6 +136,7 @@ def setUpClass(cls): print("stdout: {}, stderr: {}".format(result.stdout, result.stderr)) k8s.wait_for_operator_pod_start() + print("===== Operator pod is running") # reset taints and tolerations k8s.api.core_v1.patch_node("postgres-operator-e2e-tests-worker", {"spec": {"taints": []}}) @@ -146,6 +147,7 @@ def setUpClass(cls): # and the Docker image is in fact changed (dirty one) k8s.update_config({}, step="TestSuite Startup") + print("===== Operator configmap updated") actual_operator_image = k8s.api.core_v1.list_namespaced_pod( 'default', label_selector='name=postgres-operator').items[0].spec.containers[0].image @@ -158,6 +160,9 @@ def setUpClass(cls): k8s.wait_for_pod_start('spilo-role=replica,' + cluster_label) except timeout_decorator.TimeoutError: print('Operator log: {}'.format(k8s.get_operator_log())) + # list all stateful set and all pods for debugging + print('StatefulSet: {}'.format(k8s.api.apps_v1.list_namespaced_stateful_set(namespace='default', label_selector=cluster_label))) + print('Pods: {}'.format(k8s.api.core_v1.list_namespaced_pod(namespace='default', label_selector=cluster_label))) print('Master pod log: {}'.format(k8s.get_pod_log('spilo-role=master,' + cluster_label))) raise From 5988a75e6a55b31fed35199a229b386d7b26697a Mon Sep 17 00:00:00 2001 From: inovindasari Date: Wed, 4 Feb 2026 21:54:11 +0100 Subject: [PATCH 14/17] debug with meaningful values --- e2e/tests/k8s_api.py | 13 ------------- e2e/tests/test_e2e.py | 39 ++++++++++++++++++++++++++++++++++++--- 2 files changed, 36 insertions(+), 16 deletions(-) diff --git a/e2e/tests/k8s_api.py b/e2e/tests/k8s_api.py index 85aa1975f..1f42ad4bc 100644 --- a/e2e/tests/k8s_api.py +++ b/e2e/tests/k8s_api.py @@ -92,19 +92,6 @@ def get_operator_log(self): namespace='default' ) - def get_pod_log(self, pod_labels, namespace='default'): - pods = self.api.core_v1.list_namespaced_pod( - namespace, label_selector=pod_labels - ).items - - if pods: - pod_name = pods[0].metadata.name - return self.api.core_v1.read_namespaced_pod_log( - name=pod_name, - namespace=namespace - ) - return None - def pg_get_status(self, name="acid-minimal-cluster", namespace="default"): pg = self.api.custom_objects_api.get_namespaced_custom_object( "acid.zalan.do", "v1", namespace, "postgresqls", name) diff --git a/e2e/tests/test_e2e.py b/e2e/tests/test_e2e.py index 35973537c..5ff6f9b0f 100644 --- a/e2e/tests/test_e2e.py +++ b/e2e/tests/test_e2e.py @@ -161,9 +161,42 @@ def setUpClass(cls): except timeout_decorator.TimeoutError: print('Operator log: {}'.format(k8s.get_operator_log())) # list all stateful set and all pods for debugging - print('StatefulSet: {}'.format(k8s.api.apps_v1.list_namespaced_stateful_set(namespace='default', label_selector=cluster_label))) - print('Pods: {}'.format(k8s.api.core_v1.list_namespaced_pod(namespace='default', label_selector=cluster_label))) - print('Master pod log: {}'.format(k8s.get_pod_log('spilo-role=master,' + cluster_label))) + sts_list = k8s.api.apps_v1.list_namespaced_stateful_set(namespace='default', label_selector=cluster_label) + for sts in sts_list.items: + print(f"\n=== Debugging StatefulSet: {sts.metadata.name} ===") + + # 2. Print Status Summary + # This tells you if pods are actually being created + print(f"Status: {sts.status.replicas} total, {sts.status.ready_replicas} ready, {sts.status.updated_replicas} updated") + + # 3. Print Events related to this StatefulSet + # We use the CoreV1Api to find events involving this specific object UID + print("--- Recent Events ---") + field_selector = f"involvedObject.uid={sts.metadata.uid}" + events = k8s.api.core_v1.list_namespaced_event( + namespace='default', + field_selector=field_selector + ) + + if not events.items: + print("No events found for the StatefulSet itself.") + else: + for e in events.items: + # Formatting timestamp, type (Normal/Warning), reason, and the message + print(f"[{e.last_timestamp}] {e.type:7} {e.reason:20} {e.message}") + + # 4. Check Pods (Crucial because STS errors often bubble up from Pods) + print("--- Pod Health ---") + pods = k8s.api.core_v1.list_namespaced_pod( + namespace='default', + label_selector=cluster_label + ) + for pod in pods.items: + print(f"Pod: {pod.metadata.name:30} Phase: {pod.status.phase}") + if pod.status.container_statuses: + for container in pod.status.container_statuses: + if not container.ready: + print(f" -> Container '{container.name}' is NOT READY. State: {container.state}") raise @timeout_decorator.timeout(TEST_TIMEOUT_SEC) From a61e9642dd76b1da3493f8f2e2665b8532ef9f78 Mon Sep 17 00:00:00 2001 From: inovindasari Date: Wed, 4 Feb 2026 22:31:20 +0100 Subject: [PATCH 15/17] debugging pod and add more time --- e2e/tests/test_e2e.py | 35 ++++++++++++++++++++++++++++++++--- 1 file changed, 32 insertions(+), 3 deletions(-) diff --git a/e2e/tests/test_e2e.py b/e2e/tests/test_e2e.py index 5ff6f9b0f..020e5feef 100644 --- a/e2e/tests/test_e2e.py +++ b/e2e/tests/test_e2e.py @@ -72,7 +72,7 @@ def eventuallyTrue(self, f, m, retries=60, interval=2): time.sleep(interval) @classmethod - @timeout_decorator.timeout(1200) + @timeout_decorator.timeout(1500) def setUpClass(cls): ''' Deploy operator to a "kind" cluster created by run.sh using examples from /manifests. @@ -192,11 +192,40 @@ def setUpClass(cls): label_selector=cluster_label ) for pod in pods.items: - print(f"Pod: {pod.metadata.name:30} Phase: {pod.status.phase}") + print(f"\nPod: {pod.metadata.name:30} Phase: {pod.status.phase}") + + # Check container status for issues if pod.status.container_statuses: for container in pod.status.container_statuses: if not container.ready: - print(f" -> Container '{container.name}' is NOT READY. State: {container.state}") + print(f" -> Container '{container.name}' NOT READY. State: {container.state}") + + # 4. Fetch the logs for the failing container + print(f" -> Fetching logs for '{container.name}'...") + try: + # We try to get the 'previous' logs because the current container is likely empty/restarting + pod_log = k8s.api.core_v1.read_namespaced_pod_log( + name=pod.metadata.name, + namespace='default', + container=container.name, + previous=True, # Get logs from the crash + tail_lines=20 # Only show the last 20 lines to keep output clean + ) + print("--- Start of Previous Container Logs ---") + print(pod_log) + print("--- End of Logs ---") + except Exception as log_err: + # If there is no previous container yet, fallback to current logs + try: + pod_log = k8s.api.core_v1.read_namespaced_pod_log( + name=pod.metadata.name, + namespace='default', + container=container.name, + tail_lines=20 + ) + print(f"(Current Logs): {pod_log}") + except: + print(f" !! Could not retrieve logs: {log_err}") raise @timeout_decorator.timeout(TEST_TIMEOUT_SEC) From 714e522a7d8d4ec51a98261f5eaadc5c7cab7a5e Mon Sep 17 00:00:00 2001 From: idanovinda Date: Thu, 5 Feb 2026 14:17:39 +0100 Subject: [PATCH 16/17] use empty string to wal s3 --- manifests/configmap.yaml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/manifests/configmap.yaml b/manifests/configmap.yaml index 15b4f1dff..522c36cae 100644 --- a/manifests/configmap.yaml +++ b/manifests/configmap.yaml @@ -170,6 +170,6 @@ data: # toleration: "key:db-only,operator:Exists,effect:NoSchedule" # wal_az_storage_account: "" # wal_gs_bucket: "" - # wal_s3_bucket: "" + wal_s3_bucket: "" watched_namespace: "*" # listen to all namespaces workers: "8" From e88a3e95ef632fd98a972ec8f64cfaf2f6391eb9 Mon Sep 17 00:00:00 2001 From: idanovinda Date: Thu, 5 Feb 2026 17:27:53 +0100 Subject: [PATCH 17/17] specify env var SPILO_PROVIDER --- manifests/configmap.yaml | 2 +- manifests/minimal-postgres-manifest.yaml | 3 +++ 2 files changed, 4 insertions(+), 1 deletion(-) diff --git a/manifests/configmap.yaml b/manifests/configmap.yaml index 522c36cae..15b4f1dff 100644 --- a/manifests/configmap.yaml +++ b/manifests/configmap.yaml @@ -170,6 +170,6 @@ data: # toleration: "key:db-only,operator:Exists,effect:NoSchedule" # wal_az_storage_account: "" # wal_gs_bucket: "" - wal_s3_bucket: "" + # wal_s3_bucket: "" watched_namespace: "*" # listen to all namespaces workers: "8" diff --git a/manifests/minimal-postgres-manifest.yaml b/manifests/minimal-postgres-manifest.yaml index 086ce553a..69406e526 100644 --- a/manifests/minimal-postgres-manifest.yaml +++ b/manifests/minimal-postgres-manifest.yaml @@ -4,6 +4,9 @@ metadata: name: acid-minimal-cluster spec: teamId: "acid" + env: + - name: "SPILO_PROVIDER" + value: "local" volume: size: 1Gi numberOfInstances: 2