Compare commits

...

5 Commits

Author SHA1 Message Date
Gabriele Fedi
6d261ae068 chore: lint fix
Signed-off-by: Gabriele Fedi <gabriele.fedi@enterprisedb.com>
2026-04-23 12:23:34 +08:00
Gabriele Fedi
a2657553e3 test: unit tests
Signed-off-by: Gabriele Fedi <gabriele.fedi@enterprisedb.com>
2026-04-23 12:23:34 +08:00
Gabriele Fedi
fea7cb1414 fix: merge labels instead of replacing
Signed-off-by: Gabriele Fedi <gabriele.fedi@enterprisedb.com>
2026-04-23 12:23:34 +08:00
Gabriele Fedi
2b12aa2b18 feat: configure k8s recommended labels on subresources
Signed-off-by: Gabriele Fedi <gabriele.fedi@enterprisedb.com>
2026-04-23 12:23:34 +08:00
Marco Nenciarini
e30154b938
fix: add lz4 compression support for base backups (#868)
Some checks failed
Deploy Docusaurus to GitHub Pages / build (push) Failing after 2s
Deploy Docusaurus to GitHub Pages / deploy (push) Has been skipped
release-please / release-please (push) Failing after 1s
Upgrade barman-cloud library to v0.5.1 which includes lz4 support for
base backups. Update CRD schema and manifest to expose lz4 as a valid
compression option, and clarify docs that lz4 is no longer WAL-only.

Closes #867

Signed-off-by: Marco Nenciarini <marco.nenciarini@enterprisedb.com>
Signed-off-by: Leonardo Cecchi <leonardo.cecchi@gmail.com>
Co-authored-by: Leonardo Cecchi <leonardo.cecchi@gmail.com>
2026-04-21 19:23:45 +02:00
12 changed files with 396 additions and 53 deletions

View File

@ -15,6 +15,7 @@ DigitalOcean
Docusaurus Docusaurus
EDB EDB
EKS EKS
EnterpriseDB
Enum Enum
EnvVar EnvVar
GCP GCP
@ -76,6 +77,7 @@ backends
barmanObjectName barmanObjectName
barmanObjectStore barmanObjectStore
barmancloud barmancloud
benchmarked
boto boto
bzip bzip
cd cd

View File

@ -144,10 +144,11 @@ spec:
description: |- description: |-
Compress a backup file (a tar file per tablespace) while streaming it Compress a backup file (a tar file per tablespace) while streaming it
to the object store. Available options are empty string (no to the object store. Available options are empty string (no
compression, default), `gzip`, `bzip2`, and `snappy`. compression, default), `gzip`, `bzip2`, `lz4`, and `snappy`.
enum: enum:
- bzip2 - bzip2
- gzip - gzip
- lz4
- snappy - snappy
type: string type: string
encryption: encryption:

2
go.mod
View File

@ -7,7 +7,7 @@ toolchain go1.26.2
require ( require (
github.com/cert-manager/cert-manager v1.20.2 github.com/cert-manager/cert-manager v1.20.2
github.com/cloudnative-pg/api v1.29.0 github.com/cloudnative-pg/api v1.29.0
github.com/cloudnative-pg/barman-cloud v0.5.0 github.com/cloudnative-pg/barman-cloud v0.5.1
github.com/cloudnative-pg/cloudnative-pg v1.29.0 github.com/cloudnative-pg/cloudnative-pg v1.29.0
github.com/cloudnative-pg/cnpg-i v0.5.0 github.com/cloudnative-pg/cnpg-i v0.5.0
github.com/cloudnative-pg/cnpg-i-machinery v0.4.2 github.com/cloudnative-pg/cnpg-i-machinery v0.4.2

4
go.sum
View File

@ -20,8 +20,8 @@ github.com/cespare/xxhash/v2 v2.3.0 h1:UL815xU9SqsFlibzuggzjXhog7bL6oX9BbNZnL2UF
github.com/cespare/xxhash/v2 v2.3.0/go.mod h1:VGX0DQ3Q6kWi7AoAeZDth3/j3BFtOZR5XLFGgcrjCOs= github.com/cespare/xxhash/v2 v2.3.0/go.mod h1:VGX0DQ3Q6kWi7AoAeZDth3/j3BFtOZR5XLFGgcrjCOs=
github.com/cloudnative-pg/api v1.29.0 h1:mNx6yJ5qi+Xrjs0NYrUy6V4MlXBkVJxGKwvTJZIuTX4= github.com/cloudnative-pg/api v1.29.0 h1:mNx6yJ5qi+Xrjs0NYrUy6V4MlXBkVJxGKwvTJZIuTX4=
github.com/cloudnative-pg/api v1.29.0/go.mod h1:bF3HI8UVVcllZ7M8CfBufnb+Us8FyQArhD+4qtX0qhM= github.com/cloudnative-pg/api v1.29.0/go.mod h1:bF3HI8UVVcllZ7M8CfBufnb+Us8FyQArhD+4qtX0qhM=
github.com/cloudnative-pg/barman-cloud v0.5.0 h1:DykSaX4o7ee2vyu5FQoG1RJsntHd+EIttIKZbJPlB1Q= github.com/cloudnative-pg/barman-cloud v0.5.1 h1:vjkXrrxo2DQXHT9u9usqhtaHiPZ/lTfDVs/pIWYTepQ=
github.com/cloudnative-pg/barman-cloud v0.5.0/go.mod h1:SO2HzLa+GWlSIpGyxnISoJAFPIcaa/qDa33Bb3jefac= github.com/cloudnative-pg/barman-cloud v0.5.1/go.mod h1:XPc5IUFP1y4cZX1sg+Pd8j9V4tmUEVnv3BGCpfQOOg8=
github.com/cloudnative-pg/cloudnative-pg v1.29.0 h1:49Dm8+y4va7RODspJjeaK8uMWP3OGAD0gMsxhjm16Mo= github.com/cloudnative-pg/cloudnative-pg v1.29.0 h1:49Dm8+y4va7RODspJjeaK8uMWP3OGAD0gMsxhjm16Mo=
github.com/cloudnative-pg/cloudnative-pg v1.29.0/go.mod h1:0Sgb/50VyaCnQm3IbWqgnhQG8Kb6mgqo8Jo1J+KtkSI= github.com/cloudnative-pg/cloudnative-pg v1.29.0/go.mod h1:0Sgb/50VyaCnQm3IbWqgnhQG8Kb6mgqo8Jo1J+KtkSI=
github.com/cloudnative-pg/cnpg-i v0.5.0 h1:/TOzpNT6cwNgrpftTtrnLKdoHgMwd+88vZgXjlVgXeE= github.com/cloudnative-pg/cnpg-i v0.5.0 h1:/TOzpNT6cwNgrpftTtrnLKdoHgMwd+88vZgXjlVgXeE=

View File

@ -31,7 +31,6 @@ import (
"sigs.k8s.io/controller-runtime/pkg/client" "sigs.k8s.io/controller-runtime/pkg/client"
barmancloudv1 "github.com/cloudnative-pg/plugin-barman-cloud/api/v1" barmancloudv1 "github.com/cloudnative-pg/plugin-barman-cloud/api/v1"
"github.com/cloudnative-pg/plugin-barman-cloud/internal/cnpgi/metadata"
"github.com/cloudnative-pg/plugin-barman-cloud/internal/cnpgi/operator/specs" "github.com/cloudnative-pg/plugin-barman-cloud/internal/cnpgi/operator/specs"
) )
@ -62,9 +61,7 @@ func EnsureRole(
return err return err
} }
return patchRole(ctx, c, roleKey, newRole.Rules, map[string]string{ return patchRole(ctx, c, roleKey, newRole.Rules, specs.GetRequiredLabels(cluster))
metadata.ClusterLabelName: cluster.Name,
})
} }
// EnsureRoleRules updates the rules of an existing Role to match // EnsureRoleRules updates the rules of an existing Role to match
@ -90,6 +87,53 @@ func EnsureRoleRules(
return err return err
} }
// EnsureRoleBinding ensures the RoleBinding for the given Cluster matches
// the desired state.
//
// This function is called from the Pre hook (gRPC). It creates the RoleBinding
// if it does not exist, otherwise it patches Subjects and labels to match
// the desired state.
func EnsureRoleBinding(ctx context.Context, c client.Client, cluster *cnpgv1.Cluster) error {
contextLogger := log.FromContext(ctx)
desiredRoleBinding := specs.BuildRoleBinding(cluster)
if err := specs.SetControllerReference(cluster, desiredRoleBinding); err != nil {
return err
}
roleBinding := &rbacv1.RoleBinding{}
if err := c.Get(ctx, client.ObjectKey{
Namespace: cluster.Namespace,
Name: specs.GetRBACName(cluster.Name),
}, roleBinding); err != nil {
if apierrs.IsNotFound(err) {
contextLogger.Info("Creating RoleBinding", "name", desiredRoleBinding.Name,
"namespace", desiredRoleBinding.Namespace)
return c.Create(ctx, desiredRoleBinding)
}
return err
}
if !roleBindingNeedsUpdate(roleBinding, desiredRoleBinding) {
return nil
}
contextLogger.Info("Patching role binding",
"name", roleBinding.Name, "namespace", roleBinding.Namespace)
oldRoleBinding := roleBinding.DeepCopy()
if roleBinding.Labels == nil {
roleBinding.Labels = make(map[string]string, len(desiredRoleBinding.Labels))
}
for k, v := range desiredRoleBinding.Labels {
roleBinding.Labels[k] = v
}
roleBinding.Subjects = desiredRoleBinding.Subjects
return c.Patch(ctx, roleBinding, client.MergeFrom(oldRoleBinding))
}
// ensureRoleExists creates the Role if it does not exist. Returns // ensureRoleExists creates the Role if it does not exist. Returns
// nil on success and nil on AlreadyExists (another writer created // nil on success and nil on AlreadyExists (another writer created
// it concurrently). The caller always follows up with patchRole. // it concurrently). The caller always follows up with patchRole.
@ -179,3 +223,17 @@ func labelsNeedUpdate(existing, desired map[string]string) bool {
} }
return false return false
} }
// roleBindingNeedsUpdate returns true if the existing RoleBinding's
// Subjects differ from the desired or if labels need update.
func roleBindingNeedsUpdate(existing, desired *rbacv1.RoleBinding) bool {
if !equality.Semantic.DeepEqual(existing.Subjects, desired.Subjects) {
return true
}
if labelsNeedUpdate(existing.Labels, desired.Labels) {
return true
}
return false
}

View File

@ -25,6 +25,7 @@ import (
barmanapi "github.com/cloudnative-pg/barman-cloud/pkg/api" barmanapi "github.com/cloudnative-pg/barman-cloud/pkg/api"
cnpgv1 "github.com/cloudnative-pg/cloudnative-pg/api/v1" cnpgv1 "github.com/cloudnative-pg/cloudnative-pg/api/v1"
"github.com/cloudnative-pg/cloudnative-pg/pkg/utils"
machineryapi "github.com/cloudnative-pg/machinery/pkg/api" machineryapi "github.com/cloudnative-pg/machinery/pkg/api"
. "github.com/onsi/ginkgo/v2" . "github.com/onsi/ginkgo/v2"
. "github.com/onsi/gomega" . "github.com/onsi/gomega"
@ -42,6 +43,15 @@ import (
"github.com/cloudnative-pg/plugin-barman-cloud/internal/cnpgi/operator/rbac" "github.com/cloudnative-pg/plugin-barman-cloud/internal/cnpgi/operator/rbac"
) )
func expectRequiredLabels(labels map[string]string, clusterName string) {
ExpectWithOffset(1, labels).To(HaveKeyWithValue(metadata.ClusterLabelName, clusterName))
ExpectWithOffset(1, labels).To(HaveKeyWithValue(utils.KubernetesAppLabelName, utils.AppName))
ExpectWithOffset(1, labels).To(HaveKeyWithValue(utils.KubernetesAppInstanceLabelName, clusterName))
ExpectWithOffset(1, labels).To(HaveKeyWithValue(utils.KubernetesAppManagedByLabelName, "plugin-barman-cloud"))
ExpectWithOffset(1, labels).To(HaveKeyWithValue(utils.KubernetesAppComponentLabelName, utils.DatabaseComponentName))
ExpectWithOffset(1, labels).To(HaveKey(utils.KubernetesAppVersionLabelName))
}
func newScheme() *runtime.Scheme { func newScheme() *runtime.Scheme {
s := runtime.NewScheme() s := runtime.NewScheme()
utilruntime.Must(rbacv1.AddToScheme(s)) utilruntime.Must(rbacv1.AddToScheme(s))
@ -124,7 +134,7 @@ var _ = Describe("EnsureRole", func() {
Expect(role.OwnerReferences[0].Name).To(Equal("test-cluster")) Expect(role.OwnerReferences[0].Name).To(Equal("test-cluster"))
Expect(role.OwnerReferences[0].Kind).To(Equal("Cluster")) Expect(role.OwnerReferences[0].Kind).To(Equal("Cluster"))
Expect(role.Labels).To(HaveKeyWithValue(metadata.ClusterLabelName, "test-cluster")) expectRequiredLabels(role.Labels, "test-cluster")
}) })
}) })
@ -210,7 +220,7 @@ var _ = Describe("EnsureRole", func() {
Name: "test-cluster-barman-cloud", Name: "test-cluster-barman-cloud",
Namespace: "default", Namespace: "default",
Labels: map[string]string{ Labels: map[string]string{
"app.kubernetes.io/managed-by": "helm", "custom-label": "custom-value",
}, },
}, },
} }
@ -227,8 +237,8 @@ var _ = Describe("EnsureRole", func() {
Name: "test-cluster-barman-cloud", Name: "test-cluster-barman-cloud",
}, &role)).To(Succeed()) }, &role)).To(Succeed())
Expect(role.Labels).To(HaveKeyWithValue("app.kubernetes.io/managed-by", "helm")) Expect(role.Labels).To(HaveKeyWithValue("custom-label", "custom-value"))
Expect(role.Labels).To(HaveKeyWithValue(metadata.ClusterLabelName, "test-cluster")) expectRequiredLabels(role.Labels, "test-cluster")
}) })
}) })
@ -257,12 +267,202 @@ var _ = Describe("EnsureRole", func() {
Name: "test-cluster-barman-cloud", Name: "test-cluster-barman-cloud",
}, &role)).To(Succeed()) }, &role)).To(Succeed())
Expect(role.Labels).To(HaveKeyWithValue(metadata.ClusterLabelName, "test-cluster")) expectRequiredLabels(role.Labels, "test-cluster")
Expect(role.Rules).To(HaveLen(3)) Expect(role.Rules).To(HaveLen(3))
}) })
}) })
}) })
var _ = Describe("EnsureRoleBinding", func() {
var (
ctx context.Context
cluster *cnpgv1.Cluster
fakeClient client.Client
)
BeforeEach(func() {
ctx = context.Background()
cluster = newCluster("test-cluster", "default")
})
Context("when the RoleBinding does not exist", func() {
BeforeEach(func() {
fakeClient = fake.NewClientBuilder().WithScheme(newScheme()).Build()
})
It("should create the RoleBinding with owner reference, labels, and correct subjects", func() {
err := rbac.EnsureRoleBinding(ctx, fakeClient, cluster)
Expect(err).NotTo(HaveOccurred())
var rb rbacv1.RoleBinding
Expect(fakeClient.Get(ctx, client.ObjectKey{
Namespace: "default",
Name: "test-cluster-barman-cloud",
}, &rb)).To(Succeed())
Expect(rb.OwnerReferences).To(HaveLen(1))
Expect(rb.OwnerReferences[0].Name).To(Equal("test-cluster"))
Expect(rb.OwnerReferences[0].Kind).To(Equal("Cluster"))
expectRequiredLabels(rb.Labels, "test-cluster")
Expect(rb.Subjects).To(HaveLen(1))
Expect(rb.Subjects[0].Name).To(Equal("test-cluster"))
Expect(rb.Subjects[0].Kind).To(Equal("ServiceAccount"))
Expect(rb.RoleRef.Kind).To(Equal("Role"))
Expect(rb.RoleRef.Name).To(Equal("test-cluster-barman-cloud"))
})
})
Context("when the RoleBinding exists with matching state", func() {
BeforeEach(func() {
fakeClient = fake.NewClientBuilder().WithScheme(newScheme()).Build()
Expect(rbac.EnsureRoleBinding(ctx, fakeClient, cluster)).To(Succeed())
})
It("should not patch the RoleBinding", func() {
var before rbacv1.RoleBinding
Expect(fakeClient.Get(ctx, client.ObjectKey{
Namespace: "default",
Name: "test-cluster-barman-cloud",
}, &before)).To(Succeed())
err := rbac.EnsureRoleBinding(ctx, fakeClient, cluster)
Expect(err).NotTo(HaveOccurred())
var after rbacv1.RoleBinding
Expect(fakeClient.Get(ctx, client.ObjectKey{
Namespace: "default",
Name: "test-cluster-barman-cloud",
}, &after)).To(Succeed())
Expect(after.ResourceVersion).To(Equal(before.ResourceVersion))
})
})
Context("when the RoleBinding exists with different subjects", func() {
BeforeEach(func() {
fakeClient = fake.NewClientBuilder().WithScheme(newScheme()).Build()
existing := &rbacv1.RoleBinding{
ObjectMeta: metav1.ObjectMeta{
Name: "test-cluster-barman-cloud",
Namespace: "default",
},
Subjects: []rbacv1.Subject{
{
Kind: "ServiceAccount",
Name: "old-sa",
APIGroup: "",
},
},
RoleRef: rbacv1.RoleRef{
APIGroup: "rbac.authorization.k8s.io",
Kind: "Role",
Name: "test-cluster-barman-cloud",
},
}
Expect(fakeClient.Create(ctx, existing)).To(Succeed())
})
It("should patch the subjects to match the desired state", func() {
err := rbac.EnsureRoleBinding(ctx, fakeClient, cluster)
Expect(err).NotTo(HaveOccurred())
var rb rbacv1.RoleBinding
Expect(fakeClient.Get(ctx, client.ObjectKey{
Namespace: "default",
Name: "test-cluster-barman-cloud",
}, &rb)).To(Succeed())
Expect(rb.Subjects).To(HaveLen(1))
Expect(rb.Subjects[0].Name).To(Equal("test-cluster"))
})
})
Context("when the RoleBinding has pre-existing unrelated labels", func() {
BeforeEach(func() {
fakeClient = fake.NewClientBuilder().WithScheme(newScheme()).Build()
existing := &rbacv1.RoleBinding{
ObjectMeta: metav1.ObjectMeta{
Name: "test-cluster-barman-cloud",
Namespace: "default",
Labels: map[string]string{
"custom-label": "custom-value",
},
},
Subjects: []rbacv1.Subject{
{
Kind: "ServiceAccount",
Name: "test-cluster",
Namespace: "default",
APIGroup: "",
},
},
RoleRef: rbacv1.RoleRef{
APIGroup: "rbac.authorization.k8s.io",
Kind: "Role",
Name: "test-cluster-barman-cloud",
},
}
Expect(fakeClient.Create(ctx, existing)).To(Succeed())
})
It("should preserve unrelated labels while adding the required labels", func() {
err := rbac.EnsureRoleBinding(ctx, fakeClient, cluster)
Expect(err).NotTo(HaveOccurred())
var rb rbacv1.RoleBinding
Expect(fakeClient.Get(ctx, client.ObjectKey{
Namespace: "default",
Name: "test-cluster-barman-cloud",
}, &rb)).To(Succeed())
Expect(rb.Labels).To(HaveKeyWithValue("custom-label", "custom-value"))
expectRequiredLabels(rb.Labels, "test-cluster")
})
})
Context("when the RoleBinding exists without labels (upgrade scenario)", func() {
BeforeEach(func() {
fakeClient = fake.NewClientBuilder().WithScheme(newScheme()).Build()
existing := &rbacv1.RoleBinding{
ObjectMeta: metav1.ObjectMeta{
Name: "test-cluster-barman-cloud",
Namespace: "default",
},
Subjects: []rbacv1.Subject{
{
Kind: "ServiceAccount",
Name: "test-cluster",
Namespace: "default",
APIGroup: "",
},
},
RoleRef: rbacv1.RoleRef{
APIGroup: "rbac.authorization.k8s.io",
Kind: "Role",
Name: "test-cluster-barman-cloud",
},
}
Expect(fakeClient.Create(ctx, existing)).To(Succeed())
})
It("should add the required labels", func() {
err := rbac.EnsureRoleBinding(ctx, fakeClient, cluster)
Expect(err).NotTo(HaveOccurred())
var rb rbacv1.RoleBinding
Expect(fakeClient.Get(ctx, client.ObjectKey{
Namespace: "default",
Name: "test-cluster-barman-cloud",
}, &rb)).To(Succeed())
expectRequiredLabels(rb.Labels, "test-cluster")
})
})
})
var _ = Describe("EnsureRoleRules", func() { var _ = Describe("EnsureRoleRules", func() {
var ( var (
ctx context.Context ctx context.Context

View File

@ -27,14 +27,12 @@ import (
"github.com/cloudnative-pg/cnpg-i-machinery/pkg/pluginhelper/object" "github.com/cloudnative-pg/cnpg-i-machinery/pkg/pluginhelper/object"
"github.com/cloudnative-pg/cnpg-i/pkg/reconciler" "github.com/cloudnative-pg/cnpg-i/pkg/reconciler"
"github.com/cloudnative-pg/machinery/pkg/log" "github.com/cloudnative-pg/machinery/pkg/log"
rbacv1 "k8s.io/api/rbac/v1"
apierrs "k8s.io/apimachinery/pkg/api/errors" apierrs "k8s.io/apimachinery/pkg/api/errors"
"sigs.k8s.io/controller-runtime/pkg/client" "sigs.k8s.io/controller-runtime/pkg/client"
barmancloudv1 "github.com/cloudnative-pg/plugin-barman-cloud/api/v1" barmancloudv1 "github.com/cloudnative-pg/plugin-barman-cloud/api/v1"
"github.com/cloudnative-pg/plugin-barman-cloud/internal/cnpgi/operator/config" "github.com/cloudnative-pg/plugin-barman-cloud/internal/cnpgi/operator/config"
"github.com/cloudnative-pg/plugin-barman-cloud/internal/cnpgi/operator/rbac" "github.com/cloudnative-pg/plugin-barman-cloud/internal/cnpgi/operator/rbac"
"github.com/cloudnative-pg/plugin-barman-cloud/internal/cnpgi/operator/specs"
) )
// ReconcilerImplementation implements the Reconciler capability // ReconcilerImplementation implements the Reconciler capability
@ -117,7 +115,7 @@ func (r ReconcilerImplementation) Pre(
return nil, err return nil, err
} }
if err := r.ensureRoleBinding(ctx, &cluster); err != nil { if err := rbac.EnsureRoleBinding(ctx, r.Client, &cluster); err != nil {
return nil, err return nil, err
} }
@ -136,34 +134,3 @@ func (r ReconcilerImplementation) Post(
Behavior: reconciler.ReconcilerHooksResult_BEHAVIOR_CONTINUE, Behavior: reconciler.ReconcilerHooksResult_BEHAVIOR_CONTINUE,
}, nil }, nil
} }
func (r ReconcilerImplementation) ensureRoleBinding(
ctx context.Context,
cluster *cnpgv1.Cluster,
) error {
var roleBinding rbacv1.RoleBinding
if err := r.Client.Get(ctx, client.ObjectKey{
Namespace: cluster.Namespace,
Name: specs.GetRBACName(cluster.Name),
}, &roleBinding); err != nil {
if apierrs.IsNotFound(err) {
return r.createRoleBinding(ctx, cluster)
}
return err
}
// TODO: this assumes role bindings never change.
// Is that true? Should we relax this assumption?
return nil
}
func (r ReconcilerImplementation) createRoleBinding(
ctx context.Context,
cluster *cnpgv1.Cluster,
) error {
roleBinding := specs.BuildRoleBinding(cluster)
if err := specs.SetControllerReference(cluster, roleBinding); err != nil {
return err
}
return r.Client.Create(ctx, roleBinding)
}

View File

@ -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 specs
import (
"fmt"
cnpgv1 "github.com/cloudnative-pg/cloudnative-pg/api/v1"
"github.com/cloudnative-pg/cloudnative-pg/pkg/utils"
"github.com/cloudnative-pg/plugin-barman-cloud/internal/cnpgi/metadata"
)
// GetRequiredLabels returns the labels that must be present on all plugin-managed objects for a given Cluster.
func GetRequiredLabels(cluster *cnpgv1.Cluster) map[string]string {
requiredLabels := map[string]string{
metadata.ClusterLabelName: cluster.Name,
// Kubernetes recommended labels
utils.KubernetesAppLabelName: utils.AppName,
utils.KubernetesAppInstanceLabelName: cluster.Name,
utils.KubernetesAppManagedByLabelName: "plugin-barman-cloud",
utils.KubernetesAppComponentLabelName: utils.DatabaseComponentName,
}
if version, err := cluster.GetPostgresqlMajorVersion(); err == nil && version != 0 {
requiredLabels[utils.KubernetesAppVersionLabelName] = fmt.Sprint(version)
}
return requiredLabels
}

View File

@ -0,0 +1,67 @@
/*
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 specs
import (
cnpgv1 "github.com/cloudnative-pg/cloudnative-pg/api/v1"
"github.com/cloudnative-pg/cloudnative-pg/pkg/utils"
. "github.com/onsi/ginkgo/v2"
. "github.com/onsi/gomega"
metav1 "k8s.io/apimachinery/pkg/apis/meta/v1"
"github.com/cloudnative-pg/plugin-barman-cloud/internal/cnpgi/metadata"
)
var _ = Describe("GetRequiredLabels", func() {
It("should return all expected labels for a cluster without an image", func() {
cluster := &cnpgv1.Cluster{
ObjectMeta: metav1.ObjectMeta{
Name: "my-cluster",
Namespace: "default",
},
}
labels := GetRequiredLabels(cluster)
Expect(labels).To(HaveKeyWithValue(metadata.ClusterLabelName, "my-cluster"))
Expect(labels).To(HaveKeyWithValue(utils.KubernetesAppLabelName, utils.AppName))
Expect(labels).To(HaveKeyWithValue(utils.KubernetesAppInstanceLabelName, "my-cluster"))
Expect(labels).To(HaveKeyWithValue(utils.KubernetesAppManagedByLabelName, "plugin-barman-cloud"))
Expect(labels).To(HaveKeyWithValue(utils.KubernetesAppComponentLabelName, utils.DatabaseComponentName))
Expect(labels).To(HaveLen(6))
})
It("should use the major version from the image catalog ref", func() {
cluster := &cnpgv1.Cluster{
ObjectMeta: metav1.ObjectMeta{
Name: "pg16-cluster",
Namespace: "default",
},
Spec: cnpgv1.ClusterSpec{
ImageCatalogRef: &cnpgv1.ImageCatalogRef{
Major: 16,
},
},
}
labels := GetRequiredLabels(cluster)
Expect(labels).To(HaveKeyWithValue(utils.KubernetesAppVersionLabelName, "16"))
Expect(labels).To(HaveKeyWithValue(utils.KubernetesAppInstanceLabelName, "pg16-cluster"))
})
})

View File

@ -29,7 +29,6 @@ import (
metav1 "k8s.io/apimachinery/pkg/apis/meta/v1" metav1 "k8s.io/apimachinery/pkg/apis/meta/v1"
barmancloudv1 "github.com/cloudnative-pg/plugin-barman-cloud/api/v1" barmancloudv1 "github.com/cloudnative-pg/plugin-barman-cloud/api/v1"
"github.com/cloudnative-pg/plugin-barman-cloud/internal/cnpgi/metadata"
) )
// BuildRole builds the Role object for this cluster // BuildRole builds the Role object for this cluster
@ -41,9 +40,7 @@ func BuildRole(
ObjectMeta: metav1.ObjectMeta{ ObjectMeta: metav1.ObjectMeta{
Namespace: cluster.Namespace, Namespace: cluster.Namespace,
Name: GetRBACName(cluster.Name), Name: GetRBACName(cluster.Name),
Labels: map[string]string{ Labels: GetRequiredLabels(cluster),
metadata.ClusterLabelName: cluster.Name,
},
}, },
Rules: BuildRoleRules(barmanObjects), Rules: BuildRoleRules(barmanObjects),
} }
@ -131,6 +128,7 @@ func BuildRoleBinding(
ObjectMeta: metav1.ObjectMeta{ ObjectMeta: metav1.ObjectMeta{
Namespace: cluster.Namespace, Namespace: cluster.Namespace,
Name: GetRBACName(cluster.Name), Name: GetRBACName(cluster.Name),
Labels: GetRequiredLabels(cluster),
}, },
Subjects: []rbacv1.Subject{ Subjects: []rbacv1.Subject{
{ {

View File

@ -143,10 +143,11 @@ spec:
description: |- description: |-
Compress a backup file (a tar file per tablespace) while streaming it Compress a backup file (a tar file per tablespace) while streaming it
to the object store. Available options are empty string (no to the object store. Available options are empty string (no
compression, default), `gzip`, `bzip2`, and `snappy`. compression, default), `gzip`, `bzip2`, `lz4`, and `snappy`.
enum: enum:
- bzip2 - bzip2
- gzip - gzip
- lz4
- snappy - snappy
type: string type: string
encryption: encryption:

View File

@ -15,7 +15,7 @@ for space, speed, or a balance of both.
- `bzip2` - `bzip2`
- `gzip` - `gzip`
- `lz4` (WAL only) - `lz4`
- `snappy` - `snappy`
- `xz` (WAL only) - `xz` (WAL only)
- `zstd` (WAL only) - `zstd` (WAL only)
@ -41,3 +41,5 @@ network throughput.
| bzip2 | 25,404 | 13,886 | 395 | 67 | 5.9:1 | | bzip2 | 25,404 | 13,886 | 395 | 67 | 5.9:1 |
| gzip | 116,281 | 3,077 | 395 | 91 | 4.3:1 | | gzip | 116,281 | 3,077 | 395 | 91 | 4.3:1 |
| snappy | 8,134 | 8,341 | 395 | 166 | 2.4:1 | | snappy | 8,134 | 8,341 | 395 | 166 | 2.4:1 |
Numbers come from a 2021 Barman proof of concept ([EnterpriseDB/barman#344](https://github.com/EnterpriseDB/barman/issues/344#issuecomment-992547396)), which predates `lz4` support for base backups. `lz4` is not yet benchmarked.