Skip to content

Commit f936bf1

Browse files
leonardocemnencia
authored andcommitted
feat: lenient decoding of CNPG resources
This patch allows the barman-cloud plugin to work with operator being structurally identical with CNPG but with a different API group. It does that by using lenient decoding of the passed CNPG resources and by injecting the detected GVK to the sidecar, that uses it to properly encode and decode the Kubernetes resources. Signed-off-by: Leonardo Cecchi <[email protected]>
1 parent fcbc472 commit f936bf1

File tree

8 files changed

+110
-34
lines changed

8 files changed

+110
-34
lines changed

go.mod

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -136,3 +136,5 @@ require (
136136
sigs.k8s.io/structured-merge-diff/v4 v4.5.0 // indirect
137137
sigs.k8s.io/yaml v1.4.0 // indirect
138138
)
139+
140+
replace github.com/cloudnative-pg/cnpg-i-machinery => github.com/leonardoce/cnpg-i-machinery v0.0.0-20250307135524-f7d0a34b5b3e

go.sum

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -26,8 +26,6 @@ github.com/cloudnative-pg/cloudnative-pg v1.25.1 h1:Yc6T7ikQ1AiWXBQht+6C3DoihrIp
2626
github.com/cloudnative-pg/cloudnative-pg v1.25.1/go.mod h1:96b9bRFLSr3uFWHjhytPdcvKIKwy9H6AG7cH0O6jefs=
2727
github.com/cloudnative-pg/cnpg-i v0.1.0 h1:QH2xTsrODMhEEc6B25GbOYe7ZIttDmSkYvXotfU5dfs=
2828
github.com/cloudnative-pg/cnpg-i v0.1.0/go.mod h1:G28BhgUEHqrxEyyQeHz8BbpMVAsGuLhJm/tHUbDi8Sw=
29-
github.com/cloudnative-pg/cnpg-i-machinery v0.1.2 h1:yY8tBkN8l8ENNWDMK0ZewK+nNzsxuSvxbSfkwJoSSZ0=
30-
github.com/cloudnative-pg/cnpg-i-machinery v0.1.2/go.mod h1:4Lf5Vfl8tvCsgs7H38+JMkvFhUMIDiNoZtzfwqyFE+E=
3129
github.com/cloudnative-pg/machinery v0.1.0 h1:tjRmsqQmsO/OlaT0uFmkEtVqgr+SGPM88cKZOHYKLBo=
3230
github.com/cloudnative-pg/machinery v0.1.0/go.mod h1:0V3vm44FaIsY+x4pm8ORry7xCC3AJiO+ebfPNxeP5Ck=
3331
github.com/cpuguy83/go-md2man/v2 v2.0.6/go.mod h1:oOW0eioCTA6cOiMLiUPZOpcVxMig6NIQQ7OS05n1F4g=
@@ -116,6 +114,8 @@ github.com/kubernetes-csi/external-snapshotter/client/v8 v8.2.0 h1:Q3jQ1NkFqv5o+
116114
github.com/kubernetes-csi/external-snapshotter/client/v8 v8.2.0/go.mod h1:E3vdYxHj2C2q6qo8/Da4g7P+IcwqRZyy3gJBzYybV9Y=
117115
github.com/kylelemons/godebug v1.1.0 h1:RPNrshWIDI6G2gRW9EHilWtl7Z6Sb1BR0xunSBf0SNc=
118116
github.com/kylelemons/godebug v1.1.0/go.mod h1:9/0rRGxNHcop5bhtWyNeEfOS8JIWk580+fNqagV/RAw=
117+
github.com/leonardoce/cnpg-i-machinery v0.0.0-20250307135524-f7d0a34b5b3e h1:j8lLGGMIvNqPKIWYAVUtz+OspxXwxK/s/jdg18ZuaGU=
118+
github.com/leonardoce/cnpg-i-machinery v0.0.0-20250307135524-f7d0a34b5b3e/go.mod h1:4Lf5Vfl8tvCsgs7H38+JMkvFhUMIDiNoZtzfwqyFE+E=
119119
github.com/lib/pq v1.10.9 h1:YXG7RB+JIjhP29X+OtkiDnYaXQwpS4JEWq7dtCCRUEw=
120120
github.com/lib/pq v1.10.9/go.mod h1:AlVN5x4E4T544tWzH6hKfbfQvm3HdbOxrmggDNAPY9o=
121121
github.com/magiconair/properties v1.8.7 h1:IeQXZAiQcpL9mgcAe1Nu6cX9LLw6ExEHKjN0VQdvPDY=

internal/cmd/instance/main.go

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -36,6 +36,8 @@ func NewCmd() *cobra.Command {
3636
_ = viper.BindEnv("pod-name", "POD_NAME")
3737
_ = viper.BindEnv("pgdata", "PGDATA")
3838
_ = viper.BindEnv("spool-directory", "SPOOL_DIRECTORY")
39+
_ = viper.BindEnv("custom-cnpg-group", "CUSTOM_CNPG_GROUP")
40+
_ = viper.BindEnv("custom-cnpg-version", "CUSTOM_CNPG_VERSIONXS")
3941

4042
return cmd
4143
}

internal/cnpgi/instance/manager.go

Lines changed: 36 additions & 8 deletions
Original file line numberDiff line numberDiff line change
@@ -8,26 +8,22 @@ import (
88
"github.com/spf13/viper"
99
corev1 "k8s.io/api/core/v1"
1010
"k8s.io/apimachinery/pkg/runtime"
11+
"k8s.io/apimachinery/pkg/runtime/schema"
1112
utilruntime "k8s.io/apimachinery/pkg/util/runtime"
1213
clientgoscheme "k8s.io/client-go/kubernetes/scheme"
1314
ctrl "sigs.k8s.io/controller-runtime"
1415
"sigs.k8s.io/controller-runtime/pkg/client"
1516
"sigs.k8s.io/controller-runtime/pkg/log"
17+
"sigs.k8s.io/controller-runtime/pkg/scheme"
1618

1719
barmancloudv1 "github.com/cloudnative-pg/plugin-barman-cloud/api/v1"
1820
extendedclient "github.com/cloudnative-pg/plugin-barman-cloud/internal/cnpgi/instance/internal/client"
1921
)
2022

21-
var scheme = runtime.NewScheme()
22-
23-
func init() {
24-
utilruntime.Must(barmancloudv1.AddToScheme(scheme))
25-
utilruntime.Must(cnpgv1.AddToScheme(scheme))
26-
utilruntime.Must(clientgoscheme.AddToScheme(scheme))
27-
}
28-
2923
// Start starts the sidecar informers and CNPG-i server
3024
func Start(ctx context.Context) error {
25+
scheme := generateScheme(ctx)
26+
3127
setupLog := log.FromContext(ctx)
3228
setupLog.Info("Starting barman cloud instance plugin")
3329
podName := viper.GetString("pod-name")
@@ -70,3 +66,35 @@ func Start(ctx context.Context) error {
7066

7167
return nil
7268
}
69+
70+
// generateScheme creates a runtime.Scheme object with all the
71+
// definition needed to support the sidecar. This allows
72+
// the plugin to be used in every CNPG-based operator.
73+
func generateScheme(ctx context.Context) *runtime.Scheme {
74+
result := runtime.NewScheme()
75+
76+
utilruntime.Must(barmancloudv1.AddToScheme(result))
77+
utilruntime.Must(clientgoscheme.AddToScheme(result))
78+
79+
cnpgGroup := viper.GetString("custom-cnpg-group")
80+
cnpgVersion := viper.GetString("custom-cnpg-version")
81+
if len(cnpgGroup) == 0 {
82+
cnpgGroup = cnpgv1.SchemeGroupVersion.Group
83+
}
84+
if len(cnpgVersion) == 0 {
85+
cnpgVersion = cnpgv1.SchemeGroupVersion.Version
86+
}
87+
88+
// Proceed with custom registration of the CNPG scheme
89+
schemeGroupVersion := schema.GroupVersion{Group: cnpgGroup, Version: cnpgVersion}
90+
schemeBuilder := &scheme.Builder{GroupVersion: schemeGroupVersion}
91+
schemeBuilder.Register(&cnpgv1.Cluster{}, &cnpgv1.ClusterList{})
92+
schemeBuilder.Register(&cnpgv1.Backup{}, &cnpgv1.BackupList{})
93+
schemeBuilder.Register(&cnpgv1.ScheduledBackup{}, &cnpgv1.ScheduledBackupList{})
94+
utilruntime.Must(schemeBuilder.AddToScheme(result))
95+
96+
schemeLog := log.FromContext(ctx)
97+
schemeLog.Info("CNPG types registration", "schemeGroupVersion", schemeGroupVersion)
98+
99+
return result
100+
}

internal/cnpgi/operator/config/config.go

Lines changed: 1 addition & 10 deletions
Original file line numberDiff line numberDiff line change
@@ -5,7 +5,6 @@ import (
55

66
cnpgv1 "github.com/cloudnative-pg/cloudnative-pg/api/v1"
77
"github.com/cloudnative-pg/cnpg-i-machinery/pkg/pluginhelper/decoder"
8-
"k8s.io/apimachinery/pkg/runtime/schema"
98
"k8s.io/apimachinery/pkg/types"
109

1110
"github.com/cloudnative-pg/plugin-barman-cloud/internal/cnpgi/metadata"
@@ -101,19 +100,11 @@ func (config *PluginConfiguration) GetReferredBarmanObjectsKey() []types.Namespa
101100
return result
102101
}
103102

104-
func getClusterGVK() schema.GroupVersionKind {
105-
return schema.GroupVersionKind{
106-
Group: cnpgv1.SchemeGroupVersion.Group,
107-
Version: cnpgv1.SchemeGroupVersion.Version,
108-
Kind: cnpgv1.ClusterKind,
109-
}
110-
}
111-
112103
// NewFromClusterJSON decodes a JSON representation of a cluster.
113104
func NewFromClusterJSON(clusterJSON []byte) (*PluginConfiguration, error) {
114105
var result cnpgv1.Cluster
115106

116-
if err := decoder.DecodeObject(clusterJSON, &result, getClusterGVK()); err != nil {
107+
if err := decoder.DecodeObjectLenient(clusterJSON, &result); err != nil {
117108
return nil, err
118109
}
119110

internal/cnpgi/operator/lifecycle.go

Lines changed: 24 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -4,9 +4,9 @@ import (
44
"context"
55
"errors"
66
"fmt"
7+
"strings"
78

89
cnpgv1 "github.com/cloudnative-pg/cloudnative-pg/api/v1"
9-
"github.com/cloudnative-pg/cloudnative-pg/pkg/utils"
1010
"github.com/cloudnative-pg/cnpg-i-machinery/pkg/pluginhelper/decoder"
1111
"github.com/cloudnative-pg/cnpg-i-machinery/pkg/pluginhelper/object"
1212
"github.com/cloudnative-pg/cnpg-i/pkg/lifecycle"
@@ -77,10 +77,9 @@ func (impl LifecycleImplementation) LifecycleHook(
7777
}
7878

7979
var cluster cnpgv1.Cluster
80-
if err := decoder.DecodeObject(
80+
if err := decoder.DecodeObjectLenient(
8181
request.GetClusterDefinition(),
8282
&cluster,
83-
cnpgv1.SchemeGroupVersion.WithKind("Cluster"),
8483
); err != nil {
8584
return nil, err
8685
}
@@ -138,7 +137,7 @@ func reconcileJob(
138137
}
139138

140139
var job batchv1.Job
141-
if err := decoder.DecodeObject(
140+
if err := decoder.DecodeObjectStrict(
142141
request.GetObjectDefinition(),
143142
&job,
144143
batchv1.SchemeGroupVersion.WithKind("Job"),
@@ -151,7 +150,7 @@ func reconcileJob(
151150
WithValues("jobName", job.Name)
152151
contextLogger.Debug("starting job reconciliation")
153152

154-
if job.Spec.Template.Labels[utils.JobRoleLabelName] != "full-recovery" {
153+
if getCNPGJobRole(&job) != "full-recovery" {
155154
contextLogger.Debug("job is not a recovery job, skipping")
156155
return nil, nil
157156
}
@@ -270,6 +269,14 @@ func reconcilePodSpec(
270269
Name: "SPOOL_DIRECTORY",
271270
Value: "/controller/wal-restore-spool",
272271
},
272+
{
273+
Name: "CUSTOM_CNPG_GROUP",
274+
Value: cluster.GetObjectKind().GroupVersionKind().Group,
275+
},
276+
{
277+
Name: "CUSTOM_CNPG_VERSION",
278+
Value: cluster.GetObjectKind().GroupVersionKind().Version,
279+
},
273280
}
274281

275282
envs = append(envs, additionalEnvs...)
@@ -445,3 +452,15 @@ func volumeListHasVolume(volumes []corev1.Volume, name string) bool {
445452

446453
return false
447454
}
455+
456+
// getCNPGJobRole gets the role associated to a CNPG job
457+
func getCNPGJobRole(job *batchv1.Job) string {
458+
const jobRoleLabelSuffix = "/jobRole"
459+
for k, v := range job.Spec.Template.Labels {
460+
if strings.HasSuffix(k, jobRoleLabelSuffix) {
461+
return v
462+
}
463+
}
464+
465+
return ""
466+
}
Lines changed: 39 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,39 @@
1+
package operator
2+
3+
import (
4+
"fmt"
5+
6+
metav1 "k8s.io/apimachinery/pkg/apis/meta/v1"
7+
"k8s.io/apimachinery/pkg/runtime"
8+
"k8s.io/utils/ptr"
9+
)
10+
11+
// setOwnerReference explicitly set the owner reference between an
12+
// owner object and a controller one.
13+
//
14+
// Important: this function won't use any registered scheme and will
15+
// fail unless the metadata has been correctly set into the owner
16+
// object.
17+
func setOwnerReference(owner, controlled metav1.Object) error {
18+
ro, ok := owner.(runtime.Object)
19+
if !ok {
20+
return fmt.Errorf("%T is not a runtime.Object, cannot call setOwnerReference", owner)
21+
}
22+
23+
if len(ro.DeepCopyObject().GetObjectKind().GroupVersionKind().Group) == 0 {
24+
return fmt.Errorf("%T metadata have not been set, cannot call setOwnerReference", owner)
25+
}
26+
27+
controlled.SetOwnerReferences([]metav1.OwnerReference{
28+
{
29+
APIVersion: ro.GetObjectKind().GroupVersionKind().GroupVersion().String(),
30+
Kind: ro.GetObjectKind().GroupVersionKind().Kind,
31+
Name: owner.GetName(),
32+
UID: owner.GetUID(),
33+
BlockOwnerDeletion: ptr.To(true),
34+
Controller: ptr.To(true),
35+
},
36+
})
37+
38+
return nil
39+
}

internal/cnpgi/operator/reconciler.go

Lines changed: 4 additions & 9 deletions
Original file line numberDiff line numberDiff line change
@@ -11,7 +11,6 @@ import (
1111
rbacv1 "k8s.io/api/rbac/v1"
1212
"k8s.io/apimachinery/pkg/api/equality"
1313
apierrs "k8s.io/apimachinery/pkg/api/errors"
14-
ctrl "sigs.k8s.io/controller-runtime"
1514
"sigs.k8s.io/controller-runtime/pkg/client"
1615

1716
barmancloudv1 "github.com/cloudnative-pg/plugin-barman-cloud/api/v1"
@@ -61,10 +60,10 @@ func (r ReconcilerImplementation) Pre(
6160

6261
contextLogger.Debug("parsing cluster definition")
6362
var cluster cnpgv1.Cluster
64-
if err := decoder.DecodeObject(
63+
if err := decoder.DecodeObjectLenient(
6564
request.GetResourceDefinition(),
6665
&cluster,
67-
cnpgv1.SchemeGroupVersion.WithKind("Cluster")); err != nil {
66+
); err != nil {
6867
return nil, err
6968
}
7069

@@ -142,11 +141,7 @@ func (r ReconcilerImplementation) ensureRole(
142141
"namespace", newRole.Namespace,
143142
)
144143

145-
if err := ctrl.SetControllerReference(
146-
cluster,
147-
newRole,
148-
r.Client.Scheme(),
149-
); err != nil {
144+
if err := setOwnerReference(cluster, newRole); err != nil {
150145
return err
151146
}
152147

@@ -193,7 +188,7 @@ func (r ReconcilerImplementation) createRoleBinding(
193188
cluster *cnpgv1.Cluster,
194189
) error {
195190
roleBinding := specs.BuildRoleBinding(cluster)
196-
if err := ctrl.SetControllerReference(cluster, roleBinding, r.Client.Scheme()); err != nil {
191+
if err := setOwnerReference(cluster, roleBinding); err != nil {
197192
return err
198193
}
199194
return r.Client.Create(ctx, roleBinding)

0 commit comments

Comments
 (0)