Skip to content

Commit 13e3fab

Browse files
leonardocemnencia
andauthored
feat: lenient decoding of CNPG resources (#192)
This patch enables the barman-cloud plugin to function with an operator that is structurally identical to CNPG but works with a different API group. It achieves this through lenient decoding of the provided CNPG resources and injecting the detected GVK into the sidecar, enabling it to correctly encode and decode the Kubernetes resources. Signed-off-by: Leonardo Cecchi <[email protected]> Signed-off-by: Marco Nenciarini <[email protected]> Co-authored-by: Marco Nenciarini <[email protected]>
1 parent fcbc472 commit 13e3fab

File tree

8 files changed

+109
-35
lines changed

8 files changed

+109
-35
lines changed

go.mod

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -10,7 +10,7 @@ require (
1010
github.com/cloudnative-pg/barman-cloud v0.2.0
1111
github.com/cloudnative-pg/cloudnative-pg v1.25.1
1212
github.com/cloudnative-pg/cnpg-i v0.1.0
13-
github.com/cloudnative-pg/cnpg-i-machinery v0.1.2
13+
github.com/cloudnative-pg/cnpg-i-machinery v0.2.0
1414
github.com/cloudnative-pg/machinery v0.1.0
1515
github.com/onsi/ginkgo/v2 v2.23.0
1616
github.com/onsi/gomega v1.36.2

go.sum

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -26,8 +26,8 @@ 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=
29+
github.com/cloudnative-pg/cnpg-i-machinery v0.2.0 h1:htNuKirdAOYrc7Hu5mLDoOES+nKSyPaXNDLgbV5dLSI=
30+
github.com/cloudnative-pg/cnpg-i-machinery v0.2.0/go.mod h1:MHVxMMbLeCRnEM8PLWW4C2CsHqOeAU2OsrwWMKy3tPA=
3131
github.com/cloudnative-pg/machinery v0.1.0 h1:tjRmsqQmsO/OlaT0uFmkEtVqgr+SGPM88cKZOHYKLBo=
3232
github.com/cloudnative-pg/machinery v0.1.0/go.mod h1:0V3vm44FaIsY+x4pm8ORry7xCC3AJiO+ebfPNxeP5Ck=
3333
github.com/cpuguy83/go-md2man/v2 v2.0.6/go.mod h1:oOW0eioCTA6cOiMLiUPZOpcVxMig6NIQQ7OS05n1F4g=

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)