mirror of
https://github.com/cloudnative-pg/plugin-barman-cloud.git
synced 2026-07-09 19:22:21 +02:00
Compare commits
5 Commits
4acc222462
...
6d261ae068
| Author | SHA1 | Date | |
|---|---|---|---|
|
|
6d261ae068 | ||
|
|
a2657553e3 | ||
|
|
fea7cb1414 | ||
|
|
2b12aa2b18 | ||
|
|
e30154b938 |
@ -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
|
||||||
|
|||||||
@ -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
2
go.mod
@ -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
4
go.sum
@ -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=
|
||||||
|
|||||||
@ -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
|
||||||
|
}
|
||||||
|
|||||||
@ -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
|
||||||
|
|||||||
@ -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)
|
|
||||||
}
|
|
||||||
|
|||||||
47
internal/cnpgi/operator/specs/metadata.go
Normal file
47
internal/cnpgi/operator/specs/metadata.go
Normal 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
|
||||||
|
}
|
||||||
67
internal/cnpgi/operator/specs/metadata_test.go
Normal file
67
internal/cnpgi/operator/specs/metadata_test.go
Normal 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"))
|
||||||
|
})
|
||||||
|
})
|
||||||
@ -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{
|
||||||
{
|
{
|
||||||
|
|||||||
@ -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:
|
||||||
|
|||||||
@ -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.
|
||||||
|
|||||||
Loading…
Reference in New Issue
Block a user