controllers/gerritgroup/controller.go (127 lines of code) (raw):
package gerritgroup
import (
"context"
"fmt"
"reflect"
"strconv"
"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 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.GerritGroup{}, builder.WithPredicates(pred)).
Complete(r)
if err != nil {
return fmt.Errorf("failed to setup GerritGroup controller: %w", err)
}
return nil
}
func isSpecUpdated(e event.UpdateEvent) bool {
oo, ok := e.ObjectOld.(*gerritApi.GerritGroup)
if !ok {
return false
}
no, ok := e.ObjectNew.(*gerritApi.GerritGroup)
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=gerritgroups,verbs=get;list;watch;create;update;patch;delete
//+kubebuilder:rbac:groups=v2.edp.epam.com,namespace=placeholder,resources=gerritgroups/status,verbs=get;update;patch
//+kubebuilder:rbac:groups=v2.edp.epam.com,namespace=placeholder,resources=gerritgroups/finalizers,verbs=update
func (r *Reconcile) Reconcile(ctx context.Context, request reconcile.Request) (reconcile.Result, error) {
log := r.log.WithValues("Request.Namespace", request.Namespace, "Request.Name", request.Name)
log.Info("Reconciling GerritGroup")
var instance gerritApi.GerritGroup
if err := r.client.Get(ctx, request.NamespacedName, &instance); err != nil {
if k8sErrors.IsNotFound(err) {
// Request object not found, could have been deleted after reconcile request.
// Owned objects are automatically garbage collected. For additional cleanup logic use finalizers.
// Return and don't requeue
log.Info("instance not found")
return reconcile.Result{}, nil
}
return reconcile.Result{}, errors.Wrap(err, "unable to get gerrit group")
}
defer func() {
if err := r.client.Status().Update(context.Background(), &instance); err != nil {
log.Error(err, "unable to update instance status")
}
}()
if err := r.tryToReconcile(ctx, &instance); err != nil {
log.Error(err, "unable to reconcile gerrit group")
instance.Status.Value = err.Error()
return reconcile.Result{RequeueAfter: requeueTime}, nil
}
instance.Status.Value = helper.StatusOK
return reconcile.Result{}, nil
}
func (r *Reconcile) tryToReconcile(ctx context.Context, instance *gerritApi.GerritGroup) error {
if !helper.IsInstanceOwnerSet(instance) {
ownerReference := helper.FindCROwnerName(instance.Spec.OwnerName)
gerritInstance, err := helper.GetGerritInstance(ctx, r.client, ownerReference, instance.Namespace)
if err != nil {
return errors.Wrap(err, "unable to get gerrit instance")
}
helper.SetOwnerReference(instance, gerritInstance.TypeMeta, &gerritInstance.ObjectMeta)
err = r.client.Update(ctx, instance)
if err != nil {
return errors.Wrap(err, "unable to update instance owner refs")
}
}
gerritInstance, err := helper.GetInstanceOwner(ctx, r.client, instance)
if err != nil {
return errors.Wrap(err, "unable to get instance owner")
}
cl, err := r.service.GetRestClient(gerritInstance)
if err != nil {
return errors.Wrap(err, "unable to get rest client")
}
gr, err := cl.CreateGroup(instance.Spec.Name, instance.Spec.Description, instance.Spec.VisibleToAll)
if err == nil {
instance.Status.ID = gr.ID
instance.Status.GroupID = strconv.Itoa(gr.GroupID)
// group is created, job done, we can exit
return nil
}
if !gerritClient.IsErrAlreadyExists(err) {
// unexpected error
return errors.Wrap(err, "unable to create group")
}
// in case group already exists,
// we want to make sure that CRs spec is in sync with group
// if ID is not set yet, we can move on
if instance.Status.ID == "" {
return nil
}
err = cl.UpdateGroup(instance.Status.ID, instance.Spec.Description, instance.Spec.VisibleToAll)
if err != nil {
return errors.Wrap(err, "unable to update gerrit group")
}
return nil
}