Repository: cloudnative-pg/cloudnative-pg

Issue:
[Bug]: OLM interface failing with missing field spec.postgresql.synchronous.method
### Is there an existing issue already for this bug?

- [x] I have searched for an existing issue, and could not find anything. I believe this is a new bug.

### I have read the troubleshooting guide

- [x] I have read the troubleshooting guide and I think this is a new bug.

### I am running a supported version of CloudNativePG

- [x] I have read the troubleshooting guide and I think this is a new bug.

### Contact Details

_No response_

### Version

1.26.0-rc3

### What version of Kubernetes are you using?

1.32

### What is your Kubernetes environment?

Self-managed: kind (evaluation)

### How did you install the operator?

YAML manifest

### What happened?

The OLM interface is failing creating a cluster with only defaults with the following error:
```
Error "Unsupported value: "": supported values: "any", "first"" for field "spec.postgresql.synchronous.method".
```

### Cluster resource

```shell

```

### Relevant log output

```shell

```

### Code of Conduct

- [x] I agree to follow this project's Code of Conduct

Hints from issue comments:
@dosubot: <!-- Answer -->
The error you're encountering suggests that the `spec.postgresql.synchronous.method` field is missing or has an unsupported value during cluster creation. This field should be set to either `any` or `first` to specify the method of synchronous replication <sup>[[1]](https://github.com/cloudnative-pg/cloudnative-pg/blob/main/releases/cnpg-1.26.0-rc3.yaml)</sup>.

To resolve this issue, ensure that your YAML manifest explicitly includes the `spec.postgresql.synchronous.method` field with a valid value. Here's an example of how you might configure it:

```yaml
postgresql:
  synchronous:
    method: any  # or 'first'
```

Make sure this configuration is included in your cluster resource definition to avoid the error. If the field is missing, the default value should be `any`, but it seems like the OLM interface requires explicit specification <sup>[[2]](https://cloudnative-pg.io/documentation/current/replication)</sup>.


<!-- Dosu Comment Footer -->
*To continue talking to [Dosu](https://dosu.dev), mention @dosu.*

---
<sup>Help Dosu learn! Give it feedback: [Great Response](https://app.dosu.dev/response-feedback/e9beba30-edbf-470d-b514-5e8f62f54a37?feedback_type=great_response) | [Irrelevant Answer](https://app.dosu.dev/response-feedback/e9beba30-edbf-470d-b514-5e8f62f54a37?feedback_type=irrelevant_answer) | [Incorrect Sources](https://app.dosu.dev/response-feedback/e9beba30-edbf-470d-b514-5e8f62f54a37?feedback_type=incorrect_sources) | [Too Verbose](https://app.dosu.dev/response-feedback/e9beba30-edbf-470d-b514-5e8f62f54a37?feedback_type=too_verbose) | [Hallucination](https://app.dosu.dev/response-feedback/e9beba30-edbf-470d-b514-5e8f62f54a37?feedback_type=hallucination) | [Bug Report](https://app.dosu.dev/response-feedback/e9beba30-edbf-470d-b514-5e8f62f54a37?feedback_type=bug_report) | [Other](https://app.dosu.dev/response-feedback/e9beba30-edbf-470d-b514-5e8f62f54a37?feedback_type=other)</sup>


Solution patch:
diff --git a/api/v1/cluster_defaults.go b/api/v1/cluster_defaults.go
index a851f3ce..d026d70d 100644
--- a/api/v1/cluster_defaults.go
+++ b/api/v1/cluster_defaults.go
@@ -132,6 +132,11 @@ func (r *Cluster) setDefaults(preserveUserSettings bool) {
 		r.defaultTablespaces()
 	}
 
+	if r.Spec.PostgresConfiguration.Synchronous != nil &&
+		r.Spec.PostgresConfiguration.Synchronous.DataDurability == "" {
+		r.Spec.PostgresConfiguration.Synchronous.DataDurability = DataDurabilityLevelRequired
+	}
+
 	r.setDefaultPlugins(configuration.Current)
 }
 
diff --git a/api/v1/cluster_types.go b/api/v1/cluster_types.go
index 21c43565..3602933f 100644
--- a/api/v1/cluster_types.go
+++ b/api/v1/cluster_types.go
@@ -1317,7 +1317,6 @@ type SynchronousReplicaConfiguration struct {
 	// to allow for operational continuity. This setting is only applicable if both
 	// `standbyNamesPre` and `standbyNamesPost` are unset (empty).
 	// +kubebuilder:validation:Enum=required;preferred
-	// +kubebuilder:default:=required
 	// +optional
 	DataDurability DataDurabilityLevel `json:"dataDurability,omitempty"`
 }
diff --git a/config/crd/bases/postgresql.cnpg.io_clusters.yaml b/config/crd/bases/postgresql.cnpg.io_clusters.yaml
index 7b547370..d6d25fc4 100644
--- a/config/crd/bases/postgresql.cnpg.io_clusters.yaml
+++ b/config/crd/bases/postgresql.cnpg.io_clusters.yaml
@@ -4146,7 +4146,6 @@ spec:
                       feature
                     properties:
                       dataDurability:
-                        default: required
                         description: |-
                           If set to "required", data durability is strictly enforced. Write operations
                           with synchronous commit settings (`on`, `remote_write`, or `remote_apply`) will



Test patch:
diff --git a/api/v1/cluster_defaults_test.go b/api/v1/cluster_defaults_test.go
index 1c6f02e0..4250ef8b 100644
--- a/api/v1/cluster_defaults_test.go
+++ b/api/v1/cluster_defaults_test.go
@@ -317,3 +317,45 @@ var _ = Describe("setDefaultPlugins", func() {
 			ContainElement(PluginConfiguration{Name: "predefined-plugin1", Enabled: ptr.To(true)}))
 	})
 })
+
+var _ = Describe("default dataDurability", func() {
+	It("should default dataDurability to 'required' when synchronous is present", func() {
+		cluster := &Cluster{
+			Spec: ClusterSpec{
+				PostgresConfiguration: PostgresConfiguration{
+					Synchronous: &SynchronousReplicaConfiguration{},
+				},
+			},
+		}
+		cluster.SetDefaults()
+		Expect(cluster.Spec.PostgresConfiguration.Synchronous).ToNot(BeNil())
+		Expect(cluster.Spec.PostgresConfiguration.Synchronous.DataDurability).To(Equal(DataDurabilityLevelRequired))
+	})
+
+	It("should not touch synchronous if nil", func() {
+		cluster := &Cluster{
+			Spec: ClusterSpec{
+				PostgresConfiguration: PostgresConfiguration{
+					Synchronous: nil,
+				},
+			},
+		}
+		cluster.SetDefaults()
+		Expect(cluster.Spec.PostgresConfiguration.Synchronous).To(BeNil())
+	})
+
+	It("should not change the dataDurability when set", func() {
+		cluster := &Cluster{
+			Spec: ClusterSpec{
+				PostgresConfiguration: PostgresConfiguration{
+					Synchronous: &SynchronousReplicaConfiguration{
+						DataDurability: DataDurabilityLevelPreferred,
+					},
+				},
+			},
+		}
+		cluster.SetDefaults()
+		Expect(cluster.Spec.PostgresConfiguration.Synchronous).ToNot(BeNil())
+		Expect(cluster.Spec.PostgresConfiguration.Synchronous.DataDurability).To(Equal(DataDurabilityLevelPreferred))
+	})
+})