mirror of
https://github.com/cloudnative-pg/plugin-barman-cloud.git
synced 2026-01-11 13:23:09 +01:00
213 lines
5.2 KiB
Go
213 lines
5.2 KiB
Go
package operator
|
|
|
|
import (
|
|
"context"
|
|
"fmt"
|
|
|
|
cnpgv1 "github.com/cloudnative-pg/cloudnative-pg/api/v1"
|
|
"github.com/cloudnative-pg/cnpg-i-machinery/pkg/pluginhelper/decoder"
|
|
"github.com/cloudnative-pg/cnpg-i-machinery/pkg/pluginhelper/object"
|
|
"github.com/cloudnative-pg/cnpg-i/pkg/reconciler"
|
|
rbacv1 "k8s.io/api/rbac/v1"
|
|
apierrs "k8s.io/apimachinery/pkg/api/errors"
|
|
metav1 "k8s.io/apimachinery/pkg/apis/meta/v1"
|
|
ctrl "sigs.k8s.io/controller-runtime"
|
|
"sigs.k8s.io/controller-runtime/pkg/client"
|
|
|
|
"github.com/cloudnative-pg/plugin-barman-cloud/internal/cnpgi/operator/config"
|
|
)
|
|
|
|
// ReconcilerImplementation implements the Reconciler capability
|
|
type ReconcilerImplementation struct {
|
|
Client client.Client
|
|
reconciler.UnimplementedReconcilerHooksServer
|
|
}
|
|
|
|
// GetCapabilities implements the Reconciler interface
|
|
func (r ReconcilerImplementation) GetCapabilities(
|
|
_ context.Context,
|
|
_ *reconciler.ReconcilerHooksCapabilitiesRequest,
|
|
) (*reconciler.ReconcilerHooksCapabilitiesResult, error) {
|
|
return &reconciler.ReconcilerHooksCapabilitiesResult{
|
|
ReconcilerCapabilities: []*reconciler.ReconcilerHooksCapability{
|
|
{
|
|
Kind: reconciler.ReconcilerHooksCapability_KIND_CLUSTER,
|
|
},
|
|
{
|
|
Kind: reconciler.ReconcilerHooksCapability_KIND_BACKUP,
|
|
},
|
|
},
|
|
}, nil
|
|
}
|
|
|
|
// Pre implements the reconciler interface
|
|
func (r ReconcilerImplementation) Pre(
|
|
ctx context.Context,
|
|
request *reconciler.ReconcilerHooksRequest,
|
|
) (*reconciler.ReconcilerHooksResult, error) {
|
|
reconciledKind, err := object.GetKind(request.GetResourceDefinition())
|
|
if err != nil {
|
|
return nil, err
|
|
}
|
|
if reconciledKind != "Cluster" {
|
|
return &reconciler.ReconcilerHooksResult{
|
|
Behavior: reconciler.ReconcilerHooksResult_BEHAVIOR_CONTINUE,
|
|
}, nil
|
|
}
|
|
|
|
cluster, err := decoder.DecodeClusterJSON(request.GetResourceDefinition())
|
|
if err != nil {
|
|
return nil, err
|
|
}
|
|
|
|
pluginConfiguration, err := config.NewFromCluster(cluster)
|
|
if err != nil {
|
|
return nil, err
|
|
}
|
|
|
|
if err := r.ensureRole(ctx, cluster, pluginConfiguration.BarmanObjectName); err != nil {
|
|
return nil, err
|
|
}
|
|
|
|
if err := r.ensureRoleBinding(ctx, cluster); err != nil {
|
|
return nil, err
|
|
}
|
|
|
|
return &reconciler.ReconcilerHooksResult{
|
|
Behavior: reconciler.ReconcilerHooksResult_BEHAVIOR_CONTINUE,
|
|
}, nil
|
|
}
|
|
|
|
// Post implements the reconciler interface
|
|
func (r ReconcilerImplementation) Post(
|
|
_ context.Context,
|
|
_ *reconciler.ReconcilerHooksRequest,
|
|
) (*reconciler.ReconcilerHooksResult, error) {
|
|
return &reconciler.ReconcilerHooksResult{
|
|
Behavior: reconciler.ReconcilerHooksResult_BEHAVIOR_CONTINUE,
|
|
}, nil
|
|
}
|
|
|
|
func (r ReconcilerImplementation) ensureRole(
|
|
ctx context.Context,
|
|
cluster *cnpgv1.Cluster,
|
|
barmanObjectName string,
|
|
) error {
|
|
var role rbacv1.Role
|
|
if err := r.Client.Get(ctx, client.ObjectKey{
|
|
Namespace: cluster.Namespace,
|
|
Name: getRBACName(cluster.Name),
|
|
}, &role); err != nil {
|
|
if apierrs.IsNotFound(err) {
|
|
return r.createRole(ctx, cluster, barmanObjectName)
|
|
}
|
|
return err
|
|
}
|
|
|
|
// TODO: patch existing role
|
|
return nil
|
|
}
|
|
|
|
func (r ReconcilerImplementation) ensureRoleBinding(
|
|
ctx context.Context,
|
|
cluster *cnpgv1.Cluster,
|
|
) error {
|
|
var role rbacv1.RoleBinding
|
|
if err := r.Client.Get(ctx, client.ObjectKey{
|
|
Namespace: cluster.Namespace,
|
|
Name: getRBACName(cluster.Name),
|
|
}, &role); err != nil {
|
|
if apierrs.IsNotFound(err) {
|
|
return r.createRoleBinding(ctx, cluster)
|
|
}
|
|
return err
|
|
}
|
|
|
|
// TODO: patch existing role binding
|
|
return nil
|
|
}
|
|
|
|
func (r ReconcilerImplementation) createRole(
|
|
ctx context.Context,
|
|
cluster *cnpgv1.Cluster,
|
|
barmanObjectName string,
|
|
) error {
|
|
role := buildRole(cluster, barmanObjectName)
|
|
if err := ctrl.SetControllerReference(cluster, role, r.Client.Scheme()); err != nil {
|
|
return err
|
|
}
|
|
return r.Client.Create(ctx, role)
|
|
}
|
|
|
|
func (r ReconcilerImplementation) createRoleBinding(
|
|
ctx context.Context,
|
|
cluster *cnpgv1.Cluster,
|
|
) error {
|
|
roleBinding := buildRoleBinding(cluster)
|
|
if err := ctrl.SetControllerReference(cluster, roleBinding, r.Client.Scheme()); err != nil {
|
|
return err
|
|
}
|
|
return r.Client.Create(ctx, roleBinding)
|
|
}
|
|
|
|
func buildRole(
|
|
cluster *cnpgv1.Cluster,
|
|
barmanObjectName string,
|
|
) *rbacv1.Role {
|
|
return &rbacv1.Role{
|
|
ObjectMeta: metav1.ObjectMeta{
|
|
Namespace: cluster.Namespace,
|
|
Name: getRBACName(cluster.Name),
|
|
},
|
|
|
|
Rules: []rbacv1.PolicyRule{
|
|
{
|
|
APIGroups: []string{
|
|
"barmancloud.cnpg.io",
|
|
},
|
|
Verbs: []string{
|
|
"get",
|
|
"watch",
|
|
"list",
|
|
},
|
|
Resources: []string{
|
|
"objectstores",
|
|
},
|
|
ResourceNames: []string{
|
|
barmanObjectName,
|
|
},
|
|
},
|
|
},
|
|
}
|
|
}
|
|
|
|
func buildRoleBinding(
|
|
cluster *cnpgv1.Cluster,
|
|
) *rbacv1.RoleBinding {
|
|
return &rbacv1.RoleBinding{
|
|
ObjectMeta: metav1.ObjectMeta{
|
|
Namespace: cluster.Namespace,
|
|
Name: getRBACName(cluster.Name),
|
|
},
|
|
Subjects: []rbacv1.Subject{
|
|
{
|
|
Kind: "ServiceAccount",
|
|
APIGroup: "",
|
|
Name: cluster.Name,
|
|
Namespace: cluster.Namespace,
|
|
},
|
|
},
|
|
RoleRef: rbacv1.RoleRef{
|
|
APIGroup: "rbac.authorization.k8s.io",
|
|
Kind: "Role",
|
|
Name: getRBACName(cluster.Name),
|
|
},
|
|
}
|
|
}
|
|
|
|
// getRBACName returns the name of the RBAC entities for the
|
|
// barman cloud plugin
|
|
func getRBACName(clusterName string) string {
|
|
return fmt.Sprintf("%s-barman", clusterName)
|
|
}
|