diff --git a/cmd/operator/main.go b/cmd/operator/main.go index e01a5dd..45b5b0d 100644 --- a/cmd/operator/main.go +++ b/cmd/operator/main.go @@ -128,6 +128,11 @@ func setupControllers(mgr ctrl.Manager) error { return err } + err = controllers.NewNatsGatewayReconciler(mgr).SetupWithManager(mgr) + if err != nil { + return err + } + return nil } diff --git a/controllers/natsgateway_controller.go b/controllers/natsgateway_controller.go index 0e124f3..2b010ca 100644 --- a/controllers/natsgateway_controller.go +++ b/controllers/natsgateway_controller.go @@ -9,10 +9,13 @@ import ( "k8s.io/client-go/tools/record" ctrl "sigs.k8s.io/controller-runtime" "sigs.k8s.io/controller-runtime/pkg/client" + "sigs.k8s.io/controller-runtime/pkg/controller/controllerutil" "sigs.k8s.io/controller-runtime/pkg/log" "sigs.k8s.io/controller-runtime/pkg/reconcile" + "github.com/zeiss/natz-operator/api/v1alpha1" natsv1alpha1 "github.com/zeiss/natz-operator/api/v1alpha1" + "github.com/zeiss/pkg/cast" "github.com/zeiss/pkg/k8s/finalizers" ) @@ -68,9 +71,113 @@ func (r *NatsGatewayReconciler) Reconcile(ctx context.Context, req ctrl.Request) return reconcile.Result{}, nil } + // get latest version of the gateway + if err := r.Get(ctx, req.NamespacedName, gateway); err != nil { + log.Error(err, "gateway not found", "gateway", req.NamespacedName) + + return reconcile.Result{}, err + } + + err := r.reconcileResources(ctx, req, gateway) + if err != nil { + r.Recorder.Event(gateway, corev1.EventTypeWarning, cast.String(EventReasonGatewayFailed), "gateway resources reconciliation failed") + gateway.Status.Phase = v1alpha1.GatewayPhaseFailed + return reconcile.Result{}, r.Status().Update(ctx, gateway) + } + return reconcile.Result{}, nil } +func (r *NatsGatewayReconciler) reconcileResources(ctx context.Context, req ctrl.Request, gateway *natsv1alpha1.NatsGateway) error { + log := log.FromContext(ctx) + + log.Info("reconcile resources", "name", gateway.Name, "namespace", gateway.Namespace) + + if err := r.reconcileStatus(ctx, gateway); err != nil { + log.Error(err, "failed to reconcile status", "name", gateway.Name, "namespace", gateway.Namespace) + return err + } + + if err := r.reconcileGateway(ctx, req, gateway); err != nil { + log.Error(err, "failed to reconcile gateway", "name", gateway.Name, "namespace", gateway.Namespace) + return err + } + + if err := r.reconcileSecret(ctx, gateway); err != nil { + log.Error(err, "failed to reconcile secret", "name", gateway.Name, "namespace", gateway.Namespace) + return err + } + + return nil +} + +func (r *NatsGatewayReconciler) reconcileGateway(ctx context.Context, req ctrl.Request, gateway *natsv1alpha1.NatsGateway) error { + log := log.FromContext(ctx) + + log.Info("reconcile status", "name", gateway.Name, "namespace", gateway.Namespace) + + op, err := controllerutil.CreateOrUpdate(ctx, r.Client, gateway, func() error { + controllerutil.AddFinalizer(gateway, natsv1alpha1.FinalizerName) + + return nil + }) + if err != nil { + return err + } + + if op == controllerutil.OperationResultCreated || op == controllerutil.OperationResultUpdated { + log.Info("account created or updated", "operation", op) + } + + return nil +} + +func (r *NatsGatewayReconciler) reconcileSecret(ctx context.Context, gateway *natsv1alpha1.NatsGateway) error { + log := log.FromContext(ctx) + + log.Info("reconcile secret", "name", gateway.Name, "namespace", gateway.Namespace) + + gatewaySecret := &corev1.Secret{} + gatewaySecretName := client.ObjectKey{ + Namespace: gateway.Namespace, + Name: gateway.Spec.Password.SecretKeyRef.Name, + } + + if err := r.Get(ctx, gatewaySecretName, gatewaySecret); errors.IsNotFound(err) { + r.Recorder.Event(gateway, corev1.EventTypeWarning, cast.String(EventReasonGatewayFailed), "gateway secret not found") + return err + } + + op, err := controllerutil.CreateOrUpdate(ctx, r.Client, gatewaySecret, func() error { + return controllerutil.SetControllerReference(gateway, gatewaySecret, r.Scheme) + }) + if err != nil { + return err + } + + if op == controllerutil.OperationResultCreated || op == controllerutil.OperationResultUpdated { + log.Info("secret created or updated", "operation", op) + } + + return nil +} + +func (r *NatsGatewayReconciler) reconcileStatus(ctx context.Context, gateway *natsv1alpha1.NatsGateway) error { + log := log.FromContext(ctx) + + log.Info("reconcile status", "name", gateway.Name, "namespace", gateway.Namespace) + + phase := v1alpha1.GatewayPhaseNone + + if gateway.Status.Phase != phase { + gateway.Status.Phase = phase + + return r.Status().Update(ctx, gateway) + } + + return nil +} + func (r *NatsGatewayReconciler) reconcileDelete(ctx context.Context, gateway *natsv1alpha1.NatsGateway) error { log := log.FromContext(ctx) @@ -88,7 +195,7 @@ func (r *NatsGatewayReconciler) reconcileDelete(ctx context.Context, gateway *na // SetupWithManager sets up the controller with the Manager. func (r *NatsGatewayReconciler) SetupWithManager(mgr ctrl.Manager) error { return ctrl.NewControllerManagedBy(mgr). - For(&natsv1alpha1.NatsAccount{}). + For(&natsv1alpha1.NatsGateway{}). Owns(&corev1.Secret{}). Complete(r) }