diff --git a/internal/controller/ols_console_reconciliator.go b/internal/controller/ols_console_reconciliator.go index 29662fdc..96547ce1 100644 --- a/internal/controller/ols_console_reconciliator.go +++ b/internal/controller/ols_console_reconciliator.go @@ -200,3 +200,68 @@ func (r *OLSConfigReconciler) activateConsoleUI(ctx context.Context, cr *olsv1al r.logger.Info("Console UI plugin activated") return nil } + +func (r *OLSConfigReconciler) removeConsoleUI(ctx context.Context) error { + tasks := []DeleteTask{ + { + Name: "deactivate Console Plugin", + Task: r.deactivateConsoleUI, + }, + { + Name: "delete Console Plugin", + Task: r.deleteConsoleUIPlugin, + }, + } + + for _, task := range tasks { + err := task.Task(ctx) + if err != nil { + r.logger.Error(err, "DeleteConsoleUIPlugin error", "task", task.Name) + return fmt.Errorf("failed to %s: %w", task.Name, err) + } + } + + r.logger.Info("DeleteConsoleUIPlugin completes") + + return nil +} + +func (r *OLSConfigReconciler) deleteConsoleUIPlugin(ctx context.Context) error { + plugin := &consolev1.ConsolePlugin{} + err := r.Client.Get(ctx, client.ObjectKey{Name: ConsoleUIPluginName}, plugin) + if err != nil { + if errors.IsNotFound(err) { + r.logger.Info("Console Plugin not found, skip deletion") + return nil + } + return fmt.Errorf("failed to get Console Plugin: %w", err) + } + err = r.Delete(ctx, plugin) + if err != nil { + return fmt.Errorf("failed to delete Console Plugin: %w", err) + } + r.logger.Info("Console Plugin deleted") + return nil +} + +func (r *OLSConfigReconciler) deactivateConsoleUI(ctx context.Context) error { + console := &openshiftv1.Console{} + err := r.Client.Get(ctx, client.ObjectKey{Name: ConsoleCRName}, console) + if err != nil { + return fmt.Errorf("failed to get Console: %w", err) + } + if console.Spec.Plugins == nil { + return nil + } + if slices.Contains(console.Spec.Plugins, ConsoleUIPluginName) { + console.Spec.Plugins = slices.DeleteFunc(console.Spec.Plugins, func(name string) bool { return name == ConsoleUIPluginName }) + } else { + return nil + } + err = r.Update(ctx, console) + if err != nil { + return fmt.Errorf("failed to update Console: %w", err) + } + r.logger.Info("Console UI plugin deactivated") + return nil +} diff --git a/internal/controller/ols_console_reconciliator_test.go b/internal/controller/ols_console_reconciliator_test.go index ff48a8d7..71c90034 100644 --- a/internal/controller/ols_console_reconciliator_test.go +++ b/internal/controller/ols_console_reconciliator_test.go @@ -7,6 +7,7 @@ import ( openshiftv1 "github.com/openshift/api/operator/v1" appsv1 "k8s.io/api/apps/v1" corev1 "k8s.io/api/core/v1" + "k8s.io/apimachinery/pkg/api/errors" metav1 "k8s.io/apimachinery/pkg/apis/meta/v1" "k8s.io/apimachinery/pkg/types" ) @@ -31,6 +32,20 @@ var _ = Describe("Console UI reconciliator", Ordered, func() { }) + AfterAll(func() { + console := openshiftv1.Console{} + err := k8sClient.Get(ctx, types.NamespacedName{Name: ConsoleCRName}, &console) + if err == nil { + err = k8sClient.Delete(ctx, &console) + Expect(err).NotTo(HaveOccurred()) + return + } else if errors.IsNotFound(err) { + return + } + Expect(err).NotTo(HaveOccurred()) + + }) + It("should reconcile from OLSConfig custom resource", func() { By("Reconcile the OLSConfig custom resource") err := reconciler.reconcileConsoleUI(ctx, cr) @@ -74,4 +89,58 @@ var _ = Describe("Console UI reconciliator", Ordered, func() { }) }) + + Context("Deleting logic", Ordered, func() { + BeforeAll(func() { + console := openshiftv1.Console{ + ObjectMeta: metav1.ObjectMeta{ + Name: ConsoleCRName, + }, + Spec: openshiftv1.ConsoleSpec{ + Plugins: []string{"monitoring-plugin", ConsoleUIPluginName}, + OperatorSpec: openshiftv1.OperatorSpec{ + ManagementState: openshiftv1.Managed, + }, + }, + } + err := k8sClient.Create(ctx, &console) + Expect(err).NotTo(HaveOccurred()) + }) + + AfterAll(func() { + console := openshiftv1.Console{} + err := k8sClient.Get(ctx, types.NamespacedName{Name: ConsoleCRName}, &console) + if err == nil { + err = k8sClient.Delete(ctx, &console) + Expect(err).NotTo(HaveOccurred()) + return + } else if errors.IsNotFound(err) { + return + } + Expect(err).NotTo(HaveOccurred()) + }) + + It("should reconcile from OLSConfig custom resource", func() { + By("Reconcile the OLSConfig custom resource") + err := reconciler.reconcileConsoleUI(ctx, cr) + Expect(err).NotTo(HaveOccurred()) + }) + + It("should delete the console plugin lightspeed-console-plugin", func() { + By("Delete the console plugin") + err := reconciler.removeConsoleUI(ctx) + Expect(err).NotTo(HaveOccurred()) + By("Get the console plugin") + plugin := &consolev1.ConsolePlugin{} + err = k8sClient.Get(ctx, types.NamespacedName{Name: ConsoleUIPluginName}, plugin) + Expect(errors.IsNotFound(err)).To(BeTrue()) + By("Get the console plugin list") + console := &openshiftv1.Console{} + err = k8sClient.Get(ctx, types.NamespacedName{Name: ConsoleCRName}, console) + Expect(err).NotTo(HaveOccurred()) + Expect(console.Spec.Plugins).NotTo(ContainElement(ConsoleUIPluginName)) + + }) + + }) }) diff --git a/internal/controller/olsconfig_controller.go b/internal/controller/olsconfig_controller.go index 40c36cb7..b5de23e4 100644 --- a/internal/controller/olsconfig_controller.go +++ b/internal/controller/olsconfig_controller.go @@ -78,6 +78,11 @@ func (r *OLSConfigReconciler) Reconcile(ctx context.Context, req ctrl.Request) ( if err != nil { if apierrors.IsNotFound(err) { r.logger.Info("olsconfig resource not found. Ignoring since object must be deleted") + err = r.removeConsoleUI(ctx) + if err != nil { + r.logger.Error(err, "Failed to remove console UI") + return ctrl.Result{}, err + } return ctrl.Result{}, nil } // Error reading the object - requeue the request. diff --git a/internal/controller/types.go b/internal/controller/types.go index 82ae86f6..58fa9135 100644 --- a/internal/controller/types.go +++ b/internal/controller/types.go @@ -15,6 +15,12 @@ type ReconcileTask struct { Task ReconcileFunc } +type DeleteFunc func(context.Context) error +type DeleteTask struct { + Name string + Task DeleteFunc +} + /*** application server configuration file ***/ // root of the app server configuration file type AppSrvConfigFile struct {