package system import ( "context" "errors" "fmt" "time" zitadelv1alpha1 "gitea.corredorconect.com/software-engineering/zitadel-k8s-operator/api/v1alpha1" condition "gitea.corredorconect.com/software-engineering/zitadel-k8s-operator/pkg/condition" health "gitea.corredorconect.com/software-engineering/zitadel-k8s-operator/pkg/health" zitadelClient "gitea.corredorconect.com/software-engineering/zitadel-k8s-operator/pkg/zitadel" "github.com/hashicorp/go-multierror" ctrl "sigs.k8s.io/controller-runtime" "sigs.k8s.io/controller-runtime/pkg/client" "sigs.k8s.io/controller-runtime/pkg/log" ) type SystemReconciler struct { Client client.Client RefResolver *zitadelv1alpha1.RefResolver ConditionReady *condition.Ready WrappedReconciler WrappedSystemReconciler Finalizer Finalizer RequeueInterval time.Duration } func NewSystemReconciler(client client.Client, cr *condition.Ready, wr WrappedSystemReconciler, f Finalizer, requeueInterval time.Duration) Reconciler { return &SystemReconciler{ Client: client, RefResolver: zitadelv1alpha1.NewRefResolver(client), ConditionReady: cr, WrappedReconciler: wr, Finalizer: f, RequeueInterval: requeueInterval, } } func (r *SystemReconciler) Reconcile(ctx context.Context, resource Resource) (ctrl.Result, error) { if resource.IsBeingDeleted() { if err := r.Finalizer.Finalize(ctx, resource); err != nil { return ctrl.Result{}, fmt.Errorf("error finalizing %s: %v", resource.GetName(), err) } return ctrl.Result{}, nil } clusterRef, err := resource.ClusterRef(ctx, r.RefResolver) if err != nil { return ctrl.Result{}, err } cluster, err := r.RefResolver.Cluster(ctx, clusterRef, resource.GetNamespace()) if err != nil { var errBundle *multierror.Error errBundle = multierror.Append(errBundle, err) err = r.WrappedReconciler.PatchStatus(ctx, r.ConditionReady.PatcherRefResolver(err, cluster)) errBundle = multierror.Append(errBundle, err) return ctrl.Result{}, fmt.Errorf("error getting Cluster: %v", errBundle) } if err := waitForCluster(ctx, r.Client, resource, cluster); err != nil { var errBundle *multierror.Error errBundle = multierror.Append(errBundle, err) err := r.WrappedReconciler.PatchStatus(ctx, r.ConditionReady.PatcherWithError(err)) errBundle = multierror.Append(errBundle, err) return ctrl.Result{}, fmt.Errorf("error waiting for Cluster: %v", errBundle) } ztdClient, err := zitadelClient.NewSystemClient(ctx, cluster, *r.RefResolver) if err != nil { var errBundle *multierror.Error errBundle = multierror.Append(errBundle, err) msg := fmt.Sprintf("Error connecting to System: %v", err) err = r.WrappedReconciler.PatchStatus(ctx, r.ConditionReady.PatcherFailed(msg)) errBundle = multierror.Append(errBundle, err) return r.retryResult(ctx, resource, errBundle) } defer ztdClient.Connection.Close() err = r.WrappedReconciler.Reconcile(ctx, ztdClient) var errBundle *multierror.Error errBundle = multierror.Append(errBundle, err) if err := errBundle.ErrorOrNil(); err != nil { msg := fmt.Sprintf("Error creating %s: %v", resource.GetName(), err) err = r.WrappedReconciler.PatchStatus(ctx, r.ConditionReady.PatcherFailed(msg)) errBundle = multierror.Append(errBundle, err) return r.retryResult(ctx, resource, errBundle) } if err = r.Finalizer.AddFinalizer(ctx); err != nil { errBundle = multierror.Append(errBundle, fmt.Errorf("error adding finalizer to %s: %v", resource.GetName(), err)) } err = r.WrappedReconciler.PatchStatus(ctx, r.ConditionReady.PatcherWithError(errBundle.ErrorOrNil())) errBundle = multierror.Append(errBundle, err) if err := errBundle.ErrorOrNil(); err != nil { return ctrl.Result{}, err } return r.requeueResult(ctx, resource) } func (r *SystemReconciler) retryResult(ctx context.Context, resource Resource, err error) (ctrl.Result, error) { return ctrl.Result{}, err } func (r *SystemReconciler) requeueResult(ctx context.Context, resource Resource) (ctrl.Result, error) { if r.RequeueInterval > 0 { log.FromContext(ctx).V(1).Info("Requeuing SYSTEM resource") return ctrl.Result{RequeueAfter: r.RequeueInterval}, nil } return ctrl.Result{}, nil } func waitForCluster(ctx context.Context, client client.Client, resource Resource, system *zitadelv1alpha1.Cluster) error { var systemErr *multierror.Error healthy, err := health.IsClusterHealthy(ctx, client, system) if err != nil { systemErr = multierror.Append(systemErr, err) } if !healthy { systemErr = multierror.Append(systemErr, errors.New("System not healthy")) } return systemErr.ErrorOrNil() }