Skip to content

Commit ace695d

Browse files
committed
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 0872cf2 commit ace695d

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"
@@ -79,10 +79,9 @@ func (impl LifecycleImplementation) LifecycleHook(
7979
}
8080

8181
var cluster cnpgv1.Cluster
82-
if err := decoder.DecodeObject(
82+
if err := decoder.DecodeObjectLenient(
8383
request.GetClusterDefinition(),
8484
&cluster,
85-
cnpgv1.SchemeGroupVersion.WithKind("Cluster"),
8685
); err != nil {
8786
return nil, err
8887
}
@@ -184,7 +183,7 @@ func reconcileJob(
184183
}
185184

186185
var job batchv1.Job
187-
if err := decoder.DecodeObject(
186+
if err := decoder.DecodeObjectStrict(
188187
request.GetObjectDefinition(),
189188
&job,
190189
batchv1.SchemeGroupVersion.WithKind("Job"),
@@ -197,7 +196,7 @@ func reconcileJob(
197196
WithValues("jobName", job.Name)
198197
contextLogger.Debug("starting job reconciliation")
199198

200-
if job.Spec.Template.Labels[utils.JobRoleLabelName] != "full-recovery" {
199+
if getCNPGJobRole(&job) != "full-recovery" {
201200
contextLogger.Debug("job is not a recovery job, skipping")
202201
return nil, nil
203202
}
@@ -307,6 +306,14 @@ func reconcilePodSpec(
307306
Name: "SPOOL_DIRECTORY",
308307
Value: "/controller/wal-restore-spool",
309308
},
309+
{
310+
Name: "CUSTOM_CNPG_GROUP",
311+
Value: cluster.GetObjectKind().GroupVersionKind().Group,
312+
},
313+
{
314+
Name: "CUSTOM_CNPG_VERSION",
315+
Value: cluster.GetObjectKind().GroupVersionKind().Version,
316+
},
310317
}
311318

312319
envs = append(envs, additionalEnvs...)
@@ -455,3 +462,15 @@ func InjectPluginSidecarPodSpec(
455462

456463
return nil
457464
}
465+
466+
// getCNPGJobRole gets the role associated to a CNPG job
467+
func getCNPGJobRole(job *batchv1.Job) string {
468+
const jobRoleLabelSuffix = "/jobRole"
469+
for k, v := range job.Spec.Template.Labels {
470+
if strings.HasSuffix(k, jobRoleLabelSuffix) {
471+
return v
472+
}
473+
}
474+
475+
return ""
476+
}
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)