controllers/gerritprojectaccess/controller.go (141 lines of code) (raw):
package gerritprojectaccess
import (
"context"
"fmt"
"reflect"
"time"
"github.com/go-logr/logr"
"github.com/pkg/errors"
k8sErrors "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/event"
"sigs.k8s.io/controller-runtime/pkg/predicate"
"sigs.k8s.io/controller-runtime/pkg/reconcile"
gerritApi "github.com/epam/edp-gerrit-operator/v2/api/v1"
"github.com/epam/edp-gerrit-operator/v2/controllers/helper"
gerritClient "github.com/epam/edp-gerrit-operator/v2/pkg/client/gerrit"
"github.com/epam/edp-gerrit-operator/v2/pkg/service/gerrit"
"github.com/epam/edp-gerrit-operator/v2/pkg/service/platform"
)
const (
finalizerName = "gerritprojectaccess.gerrit.finalizer.name"
requeueTime = 10 * time.Second
)
type Reconcile struct {
client client.Client
service gerrit.Interface
log logr.Logger
}
func NewReconcile(k8sClient client.Client, scheme *runtime.Scheme, log logr.Logger) (helper.Controller, error) {
ps, err := platform.NewService(helper.GetPlatformTypeEnv(), scheme)
if err != nil {
return nil, errors.Wrap(err, "unable to create platform service")
}
return &Reconcile{
client: k8sClient,
service: gerrit.NewComponentService(ps, k8sClient, scheme),
log: log.WithName("gerrit"),
}, nil
}
func (r *Reconcile) SetupWithManager(mgr ctrl.Manager) error {
pred := predicate.Funcs{
UpdateFunc: isSpecUpdated,
}
err := ctrl.NewControllerManagedBy(mgr).
For(&gerritApi.GerritProjectAccess{}, builder.WithPredicates(pred)).
Complete(r)
if err != nil {
return fmt.Errorf("failed to setup GerritProjectAccess controller: %w", err)
}
return nil
}
func isSpecUpdated(e event.UpdateEvent) bool {
oo, ok := e.ObjectOld.(*gerritApi.GerritProjectAccess)
if !ok {
return false
}
no, ok := e.ObjectNew.(*gerritApi.GerritProjectAccess)
if !ok {
return false
}
return !reflect.DeepEqual(oo.Spec, no.Spec) ||
(oo.GetDeletionTimestamp().IsZero() && !no.GetDeletionTimestamp().IsZero())
}
//+kubebuilder:rbac:groups=v2.edp.epam.com,namespace=placeholder,resources=gerritprojectaccesses,verbs=get;list;watch;create;update;patch;delete
//+kubebuilder:rbac:groups=v2.edp.epam.com,namespace=placeholder,resources=gerritprojectaccesses/status,verbs=get;update;patch
//+kubebuilder:rbac:groups=v2.edp.epam.com,namespace=placeholder,resources=gerritprojectaccesses/finalizers,verbs=update
func (r *Reconcile) Reconcile(ctx context.Context, request reconcile.Request) (result reconcile.Result, resError error) {
reqLogger := r.log.WithValues("Request.Namespace", request.Namespace, "Request.Name", request.Name)
reqLogger.V(2).Info("Reconciling GerritProjectAccess has been started")
var instance gerritApi.GerritProjectAccess
if err := r.client.Get(context.TODO(), request.NamespacedName, &instance); err != nil {
if k8sErrors.IsNotFound(err) {
return
}
return reconcile.Result{}, errors.Wrap(err, "unable to get GerritProjectAccess instance")
}
defer func() {
if err := r.client.Status().Update(context.Background(), &instance); err != nil {
reqLogger.Error(err, "unable to update instance status")
}
}()
if err := r.tryToReconcile(ctx, &instance); err != nil {
reqLogger.Error(err, "unable to reconcile GerritProjectAccess")
instance.Status.Value = err.Error()
return reconcile.Result{RequeueAfter: requeueTime}, nil
}
instance.Status.Value = helper.StatusOK
instance.Status.Created = true
return
}
func prepareAccessInfo(references []gerritApi.Reference) []gerritClient.AccessInfo {
ai := make([]gerritClient.AccessInfo, 0, len(references))
for _, ref := range references {
ai = append(ai, gerritClient.AccessInfo{
Action: ref.Action,
Force: ref.Force,
GroupName: ref.GroupName,
Max: ref.Max,
Min: ref.Min,
RefPattern: ref.Pattern,
PermissionLabel: ref.PermissionLabel,
PermissionName: ref.PermissionName,
})
}
return ai
}
func (r *Reconcile) tryToReconcile(ctx context.Context, instance *gerritApi.GerritProjectAccess) error {
cl, err := helper.GetGerritClient(ctx, r.client, instance, instance.Spec.OwnerName, r.service)
if err != nil {
return errors.Wrap(err, "unable to init gerrit client")
}
if len(instance.Spec.References) > 0 && !instance.Status.Created {
if err := cl.AddAccessRights(instance.Spec.ProjectName, prepareAccessInfo(instance.Spec.References)); err != nil {
return errors.Wrap(err, "unable to add access rights")
}
} else if len(instance.Spec.References) > 0 {
if err := cl.UpdateAccessRights(instance.Spec.ProjectName, prepareAccessInfo(instance.Spec.References)); err != nil {
return errors.Wrap(err, "unable to update access rights")
}
}
if instance.Spec.Parent != "" {
if err := cl.SetProjectParent(instance.Spec.ProjectName, instance.Spec.Parent); err != nil {
return errors.Wrap(err, "unable to set project parent")
}
}
if err := helper.TryToDelete(ctx, r.client, instance, finalizerName,
r.makeDeletionFunc(cl, instance.Spec.ProjectName, instance.Spec.References)); err != nil {
return errors.Wrap(err, "error during TryToDelete")
}
return nil
}
func (*Reconcile) makeDeletionFunc(gc gerritClient.ClientInterface, projectName string,
refs []gerritApi.Reference,
) func() error {
return func() error {
if err := gc.DeleteAccessRights(projectName, prepareAccessInfo(refs)); err != nil {
return errors.Wrap(err, "unable to delete access rights")
}
return nil
}
}