controllers/clusterkeycloak/clusterkeycloak_controller.go (112 lines of code) (raw):

package clusterkeycloak 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/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" keycloakApi "github.com/epam/edp-keycloak-operator/api/v1alpha1" "github.com/epam/edp-keycloak-operator/controllers/helper" "github.com/epam/edp-keycloak-operator/pkg/client/keycloak" ) type keycloakClientProvider interface { CreateKeycloakClientFomAuthData(ctx context.Context, authData *helper.KeycloakAuthData) (keycloak.Client, error) } func NewReconcile( client client.Client, scheme *runtime.Scheme, helper keycloakClientProvider, operatorNamespace string, ) *Reconciler { return &Reconciler{ client: client, scheme: scheme, helper: helper, operatorNamespace: operatorNamespace, } } // Reconciler reconciles a Keycloak object. type Reconciler struct { client client.Client scheme *runtime.Scheme helper keycloakClientProvider operatorNamespace string } const ( failedConnectionRetryPeriod = time.Second * 10 successConnectionRetryPeriod = time.Minute * 30 ) //+kubebuilder:rbac:groups=v1.edp.epam.com,resources=clusterkeycloaks,verbs=get;list;watch;create;update;patch;delete //+kubebuilder:rbac:groups=v1.edp.epam.com,resources=clusterkeycloaks/status,verbs=get;update;patch //+kubebuilder:rbac:groups=v1.edp.epam.com,resources=clusterkeycloaks/finalizers,verbs=update //+kubebuilder:rbac:groups=v1,resources=configmap,verbs=get;list;watch // Reconcile is a loop for reconciling ClusterKeycloak object. func (r *Reconciler) Reconcile(ctx context.Context, req ctrl.Request) (ctrl.Result, error) { log := ctrl.LoggerFrom(ctx) log.Info("Reconciling ClusterKeycloak") clusterKeycloak := &keycloakApi.ClusterKeycloak{} if err := r.client.Get(ctx, req.NamespacedName, clusterKeycloak); err != nil { if errors.IsNotFound(err) { log.Info("Instance not found") return reconcile.Result{}, nil } return ctrl.Result{}, fmt.Errorf("unable to get cluster keycloak: %w", err) } if err := r.updateConnectionStatusToKeycloak(ctx, clusterKeycloak); err != nil { return reconcile.Result{}, err } if !clusterKeycloak.Status.Connected { log.Info("ClusterKeycloak is not connected, will retry") return reconcile.Result{RequeueAfter: failedConnectionRetryPeriod}, nil } log.Info("Reconciling ClusterKeycloak has been finished") return reconcile.Result{ RequeueAfter: successConnectionRetryPeriod, }, nil } // SetupWithManager sets up the controller with the Manager. func (r *Reconciler) SetupWithManager(mgr ctrl.Manager) error { pred := predicate.Funcs{ DeleteFunc: func(e event.DeleteEvent) bool { return false }, } err := ctrl.NewControllerManagedBy(mgr). For(&keycloakApi.ClusterKeycloak{}, builder.WithPredicates(pred)). Complete(r) if err != nil { return fmt.Errorf("failed to setup ClusterKeycloak controller: %w", err) } return nil } func (r *Reconciler) updateConnectionStatusToKeycloak(ctx context.Context, instance *keycloakApi.ClusterKeycloak) error { log := ctrl.LoggerFrom(ctx) log.Info("Start updating connection status to ClusterKeycloak") err := r.createClient(ctx, instance) if err != nil { log.Error(err, "Unable to connect to Keycloak") } connected := err == nil if instance.Status.Connected == connected { log.Info("Connection status hasn't been changed", "status", instance.Status.Connected) return nil } log.Info("Connection status has been changed", "from", instance.Status.Connected, "to", connected) instance.Status.Connected = connected err = r.client.Status().Update(ctx, instance) if err != nil { return fmt.Errorf("failed to update status: %w", err) } log.Info("Status has been updated", "status", instance.Status) return nil } func (r *Reconciler) createClient(ctx context.Context, instance *keycloakApi.ClusterKeycloak) error { auth, err := helper.MakeKeycloakAuthDataFromClusterKeycloak(ctx, instance, r.operatorNamespace, r.client) if err != nil { return fmt.Errorf("failed to make Keycloak auth data: %w", err) } _, err = r.helper.CreateKeycloakClientFomAuthData(ctx, auth) if err != nil { return fmt.Errorf("failed to create Keycloak client: %w", err) } return nil }