mirror of
https://github.com/cloudnative-pg/plugin-barman-cloud.git
synced 2026-07-09 19:22:21 +02:00
Compare commits
2 Commits
9d938831ce
...
fca31a984c
| Author | SHA1 | Date | |
|---|---|---|---|
|
|
fca31a984c | ||
|
|
064864ba72 |
@ -102,8 +102,6 @@ func NewCmd() *cobra.Command {
|
||||
_ = viper.BindPFlag("server-address", cmd.Flags().Lookup("server-address"))
|
||||
|
||||
_ = viper.BindEnv("sidecar-image", "SIDECAR_IMAGE")
|
||||
_ = viper.BindEnv("custom-cnpg-group", "CUSTOM_CNPG_GROUP")
|
||||
_ = viper.BindEnv("custom-cnpg-version", "CUSTOM_CNPG_VERSION")
|
||||
|
||||
return cmd
|
||||
}
|
||||
|
||||
@ -57,8 +57,6 @@ func NewCmd() *cobra.Command {
|
||||
_ = viper.BindEnv("pod-name", "POD_NAME")
|
||||
_ = viper.BindEnv("pgdata", "PGDATA")
|
||||
_ = viper.BindEnv("spool-directory", "SPOOL_DIRECTORY")
|
||||
_ = viper.BindEnv("custom-cnpg-group", "CUSTOM_CNPG_GROUP")
|
||||
_ = viper.BindEnv("custom-cnpg-version", "CUSTOM_CNPG_VERSION")
|
||||
|
||||
return cmd
|
||||
}
|
||||
|
||||
@ -28,15 +28,16 @@ import (
|
||||
"github.com/spf13/viper"
|
||||
corev1 "k8s.io/api/core/v1"
|
||||
"k8s.io/apimachinery/pkg/runtime"
|
||||
"k8s.io/apimachinery/pkg/runtime/schema"
|
||||
"k8s.io/apimachinery/pkg/types"
|
||||
utilruntime "k8s.io/apimachinery/pkg/util/runtime"
|
||||
clientgoscheme "k8s.io/client-go/kubernetes/scheme"
|
||||
ctrl "sigs.k8s.io/controller-runtime"
|
||||
"sigs.k8s.io/controller-runtime/pkg/client"
|
||||
"sigs.k8s.io/controller-runtime/pkg/scheme"
|
||||
|
||||
barmancloudv1 "github.com/cloudnative-pg/plugin-barman-cloud/api/v1"
|
||||
extendedclient "github.com/cloudnative-pg/plugin-barman-cloud/internal/cnpgi/instance/internal/client"
|
||||
pluginscheme "github.com/cloudnative-pg/plugin-barman-cloud/internal/scheme"
|
||||
)
|
||||
|
||||
// Start starts the sidecar informers and CNPG-i server
|
||||
@ -126,7 +127,26 @@ func generateScheme(ctx context.Context) *runtime.Scheme {
|
||||
|
||||
utilruntime.Must(barmancloudv1.AddToScheme(result))
|
||||
utilruntime.Must(clientgoscheme.AddToScheme(result))
|
||||
pluginscheme.AddCNPGToScheme(ctx, result)
|
||||
|
||||
cnpgGroup := viper.GetString("custom-cnpg-group")
|
||||
cnpgVersion := viper.GetString("custom-cnpg-version")
|
||||
if len(cnpgGroup) == 0 {
|
||||
cnpgGroup = cnpgv1.SchemeGroupVersion.Group
|
||||
}
|
||||
if len(cnpgVersion) == 0 {
|
||||
cnpgVersion = cnpgv1.SchemeGroupVersion.Version
|
||||
}
|
||||
|
||||
// Proceed with custom registration of the CNPG scheme
|
||||
schemeGroupVersion := schema.GroupVersion{Group: cnpgGroup, Version: cnpgVersion}
|
||||
schemeBuilder := &scheme.Builder{GroupVersion: schemeGroupVersion}
|
||||
schemeBuilder.Register(&cnpgv1.Cluster{}, &cnpgv1.ClusterList{})
|
||||
schemeBuilder.Register(&cnpgv1.Backup{}, &cnpgv1.BackupList{})
|
||||
schemeBuilder.Register(&cnpgv1.ScheduledBackup{}, &cnpgv1.ScheduledBackupList{})
|
||||
utilruntime.Must(schemeBuilder.AddToScheme(result))
|
||||
|
||||
schemeLog := log.FromContext(ctx)
|
||||
schemeLog.Info("CNPG types registration", "schemeGroupVersion", schemeGroupVersion)
|
||||
|
||||
return result
|
||||
}
|
||||
|
||||
@ -24,6 +24,7 @@ import (
|
||||
"crypto/tls"
|
||||
|
||||
// +kubebuilder:scaffold:imports
|
||||
cnpgv1 "github.com/cloudnative-pg/cloudnative-pg/api/v1"
|
||||
"github.com/cloudnative-pg/machinery/pkg/log"
|
||||
"github.com/spf13/viper"
|
||||
"k8s.io/apimachinery/pkg/runtime"
|
||||
@ -37,33 +38,25 @@ import (
|
||||
|
||||
barmancloudv1 "github.com/cloudnative-pg/plugin-barman-cloud/api/v1"
|
||||
"github.com/cloudnative-pg/plugin-barman-cloud/internal/controller"
|
||||
pluginscheme "github.com/cloudnative-pg/plugin-barman-cloud/internal/scheme"
|
||||
|
||||
// Import all Kubernetes client auth plugins (e.g. Azure, GCP, OIDC, etc.)
|
||||
// to ensure that exec-entrypoint and run can make use of them.
|
||||
_ "k8s.io/client-go/plugin/pkg/client/auth"
|
||||
)
|
||||
|
||||
// generateScheme creates a runtime.Scheme with all type definitions
|
||||
// needed by the operator. CNPG types are registered under a
|
||||
// configurable API group to support custom CNPG-based operators.
|
||||
func generateScheme(ctx context.Context) *runtime.Scheme {
|
||||
result := runtime.NewScheme()
|
||||
var scheme = runtime.NewScheme()
|
||||
|
||||
utilruntime.Must(clientgoscheme.AddToScheme(result))
|
||||
utilruntime.Must(barmancloudv1.AddToScheme(result))
|
||||
pluginscheme.AddCNPGToScheme(ctx, result)
|
||||
func init() {
|
||||
utilruntime.Must(clientgoscheme.AddToScheme(scheme))
|
||||
utilruntime.Must(barmancloudv1.AddToScheme(scheme))
|
||||
utilruntime.Must(cnpgv1.AddToScheme(scheme))
|
||||
// +kubebuilder:scaffold:scheme
|
||||
|
||||
return result
|
||||
}
|
||||
|
||||
// Start starts the manager
|
||||
func Start(ctx context.Context) error {
|
||||
setupLog := log.FromContext(ctx)
|
||||
|
||||
scheme := generateScheme(ctx)
|
||||
|
||||
var tlsOpts []func(*tls.Config)
|
||||
|
||||
// if the enable-http2 flag is false (the default), http/2 should be disabled
|
||||
|
||||
58
internal/cnpgi/operator/ownership.go
Normal file
58
internal/cnpgi/operator/ownership.go
Normal file
@ -0,0 +1,58 @@
|
||||
/*
|
||||
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 operator
|
||||
|
||||
import (
|
||||
"fmt"
|
||||
|
||||
metav1 "k8s.io/apimachinery/pkg/apis/meta/v1"
|
||||
"k8s.io/apimachinery/pkg/runtime"
|
||||
"k8s.io/utils/ptr"
|
||||
)
|
||||
|
||||
// setOwnerReference explicitly set the owner reference between an
|
||||
// owner object and a controller one.
|
||||
//
|
||||
// Important: this function won't use any registered scheme and will
|
||||
// fail unless the metadata has been correctly set into the owner
|
||||
// object.
|
||||
func setOwnerReference(owner, controlled metav1.Object) error {
|
||||
ro, ok := owner.(runtime.Object)
|
||||
if !ok {
|
||||
return fmt.Errorf("%T is not a runtime.Object, cannot call setOwnerReference", owner)
|
||||
}
|
||||
|
||||
if len(ro.DeepCopyObject().GetObjectKind().GroupVersionKind().Group) == 0 {
|
||||
return fmt.Errorf("%T metadata have not been set, cannot call setOwnerReference", owner)
|
||||
}
|
||||
|
||||
controlled.SetOwnerReferences([]metav1.OwnerReference{
|
||||
{
|
||||
APIVersion: ro.GetObjectKind().GroupVersionKind().GroupVersion().String(),
|
||||
Kind: ro.GetObjectKind().GroupVersionKind().Kind,
|
||||
Name: owner.GetName(),
|
||||
UID: owner.GetUID(),
|
||||
BlockOwnerDeletion: ptr.To(true),
|
||||
Controller: ptr.To(true),
|
||||
},
|
||||
})
|
||||
|
||||
return nil
|
||||
}
|
||||
@ -30,129 +30,62 @@ import (
|
||||
"k8s.io/apimachinery/pkg/api/equality"
|
||||
apierrs "k8s.io/apimachinery/pkg/api/errors"
|
||||
"sigs.k8s.io/controller-runtime/pkg/client"
|
||||
"sigs.k8s.io/controller-runtime/pkg/controller/controllerutil"
|
||||
|
||||
barmancloudv1 "github.com/cloudnative-pg/plugin-barman-cloud/api/v1"
|
||||
"github.com/cloudnative-pg/plugin-barman-cloud/internal/cnpgi/operator/specs"
|
||||
)
|
||||
|
||||
// EnsureRole ensures the RBAC Role for the given Cluster matches
|
||||
// the desired state derived from the given ObjectStores. On creation,
|
||||
// the Cluster is set as the owner of the Role for garbage collection.
|
||||
//
|
||||
// This function is called from both the Pre hook (gRPC) and the
|
||||
// ObjectStore controller. To handle concurrent modifications
|
||||
// gracefully, AlreadyExists on Create and Conflict on Patch are
|
||||
// retried once rather than returned as errors.
|
||||
// the desired state derived from the given ObjectStores.
|
||||
// Optional beforeCreate callbacks are applied to the Role before creation
|
||||
// (e.g. to set owner references). They are not called on updates.
|
||||
func EnsureRole(
|
||||
ctx context.Context,
|
||||
c client.Client,
|
||||
cluster *cnpgv1.Cluster,
|
||||
barmanObjects []barmancloudv1.ObjectStore,
|
||||
beforeCreate ...func(*rbacv1.Role) error,
|
||||
) error {
|
||||
contextLogger := log.FromContext(ctx)
|
||||
newRole := specs.BuildRole(cluster, barmanObjects)
|
||||
|
||||
roleKey := client.ObjectKey{
|
||||
var role rbacv1.Role
|
||||
if err := c.Get(ctx, client.ObjectKey{
|
||||
Namespace: newRole.Namespace,
|
||||
Name: newRole.Name,
|
||||
}
|
||||
|
||||
var role rbacv1.Role
|
||||
err := c.Get(ctx, roleKey, &role)
|
||||
|
||||
switch {
|
||||
case apierrs.IsNotFound(err):
|
||||
role, err := createRole(ctx, c, cluster, newRole)
|
||||
if err != nil {
|
||||
}, &role); err != nil {
|
||||
if !apierrs.IsNotFound(err) {
|
||||
return err
|
||||
}
|
||||
if role == nil {
|
||||
// Created successfully, nothing else to do.
|
||||
return nil
|
||||
|
||||
contextLogger.Info(
|
||||
"Creating role",
|
||||
"name", newRole.Name,
|
||||
"namespace", newRole.Namespace,
|
||||
)
|
||||
|
||||
for _, fn := range beforeCreate {
|
||||
if err := fn(newRole); err != nil {
|
||||
return err
|
||||
}
|
||||
}
|
||||
// AlreadyExists: fall through to patch with the re-read role.
|
||||
return patchRoleRules(ctx, c, newRole.Rules, role)
|
||||
|
||||
case err != nil:
|
||||
return err
|
||||
|
||||
default:
|
||||
return patchRoleRules(ctx, c, newRole.Rules, &role)
|
||||
}
|
||||
}
|
||||
|
||||
// createRole attempts to create the Role. If another writer created
|
||||
// it concurrently (AlreadyExists), it re-reads and returns the
|
||||
// existing Role for the caller to patch. On success it returns nil.
|
||||
func createRole(
|
||||
ctx context.Context,
|
||||
c client.Client,
|
||||
cluster *cnpgv1.Cluster,
|
||||
newRole *rbacv1.Role,
|
||||
) (*rbacv1.Role, error) {
|
||||
contextLogger := log.FromContext(ctx)
|
||||
|
||||
if err := controllerutil.SetControllerReference(cluster, newRole, c.Scheme()); err != nil {
|
||||
return nil, err
|
||||
return c.Create(ctx, newRole)
|
||||
}
|
||||
|
||||
contextLogger.Info("Creating role",
|
||||
"name", newRole.Name, "namespace", newRole.Namespace)
|
||||
|
||||
createErr := c.Create(ctx, newRole)
|
||||
if createErr == nil {
|
||||
return nil, nil
|
||||
}
|
||||
if !apierrs.IsAlreadyExists(createErr) {
|
||||
return nil, createErr
|
||||
}
|
||||
|
||||
contextLogger.Info("Role was created concurrently, checking rules")
|
||||
|
||||
var role rbacv1.Role
|
||||
if err := c.Get(ctx, client.ObjectKeyFromObject(newRole), &role); err != nil {
|
||||
return nil, err
|
||||
}
|
||||
|
||||
return &role, nil
|
||||
}
|
||||
|
||||
// patchRoleRules patches the Role's rules if they differ from the
|
||||
// desired state. On Conflict (concurrent modification), it retries
|
||||
// once with a fresh read.
|
||||
func patchRoleRules(
|
||||
ctx context.Context,
|
||||
c client.Client,
|
||||
desiredRules []rbacv1.PolicyRule,
|
||||
role *rbacv1.Role,
|
||||
) error {
|
||||
if equality.Semantic.DeepEqual(desiredRules, role.Rules) {
|
||||
if equality.Semantic.DeepEqual(newRole.Rules, role.Rules) {
|
||||
return nil
|
||||
}
|
||||
|
||||
contextLogger := log.FromContext(ctx)
|
||||
contextLogger.Info("Patching role",
|
||||
"name", role.Name, "namespace", role.Namespace, "rules", desiredRules)
|
||||
contextLogger.Info(
|
||||
"Patching role",
|
||||
"name", newRole.Name,
|
||||
"namespace", newRole.Namespace,
|
||||
"rules", newRole.Rules,
|
||||
)
|
||||
|
||||
oldRole := role.DeepCopy()
|
||||
role.Rules = desiredRules
|
||||
role.Rules = newRole.Rules
|
||||
|
||||
patchErr := c.Patch(ctx, role, client.MergeFrom(oldRole))
|
||||
if patchErr == nil || !apierrs.IsConflict(patchErr) {
|
||||
return patchErr
|
||||
}
|
||||
|
||||
// Conflict: re-read and retry once.
|
||||
contextLogger.Info("Role was modified concurrently, retrying patch")
|
||||
if err := c.Get(ctx, client.ObjectKeyFromObject(role), role); err != nil {
|
||||
return err
|
||||
}
|
||||
if equality.Semantic.DeepEqual(desiredRules, role.Rules) {
|
||||
return nil
|
||||
}
|
||||
|
||||
oldRole = role.DeepCopy()
|
||||
role.Rules = desiredRules
|
||||
|
||||
return c.Patch(ctx, role, client.MergeFrom(oldRole))
|
||||
return c.Patch(ctx, &role, client.MergeFrom(oldRole))
|
||||
}
|
||||
|
||||
@ -21,12 +21,13 @@ package rbac_test
|
||||
|
||||
import (
|
||||
"context"
|
||||
"fmt"
|
||||
|
||||
barmanapi "github.com/cloudnative-pg/barman-cloud/pkg/api"
|
||||
cnpgv1 "github.com/cloudnative-pg/cloudnative-pg/api/v1"
|
||||
machineryapi "github.com/cloudnative-pg/machinery/pkg/api"
|
||||
. "github.com/onsi/ginkgo/v2"
|
||||
. "github.com/onsi/gomega"
|
||||
barmanapi "github.com/cloudnative-pg/barman-cloud/pkg/api"
|
||||
machineryapi "github.com/cloudnative-pg/machinery/pkg/api"
|
||||
rbacv1 "k8s.io/api/rbac/v1"
|
||||
metav1 "k8s.io/apimachinery/pkg/apis/meta/v1"
|
||||
"k8s.io/apimachinery/pkg/runtime"
|
||||
@ -80,9 +81,9 @@ func newObjectStore(name, namespace, secretName string) barmancloudv1.ObjectStor
|
||||
|
||||
var _ = Describe("EnsureRole", func() {
|
||||
var (
|
||||
ctx context.Context
|
||||
cluster *cnpgv1.Cluster
|
||||
objects []barmancloudv1.ObjectStore
|
||||
ctx context.Context
|
||||
cluster *cnpgv1.Cluster
|
||||
objects []barmancloudv1.ObjectStore
|
||||
fakeClient client.Client
|
||||
)
|
||||
|
||||
@ -99,7 +100,7 @@ var _ = Describe("EnsureRole", func() {
|
||||
fakeClient = fake.NewClientBuilder().WithScheme(newScheme()).Build()
|
||||
})
|
||||
|
||||
It("should create the Role with owner reference", func() {
|
||||
It("should create the Role", func() {
|
||||
err := rbac.EnsureRole(ctx, fakeClient, cluster, objects)
|
||||
Expect(err).NotTo(HaveOccurred())
|
||||
|
||||
@ -110,11 +111,32 @@ var _ = Describe("EnsureRole", func() {
|
||||
}, &role)
|
||||
Expect(err).NotTo(HaveOccurred())
|
||||
Expect(role.Rules).To(HaveLen(3))
|
||||
})
|
||||
|
||||
// Verify owner reference is set to the Cluster
|
||||
Expect(role.OwnerReferences).To(HaveLen(1))
|
||||
Expect(role.OwnerReferences[0].Name).To(Equal("test-cluster"))
|
||||
Expect(role.OwnerReferences[0].Kind).To(Equal("Cluster"))
|
||||
It("should apply beforeCreate callbacks", func() {
|
||||
called := false
|
||||
err := rbac.EnsureRole(ctx, fakeClient, cluster, objects, func(role *rbacv1.Role) error {
|
||||
called = true
|
||||
role.Labels = map[string]string{"owner": "test-cluster"}
|
||||
return nil
|
||||
})
|
||||
Expect(err).NotTo(HaveOccurred())
|
||||
Expect(called).To(BeTrue())
|
||||
|
||||
var role rbacv1.Role
|
||||
err = fakeClient.Get(ctx, client.ObjectKey{
|
||||
Namespace: "default",
|
||||
Name: "test-cluster-barman-cloud",
|
||||
}, &role)
|
||||
Expect(err).NotTo(HaveOccurred())
|
||||
Expect(role.Labels).To(HaveKeyWithValue("owner", "test-cluster"))
|
||||
})
|
||||
|
||||
It("should return error if beforeCreate callback fails", func() {
|
||||
err := rbac.EnsureRole(ctx, fakeClient, cluster, objects, func(_ *rbacv1.Role) error {
|
||||
return fmt.Errorf("callback error")
|
||||
})
|
||||
Expect(err).To(MatchError("callback error"))
|
||||
})
|
||||
})
|
||||
|
||||
@ -147,13 +169,15 @@ var _ = Describe("EnsureRole", func() {
|
||||
Context("when the Role exists with different rules", func() {
|
||||
BeforeEach(func() {
|
||||
fakeClient = fake.NewClientBuilder().WithScheme(newScheme()).Build()
|
||||
// Create with old secret
|
||||
oldObjects := []barmancloudv1.ObjectStore{
|
||||
newObjectStore("my-store", "default", "old-secret"),
|
||||
}
|
||||
Expect(rbac.EnsureRole(ctx, fakeClient, cluster, oldObjects)).To(Succeed())
|
||||
})
|
||||
|
||||
It("should patch the Role with new rules and preserve owner reference", func() {
|
||||
It("should patch the Role with new rules", func() {
|
||||
// Now call with new secret name
|
||||
err := rbac.EnsureRole(ctx, fakeClient, cluster, objects)
|
||||
Expect(err).NotTo(HaveOccurred())
|
||||
|
||||
@ -163,13 +187,20 @@ var _ = Describe("EnsureRole", func() {
|
||||
Name: "test-cluster-barman-cloud",
|
||||
}, &role)).To(Succeed())
|
||||
|
||||
// The secrets rule should reference the new secret
|
||||
secretsRule := role.Rules[2]
|
||||
Expect(secretsRule.ResourceNames).To(ContainElement("aws-creds"))
|
||||
Expect(secretsRule.ResourceNames).NotTo(ContainElement("old-secret"))
|
||||
})
|
||||
|
||||
// Owner reference must survive the patch
|
||||
Expect(role.OwnerReferences).To(HaveLen(1))
|
||||
Expect(role.OwnerReferences[0].Name).To(Equal("test-cluster"))
|
||||
It("should not call beforeCreate callbacks on update", func() {
|
||||
called := false
|
||||
err := rbac.EnsureRole(ctx, fakeClient, cluster, objects, func(_ *rbacv1.Role) error {
|
||||
called = true
|
||||
return nil
|
||||
})
|
||||
Expect(err).NotTo(HaveOccurred())
|
||||
Expect(called).To(BeFalse())
|
||||
})
|
||||
})
|
||||
})
|
||||
|
||||
@ -30,7 +30,6 @@ import (
|
||||
rbacv1 "k8s.io/api/rbac/v1"
|
||||
apierrs "k8s.io/apimachinery/pkg/api/errors"
|
||||
"sigs.k8s.io/controller-runtime/pkg/client"
|
||||
"sigs.k8s.io/controller-runtime/pkg/controller/controllerutil"
|
||||
|
||||
barmancloudv1 "github.com/cloudnative-pg/plugin-barman-cloud/api/v1"
|
||||
"github.com/cloudnative-pg/plugin-barman-cloud/internal/cnpgi/operator/config"
|
||||
@ -114,7 +113,9 @@ func (r ReconcilerImplementation) Pre(
|
||||
barmanObjects = append(barmanObjects, barmanObject)
|
||||
}
|
||||
|
||||
if err := rbac.EnsureRole(ctx, r.Client, &cluster, barmanObjects); err != nil {
|
||||
if err := rbac.EnsureRole(ctx, r.Client, &cluster, barmanObjects, func(role *rbacv1.Role) error {
|
||||
return setOwnerReference(&cluster, role)
|
||||
}); err != nil {
|
||||
return nil, err
|
||||
}
|
||||
|
||||
@ -163,7 +164,7 @@ func (r ReconcilerImplementation) createRoleBinding(
|
||||
cluster *cnpgv1.Cluster,
|
||||
) error {
|
||||
roleBinding := specs.BuildRoleBinding(cluster)
|
||||
if err := controllerutil.SetControllerReference(cluster, roleBinding, r.Client.Scheme()); err != nil {
|
||||
if err := setOwnerReference(cluster, roleBinding); err != nil {
|
||||
return err
|
||||
}
|
||||
return r.Client.Create(ctx, roleBinding)
|
||||
|
||||
@ -22,6 +22,7 @@ package restore
|
||||
import (
|
||||
"context"
|
||||
|
||||
cnpgv1 "github.com/cloudnative-pg/cloudnative-pg/api/v1"
|
||||
"github.com/cloudnative-pg/machinery/pkg/log"
|
||||
"github.com/spf13/viper"
|
||||
corev1 "k8s.io/api/core/v1"
|
||||
@ -32,20 +33,14 @@ import (
|
||||
"sigs.k8s.io/controller-runtime/pkg/client"
|
||||
|
||||
barmancloudv1 "github.com/cloudnative-pg/plugin-barman-cloud/api/v1"
|
||||
pluginscheme "github.com/cloudnative-pg/plugin-barman-cloud/internal/scheme"
|
||||
)
|
||||
|
||||
// generateScheme creates a runtime.Scheme with all type definitions
|
||||
// needed by the restore sidecar. CNPG types are registered under a
|
||||
// configurable API group to support custom CNPG-based operators.
|
||||
func generateScheme(ctx context.Context) *runtime.Scheme {
|
||||
result := runtime.NewScheme()
|
||||
var scheme = runtime.NewScheme()
|
||||
|
||||
utilruntime.Must(barmancloudv1.AddToScheme(result))
|
||||
utilruntime.Must(clientgoscheme.AddToScheme(result))
|
||||
pluginscheme.AddCNPGToScheme(ctx, result)
|
||||
|
||||
return result
|
||||
func init() {
|
||||
utilruntime.Must(barmancloudv1.AddToScheme(scheme))
|
||||
utilruntime.Must(cnpgv1.AddToScheme(scheme))
|
||||
utilruntime.Must(clientgoscheme.AddToScheme(scheme))
|
||||
}
|
||||
|
||||
// Start starts the sidecar informers and CNPG-i server
|
||||
@ -53,8 +48,6 @@ func Start(ctx context.Context) error {
|
||||
setupLog := log.FromContext(ctx)
|
||||
setupLog.Info("Starting barman cloud instance plugin")
|
||||
|
||||
scheme := generateScheme(ctx)
|
||||
|
||||
mgr, err := ctrl.NewManager(ctrl.GetConfigOrDie(), ctrl.Options{
|
||||
Scheme: scheme,
|
||||
Client: client.Options{
|
||||
|
||||
@ -25,11 +25,13 @@ import (
|
||||
|
||||
cnpgv1 "github.com/cloudnative-pg/cloudnative-pg/api/v1"
|
||||
"github.com/cloudnative-pg/machinery/pkg/log"
|
||||
rbacv1 "k8s.io/api/rbac/v1"
|
||||
apierrs "k8s.io/apimachinery/pkg/api/errors"
|
||||
"k8s.io/apimachinery/pkg/runtime"
|
||||
ctrl "sigs.k8s.io/controller-runtime"
|
||||
"sigs.k8s.io/controller-runtime/pkg/builder"
|
||||
"sigs.k8s.io/controller-runtime/pkg/client"
|
||||
"sigs.k8s.io/controller-runtime/pkg/controller/controllerutil"
|
||||
"sigs.k8s.io/controller-runtime/pkg/predicate"
|
||||
|
||||
barmancloudv1 "github.com/cloudnative-pg/plugin-barman-cloud/api/v1"
|
||||
@ -115,7 +117,9 @@ func (r *ObjectStoreReconciler) reconcileRBACForCluster(
|
||||
barmanObjects = append(barmanObjects, barmanObject)
|
||||
}
|
||||
|
||||
return rbac.EnsureRole(ctx, r.Client, cluster, barmanObjects)
|
||||
return rbac.EnsureRole(ctx, r.Client, cluster, barmanObjects, func(role *rbacv1.Role) error {
|
||||
return controllerutil.SetControllerReference(cluster, role, r.Scheme)
|
||||
})
|
||||
}
|
||||
|
||||
// referencesObjectStore checks if the given ObjectStore is in the list
|
||||
|
||||
@ -20,14 +20,81 @@ SPDX-License-Identifier: Apache-2.0
|
||||
package controller
|
||||
|
||||
import (
|
||||
"context"
|
||||
"fmt"
|
||||
"path/filepath"
|
||||
"runtime"
|
||||
"testing"
|
||||
|
||||
// +kubebuilder:scaffold:imports
|
||||
"k8s.io/client-go/kubernetes/scheme"
|
||||
"k8s.io/client-go/rest"
|
||||
"sigs.k8s.io/controller-runtime/pkg/client"
|
||||
"sigs.k8s.io/controller-runtime/pkg/envtest"
|
||||
logf "sigs.k8s.io/controller-runtime/pkg/log"
|
||||
"sigs.k8s.io/controller-runtime/pkg/log/zap"
|
||||
|
||||
barmancloudv1 "github.com/cloudnative-pg/plugin-barman-cloud/api/v1"
|
||||
|
||||
. "github.com/onsi/ginkgo/v2"
|
||||
. "github.com/onsi/gomega"
|
||||
)
|
||||
|
||||
// These tests use Ginkgo (BDD-style Go testing framework). Refer to
|
||||
// http://onsi.github.io/ginkgo/ to learn more about Ginkgo.
|
||||
|
||||
var (
|
||||
cfg *rest.Config
|
||||
k8sClient client.Client
|
||||
testEnv *envtest.Environment
|
||||
ctx context.Context
|
||||
cancel context.CancelFunc
|
||||
)
|
||||
|
||||
func TestControllers(t *testing.T) {
|
||||
RegisterFailHandler(Fail)
|
||||
|
||||
RunSpecs(t, "Controller Suite")
|
||||
}
|
||||
|
||||
var _ = BeforeSuite(func() {
|
||||
logf.SetLogger(zap.New(zap.WriteTo(GinkgoWriter), zap.UseDevMode(true)))
|
||||
|
||||
ctx, cancel = context.WithCancel(context.TODO())
|
||||
|
||||
By("bootstrapping test environment")
|
||||
testEnv = &envtest.Environment{
|
||||
CRDDirectoryPaths: []string{filepath.Join("..", "..", "config", "crd", "bases")},
|
||||
ErrorIfCRDPathMissing: true,
|
||||
|
||||
// The BinaryAssetsDirectory is only required if you want to run the tests directly
|
||||
// without call the makefile target test. If not informed it will look for the
|
||||
// default path defined in controller-runtime which is /usr/local/kubebuilder/.
|
||||
// Note that you must have the required binaries setup under the bin directory to perform
|
||||
// the tests directly. When we run make test it will be setup and used automatically.
|
||||
BinaryAssetsDirectory: filepath.Join("..", "..", "bin", "k8s",
|
||||
fmt.Sprintf("1.31.0-%s-%s", runtime.GOOS, runtime.GOARCH)),
|
||||
}
|
||||
|
||||
var err error
|
||||
// cfg is defined in this file globally.
|
||||
cfg, err = testEnv.Start()
|
||||
Expect(err).NotTo(HaveOccurred())
|
||||
Expect(cfg).NotTo(BeNil())
|
||||
|
||||
err = barmancloudv1.AddToScheme(scheme.Scheme)
|
||||
Expect(err).NotTo(HaveOccurred())
|
||||
|
||||
// +kubebuilder:scaffold:scheme
|
||||
|
||||
k8sClient, err = client.New(cfg, client.Options{Scheme: scheme.Scheme})
|
||||
Expect(err).NotTo(HaveOccurred())
|
||||
Expect(k8sClient).NotTo(BeNil())
|
||||
})
|
||||
|
||||
var _ = AfterSuite(func() {
|
||||
By("tearing down the test environment")
|
||||
cancel()
|
||||
err := testEnv.Stop()
|
||||
Expect(err).NotTo(HaveOccurred())
|
||||
})
|
||||
|
||||
@ -1,58 +0,0 @@
|
||||
/*
|
||||
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 scheme provides utilities for building runtime schemes
|
||||
// with support for custom CNPG API groups.
|
||||
package scheme
|
||||
|
||||
import (
|
||||
"context"
|
||||
|
||||
cnpgv1 "github.com/cloudnative-pg/cloudnative-pg/api/v1"
|
||||
"github.com/cloudnative-pg/machinery/pkg/log"
|
||||
"github.com/spf13/viper"
|
||||
"k8s.io/apimachinery/pkg/runtime"
|
||||
"k8s.io/apimachinery/pkg/runtime/schema"
|
||||
utilruntime "k8s.io/apimachinery/pkg/util/runtime"
|
||||
crscheme "sigs.k8s.io/controller-runtime/pkg/scheme"
|
||||
)
|
||||
|
||||
// AddCNPGToScheme registers CNPG types into the given scheme using
|
||||
// the API group configured via CUSTOM_CNPG_GROUP/CUSTOM_CNPG_VERSION
|
||||
// environment variables, defaulting to postgresql.cnpg.io/v1.
|
||||
// This allows the plugin to work with any CNPG-based operator.
|
||||
func AddCNPGToScheme(ctx context.Context, s *runtime.Scheme) {
|
||||
cnpgGroup := viper.GetString("custom-cnpg-group")
|
||||
cnpgVersion := viper.GetString("custom-cnpg-version")
|
||||
if len(cnpgGroup) == 0 {
|
||||
cnpgGroup = cnpgv1.SchemeGroupVersion.Group
|
||||
}
|
||||
if len(cnpgVersion) == 0 {
|
||||
cnpgVersion = cnpgv1.SchemeGroupVersion.Version
|
||||
}
|
||||
|
||||
schemeGroupVersion := schema.GroupVersion{Group: cnpgGroup, Version: cnpgVersion}
|
||||
schemeBuilder := &crscheme.Builder{GroupVersion: schemeGroupVersion}
|
||||
schemeBuilder.Register(&cnpgv1.Cluster{}, &cnpgv1.ClusterList{})
|
||||
schemeBuilder.Register(&cnpgv1.Backup{}, &cnpgv1.BackupList{})
|
||||
schemeBuilder.Register(&cnpgv1.ScheduledBackup{}, &cnpgv1.ScheduledBackupList{})
|
||||
utilruntime.Must(schemeBuilder.AddToScheme(s))
|
||||
|
||||
log.FromContext(ctx).Info("CNPG types registration", "schemeGroupVersion", schemeGroupVersion)
|
||||
}
|
||||
@ -870,7 +870,6 @@ rules:
|
||||
- postgresql.cnpg.io
|
||||
resources:
|
||||
- backups
|
||||
- clusters
|
||||
verbs:
|
||||
- get
|
||||
- list
|
||||
|
||||
Loading…
Reference in New Issue
Block a user