configuration.sidecars was annotated with kubebuilder:validation:Type=object
while SidecarContainers is a []v1.Container, so the generated schema rejected
every list value and global sidecars could not be configured at all.
Drop the hand-written Schemaless/Type=object markers and let controller-gen
derive the schema from the Go type, the same way spec.initContainers is
already handled in the Postgresql CRD. The field now renders as type: array
with a full Container schema for its items.
Fixes#3159
Co-authored-by: Claude Opus 5 (1M context) <noreply@anthropic.com>
Upgrading to v2.0.0 fails at the CRD apply step. The apiserver rejects the
OperatorConfiguration CRD:
CustomResourceDefinition "operatorconfigurations.acid.zalan.do" is invalid:
...oauth_token_secret_name.default: Invalid value: "string": in body must
be of type object
Root cause: these CRDs are generated by controller-gen from the Go types.
spec.NamespacedName is a struct {Namespace, Name}, so controller-gen emits an
object schema for every NamespacedName field. But NamespacedName has custom
MarshalJSON/UnmarshalJSON that (de)serialize it as a plain JSON string
("namespace/name"). The generated object schema therefore never matched how
the operator actually reads and writes these fields (it did in 1.15.x, where
they were type: string).
For oauth_token_secret_name this is a hard failure: it also carries
`// +kubebuilder:default=postgres-operator`, and a scalar string default on an
object-typed property is rejected by the apiserver, blocking the whole
1.15.x -> 2.0.0 upgrade before the operator Deployment is touched.
Fix at the source by annotating the NamespacedName type with
`// +kubebuilder:validation:Type=string` and regenerating the CRDs. This makes
controller-gen emit `type: string` for all NamespacedName fields
(oauth_token_secret_name, infrastructure_roles_secret_name,
pod_environment_configmap, and the nested infrastructure role secretname),
matching their runtime serialization and restoring 1.15.x behaviour. A
field-level Type override cannot be used here: it conflicts with the
struct-derived schema ("object vs string in allOf") and fails generation.
Regenerated manifests/operatorconfiguration.crd.yaml and its two synced
copies (pkg/apis/... embed source and charts/.../crds). Verified with a
server-side dry-run apply: the unpatched CRD is rejected, the regenerated CRD
is accepted.
Fixes#3143
* Use maxUnavailable for the critical-op PDB to stop idle alert noise
The critical-op PDB is created with minAvailable equal to
numberOfInstances while its selector (critical-operation=true) matches
no pods during normal operation. This leaves status.desiredHealthy at N
and currentHealthy at 0 permanently, so monitoring stacks fire alerts
like kube-prometheus-stack's KubePdbNotEnoughHealthyPods for every idle
cluster (#3020).
maxUnavailable: 0 provides the same protection while a critical
operation is running - no voluntary evictions of labeled pods - but
keeps the budget satisfied (desiredHealthy 0) when nothing matches.
When PDBs are disabled or there are no instances, the budget relaxes to
maxUnavailable 100% instead of minAvailable 0.
Fixes#3020
Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
* Update PDB docs for critical-op maxUnavailable semantics
Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
* Clarify why the two PDBs use different budget fields
Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
---------
Co-authored-by: Claude Fable 5 <noreply@anthropic.com>
Co-authored-by: Felix Kunde <felix-kunde@gmx.de>
* Use minAvalable=SynchronousNodeCount + 1 in primary PDB when master selector is disabled
---------
Co-authored-by: Felix Kunde <felix-kunde@gmx.de>
Co-authored-by: Ida Novindasari <idanovinda@gmail.com>
* fix data to POSIX and sed working on macos
* add ServiceAccountGetter to the newFakeK8sAnnotationsClient for unit tests
* try to update the service account
* use irsa_role_arn since we need the full arn, and remove enable_irsa
* move sa sync code to existing sync.go file to be all together
* change all Irsa to IRSA to follow go idiomatic that capitalize initialisms or acronyms
* using Update instead of Patch for the service account syn
* document the new option and add the key in the values/configs
* add the new option to the administrator docs
* trying to increase the timeout for the flaky test after sync
---------
Co-authored-by: Felix Kunde <felix-kunde@gmx.de>
* update golang and dependencies
* fix incorrect log formatting
* clean mod chache and introduce GOARCH in Dockerfile (choose dynamically)
* remove GO111MODULE mentions
* bump github actions from v2 to v3
* bump docker runners to v7
* use extra event store for backwards compatibility with existing codebase
* updated generated opconfig api
* feat(logical-backup): add configurable job history limits and TTL
Adds three new configuration options for logical backup cronjobs:
- logical_backup_successful_jobs_history_limit (default: 3)
- logical_backup_failed_jobs_history_limit (default: 3)
- logical_backup_ttl_seconds_after_finished (default: 86400)
These options control how many completed/failed backup jobs are
retained by Kubernetes and when finished jobs are automatically
deleted. This prevents accumulation of old backup jobs and pods
in namespaces with many PostgreSQL clusters.
Also updates the CronJob comparison logic to detect changes in
these new fields and trigger reconciliation when needed.
Closeszalando/postgres-operator#1092
* add added the 3 new fieldson crd
* updated gen api
---------
Co-authored-by: Jairo Llopis <jairo@moduon.team>
Co-authored-by: Felix Kunde <felix-kunde@gmx.de>
feat: implement service type NodePort
fix: handle LoadBalancer to NodePort service type transition
move NodePort check before LoadBalancer and remove redundant nodePor
add LB-specific DNS annotations again
* Add cluster_labels and annotations to logical backup CronJob and Jobs
When using the logical backup feature, the CronJob and its created Jobs
were missing the cluster_labels and annotations that are applied to
other cluster resources. This made it difficult to filter or identify
backup jobs using the same labels as other cluster components.
Changes:
- Added ObjectMeta with labels and annotations to JobTemplateSpec
- Updated CronJob ObjectMeta to use the merged labels (including
'application: spilo-logical-backup')
- Updated tests to expect the new labels
* fix: set password encryption default to scram-sha-256
According to the Postgres official documentation, md5 passwords is
deprecated in favor of scram-sha-256 encryption.
The change in this PR updates the default encryption to the new postgres
default.
Documentation link: https://www.postgresql.org/docs/18/auth-password.html
>Warning: Support for MD5-encrypted passwords is deprecated and will be removed in a future release of PostgreSQL.
Signed-off-by: Kadaffy Talavera <kadtalavera@gmail.com>
* fix: update user documentation about password encryption
Signed-off-by: Kadaffy Talavera <kadtalavera@gmail.com>
* Apply suggestion from @FxKu
---------
Signed-off-by: Kadaffy Talavera <kadtalavera@gmail.com>
Co-authored-by: Felix Kunde <felix-kunde@gmx.de>
* Fix bool config defaults when using OperatorConfiguration CRD
When using OperatorConfiguration CRD, boolean fields with default value
of `true` (like `enable_database_access` and `debug_logging`) were
incorrectly defaulting to `false` when not explicitly specified.
This happened because Go initializes bool fields to `false`, and there
was no coalesce logic to apply the intended defaults.
The fix changes the CRD type fields from `bool` to `*bool` (pointer),
allowing us to distinguish between "not specified" (nil) and "explicitly
set to false". Then we use the existing `CoalesceBool` utility function
to apply the correct defaults.
Fixes#2575
* update generated code
Updated DeepCopyInto method for OperatorDebugConfiguration to handle pointers for DebugLogging and EnableDBAccess.
---------
Co-authored-by: Felix Kunde <felix-kunde@gmx.de>
* refactor(controller): use kubernetes informers provided by client-go
* forgot assigning struct field member
---------
Co-authored-by: Felix Kunde <felix-kunde@gmx.de>
This addresses issue #416 by adding comprehensive unit tests for the
config utility functions:
- TestValidate: Tests validation logic for MinInstances/MaxInstances,
Workers count, ConnectionPooler instances, and user conflicts
- TestNewFromMap: Tests config creation from map with defaults,
custom values, duration/boolean/map/slice parsing, and panic behavior
- TestMain: Sets OPERATOR_NAMESPACE env var for testing outside K8s
The tests cover both valid configurations and error cases.
Co-authored-by: Felix Kunde <felix-kunde@gmx.de>
When a Postgres cluster has a finalizer, deleting it sets a DeletionTimestamp
but doesn't remove the object until the finalizer is cleared. The operator
was not properly handling these DeletionTimestamp changes:
1. postgresqlUpdate() was filtering out events where only DeletionTimestamp
changed (it only checked Spec and Annotations), causing the delete to
never be processed.
2. EventUpdate case in processEvent() didn't check for DeletionTimestamp,
so even if the event reached the processor, it would run Update() instead
of Delete().
3. removeFinalizer() used a cached object with stale resourceVersion,
causing "object has been modified" errors.
Fixes:
- Add explicit DeletionTimestamp check in postgresqlUpdate() to queue the event
- Add DeletionTimestamp check in EventUpdate to call Delete() when set
- Fetch latest object from API before removing finalizer to avoid conflicts
Co-authored-by: Felix Kunde <felix-kunde@gmx.de>
* Add topologySpreadConstraints configuration to pod spec.
* Run update-codegen.sh to add deepcopy for new field to the api.
* Reuse configured TopologySpreadConstraints for logical backup.
* Remove x-kubernetes-preserve-unknown-fields and XPreserveUnknownFields.
* Add topologySpreadConstraint example in the complete manifest.
* Add support for helm chart.
* Add documentation for topologySpreadConstraint.
* Update e2e test to patch topologySpreadConstraints into the postgresqls manifest.
* For e2e test, updated the PVC retention policy to remove redundant PVCs.
* Fix e2e test, expected PVC count in end-to-end test after config changes.
* build multi-arch pooler image
* add pooler build step in delivery.yaml and bump pooler version
* pull from docker hub not zalando registry
* add pooler step to ghcr workflow
* pass infra roles to auth file via pooler entrypoint
* introduce extra pooler secret for mounting auth_file
* use pbgouncer as image name and push to ghcr on next merge
* build with latest pgbouncer
* integrate new image in e2e process and update pooler image default
* update pooler build dependencies
* build pooler image for e2e test
* more Makefile and e2e run script tweaking
---------
Co-authored-by: Ida Novindasari <idanovinda@gmail.com>
* add fix to recreate non running pods in syncStatefulsets
* remove TestSyncStatefulSetNonRunningPodsDoNotBlockRecreatio
* revert pod_test
* pod without status
---------
Co-authored-by: Felix Kunde <felix-kunde@gmx.de>
Co-authored-by: Ida Novindasari <idanovinda@gmail.com>
* Add support for pg18 and remove pg13
* Update general spilo image and use new rebuilt e2e spilo image
---------
Co-authored-by: Polina Bungina <polina.bungina@zalando.de>