controllers/qualitygate/sonarqualitygate_controller.go (110 lines of code) (raw):
package qualitygate
import (
"context"
"fmt"
"time"
"k8s.io/apimachinery/pkg/api/errors"
"k8s.io/apimachinery/pkg/runtime"
ctrl "sigs.k8s.io/controller-runtime"
"sigs.k8s.io/controller-runtime/pkg/client"
"sigs.k8s.io/controller-runtime/pkg/controller/controllerutil"
"github.com/epam/edp-sonar-operator/api/common"
sonarApi "github.com/epam/edp-sonar-operator/api/v1alpha1"
"github.com/epam/edp-sonar-operator/controllers/qualitygate/chain"
sonarclient "github.com/epam/edp-sonar-operator/pkg/client/sonar"
)
const (
sonarOperatorFinalizer = "edp.epam.com/finalizer"
errorRequeueTime = time.Second * 30
)
type apiClientProvider interface {
GetSonarApiClientFromSonarRef(ctx context.Context, namespace string, sonarRef common.HasSonarRef) (*sonarclient.Client, error)
}
// SonarQualityGateReconciler reconciles a SonarQualityGate object
type SonarQualityGateReconciler struct {
client client.Client
scheme *runtime.Scheme
apiClientProvider apiClientProvider
}
func NewSonarQualityGateReconciler(
client client.Client,
scheme *runtime.Scheme,
apiClientProvider apiClientProvider,
) *SonarQualityGateReconciler {
return &SonarQualityGateReconciler{client: client, scheme: scheme, apiClientProvider: apiClientProvider}
}
//+kubebuilder:rbac:groups=edp.epam.com,namespace=placeholder,resources=sonarqualitygates,verbs=get;list;watch;create;update;patch;delete
//+kubebuilder:rbac:groups=edp.epam.com,namespace=placeholder,resources=sonarqualitygates/status,verbs=get;update;patch
//+kubebuilder:rbac:groups=edp.epam.com,namespace=placeholder,resources=sonarqualitygates/finalizers,verbs=update
//+kubebuilder:rbac:groups="",namespace=placeholder,resources=secrets,verbs=get;list;watch
// Reconcile is part of the main kubernetes reconciliation loop which aims to
// move the current state of the cluster closer to the desired state.
func (r *SonarQualityGateReconciler) Reconcile(ctx context.Context, req ctrl.Request) (ctrl.Result, error) {
log := ctrl.LoggerFrom(ctx)
log.Info("Reconciling SonarQualityGate")
gate := &sonarApi.SonarQualityGate{}
err := r.client.Get(ctx, req.NamespacedName, gate)
if err != nil {
if errors.IsNotFound(err) {
return ctrl.Result{}, nil
}
return ctrl.Result{}, err
}
sonarApiClient, err := r.apiClientProvider.GetSonarApiClientFromSonarRef(ctx, req.Namespace, gate)
if err != nil {
log.Error(err, "An error has occurred while getting sonar api client")
return ctrl.Result{
RequeueAfter: errorRequeueTime,
}, nil
}
if gate.GetDeletionTimestamp() != nil {
if controllerutil.ContainsFinalizer(gate, sonarOperatorFinalizer) {
if err = chain.NewRemoveQualityGate(sonarApiClient).ServeRequest(ctx, gate); err != nil {
log.Error(err, "An error has occurred while deleting QualityGate")
return ctrl.Result{
RequeueAfter: errorRequeueTime,
}, nil
}
controllerutil.RemoveFinalizer(gate, sonarOperatorFinalizer)
if err = r.client.Update(ctx, gate); err != nil {
return ctrl.Result{}, err
}
}
return ctrl.Result{}, nil
}
if controllerutil.AddFinalizer(gate, sonarOperatorFinalizer) {
err = r.client.Update(ctx, gate)
if err != nil {
return ctrl.Result{}, err
}
}
oldStatus := gate.Status
if err = chain.MakeChain(sonarApiClient).ServeRequest(ctx, gate); err != nil {
log.Error(err, "An error has occurred while handling SonarQualityGate")
gate.Status.Value = "error"
gate.Status.Error = err.Error()
if err = r.updateSonarQualityGateStatus(ctx, gate, oldStatus); err != nil {
return ctrl.Result{}, err
}
return ctrl.Result{
RequeueAfter: errorRequeueTime,
}, nil
}
gate.Status.Value = common.StatusCreated
gate.Status.Error = ""
if err = r.updateSonarQualityGateStatus(ctx, gate, oldStatus); err != nil {
return ctrl.Result{}, err
}
return ctrl.Result{}, nil
}
// SetupWithManager sets up the controller with the Manager.
func (r *SonarQualityGateReconciler) SetupWithManager(mgr ctrl.Manager) error {
return ctrl.NewControllerManagedBy(mgr).
For(&sonarApi.SonarQualityGate{}).
Complete(r)
}
func (r *SonarQualityGateReconciler) updateSonarQualityGateStatus(
ctx context.Context,
gate *sonarApi.SonarQualityGate,
oldStatus sonarApi.SonarQualityGateStatus,
) error {
if gate.Status == oldStatus {
return nil
}
if err := r.client.Status().Update(ctx, gate); err != nil {
return fmt.Errorf("failed to update SonarQualityGate status: %w", err)
}
return nil
}