From 20e5afeba7ec8ba5e460acb3657a1f8c67d152d0 Mon Sep 17 00:00:00 2001 From: Leonardo Cecchi Date: Tue, 16 Jun 2026 16:08:59 +0200 Subject: [PATCH] fix: inject barman sidecar in replica clusters bootstrapped with pg_basebackup Replica clusters that use `pg_basebackup` as the bootstrap method and stream WAL from an object store were not getting the barman sidecar injected, causing WAL restore to fail silently. These clusters are now handled correctly. Signed-off-by: Leonardo Cecchi --- hack/examples/cluster-replica-streaming.yaml | 36 ++++++++++++++ internal/cnpgi/operator/config/config.go | 4 +- internal/cnpgi/operator/config/config_test.go | 47 +++++++++++++++++++ internal/cnpgi/operator/config/suite_test.go | 32 +++++++++++++ 4 files changed, 118 insertions(+), 1 deletion(-) create mode 100644 hack/examples/cluster-replica-streaming.yaml create mode 100644 internal/cnpgi/operator/config/config_test.go create mode 100644 internal/cnpgi/operator/config/suite_test.go diff --git a/hack/examples/cluster-replica-streaming.yaml b/hack/examples/cluster-replica-streaming.yaml new file mode 100644 index 0000000..1fba84c --- /dev/null +++ b/hack/examples/cluster-replica-streaming.yaml @@ -0,0 +1,36 @@ +apiVersion: postgresql.cnpg.io/v1 +kind: Cluster +metadata: + name: cluster-replica +spec: + instances: 3 + bootstrap: + pg_basebackup: + source: source + replica: + enabled: true + source: source + externalClusters: + - name: source + connectionParameters: + host: cluster-example-rw.default.svc + user: streaming_replica + sslmode: verify-full + dbname: postgres + sslKey: + name: cluster-example-replication + key: tls.key + sslCert: + name: cluster-example-replication + key: tls.crt + sslRootCert: + name: cluster-example-ca + key: ca.crt + plugin: + name: barman-cloud.cloudnative-pg.io + parameters: + barmanObjectName: minio-store + serverName: cluster-example + storage: + size: 1Gi + diff --git a/internal/cnpgi/operator/config/config.go b/internal/cnpgi/operator/config/config.go index 61c7063..7f16dda 100644 --- a/internal/cnpgi/operator/config/config.go +++ b/internal/cnpgi/operator/config/config.go @@ -263,7 +263,9 @@ func getReplicaSourcePlugin(cluster *cnpgv1.Cluster) *cnpgv1.PluginConfiguration func (config *PluginConfiguration) Validate() error { err := NewConfigurationError() - if len(config.BarmanObjectName) == 0 && len(config.RecoveryBarmanObjectName) == 0 { + if len(config.BarmanObjectName) == 0 && + len(config.RecoveryBarmanObjectName) == 0 && + len(config.ReplicaSourceBarmanObjectName) == 0 { return err.WithMessage("no reference to barmanObjectName have been included") } diff --git a/internal/cnpgi/operator/config/config_test.go b/internal/cnpgi/operator/config/config_test.go new file mode 100644 index 0000000..a3da6c8 --- /dev/null +++ b/internal/cnpgi/operator/config/config_test.go @@ -0,0 +1,47 @@ +/* +Copyright © contributors to CloudNativePG, established as +CloudNativePG a Series of LF Projects, LLC. + +Licensed under the Apache License, Version 2.0 (the "License"); +you may not use this file except in compliance with the License. +You may obtain a copy of the License at + + http://www.apache.org/licenses/LICENSE-2.0 + +Unless required by applicable law or agreed to in writing, software +distributed under the License is distributed on an "AS IS" BASIS, +WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +See the License for the specific language governing permissions and +limitations under the License. + +SPDX-License-Identifier: Apache-2.0 +*/ + +package config + +import ( + . "github.com/onsi/ginkgo/v2" + . "github.com/onsi/gomega" +) + +var _ = Describe("PluginConfiguration.Validate", func() { + It("fails when no barman object name is set", func() { + cfg := &PluginConfiguration{} + Expect(cfg.Validate()).To(HaveOccurred()) + }) + + It("passes when only BarmanObjectName is set (backup/archive)", func() { + cfg := &PluginConfiguration{BarmanObjectName: "my-store"} + Expect(cfg.Validate()).To(Succeed()) + }) + + It("passes when only RecoveryBarmanObjectName is set (recovery bootstrap)", func() { + cfg := &PluginConfiguration{RecoveryBarmanObjectName: "my-store"} + Expect(cfg.Validate()).To(Succeed()) + }) + + It("passes when only ReplicaSourceBarmanObjectName is set (pg_basebackup replica cluster)", func() { + cfg := &PluginConfiguration{ReplicaSourceBarmanObjectName: "my-store"} + Expect(cfg.Validate()).To(Succeed()) + }) +}) diff --git a/internal/cnpgi/operator/config/suite_test.go b/internal/cnpgi/operator/config/suite_test.go new file mode 100644 index 0000000..5448bb3 --- /dev/null +++ b/internal/cnpgi/operator/config/suite_test.go @@ -0,0 +1,32 @@ +/* +Copyright © contributors to CloudNativePG, established as +CloudNativePG a Series of LF Projects, LLC. + +Licensed under the Apache License, Version 2.0 (the "License"); +you may not use this file except in compliance with the License. +You may obtain a copy of the License at + + http://www.apache.org/licenses/LICENSE-2.0 + +Unless required by applicable law or agreed to in writing, software +distributed under the License is distributed on an "AS IS" BASIS, +WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +See the License for the specific language governing permissions and +limitations under the License. + +SPDX-License-Identifier: Apache-2.0 +*/ + +package config + +import ( + "testing" + + . "github.com/onsi/ginkgo/v2" + . "github.com/onsi/gomega" +) + +func TestConfig(t *testing.T) { + RegisterFailHandler(Fail) + RunSpecs(t, "Config Suite") +}