github.com/verrazzano/verrazzano@v1.7.0/platform-operator/controllers/configmaps/overrides/controller.go (about)

     1  // Copyright (c) 2022, 2023, Oracle and/or its affiliates.
     2  // Licensed under the Universal Permissive License v 1.0 as shown at https://oss.oracle.com/licenses/upl.
     3  
     4  package overrides
     5  
     6  import (
     7  	"context"
     8  	"github.com/verrazzano/verrazzano/platform-operator/constants"
     9  	vzstatus "github.com/verrazzano/verrazzano/platform-operator/controllers/verrazzano/healthcheck"
    10  	"sigs.k8s.io/controller-runtime/pkg/controller/controllerutil"
    11  	"time"
    12  
    13  	corev1 "k8s.io/api/core/v1"
    14  	"k8s.io/apimachinery/pkg/api/errors"
    15  	"k8s.io/apimachinery/pkg/runtime"
    16  	ctrl "sigs.k8s.io/controller-runtime"
    17  	"sigs.k8s.io/controller-runtime/pkg/client"
    18  	"sigs.k8s.io/controller-runtime/pkg/reconcile"
    19  
    20  	vzctrl "github.com/verrazzano/verrazzano/pkg/controller"
    21  	"github.com/verrazzano/verrazzano/pkg/log/vzlog"
    22  	installv1alpha1 "github.com/verrazzano/verrazzano/platform-operator/apis/verrazzano/v1alpha1"
    23  	"github.com/verrazzano/verrazzano/platform-operator/controllers"
    24  	"github.com/verrazzano/verrazzano/platform-operator/controllers/verrazzano/component/spi"
    25  
    26  	"go.uber.org/zap"
    27  )
    28  
    29  // OverridesConfigMapsReconciler reconciles ConfigMaps.
    30  // This controller manages install override sources from the Verrazzano CR
    31  type OverridesConfigMapsReconciler struct {
    32  	client.Client
    33  	Scheme        *runtime.Scheme
    34  	log           vzlog.VerrazzanoLogger
    35  	StatusUpdater vzstatus.Updater
    36  }
    37  
    38  // SetupWithManager creates a new controller and adds it to the manager
    39  func (r *OverridesConfigMapsReconciler) SetupWithManager(mgr ctrl.Manager) error {
    40  	return ctrl.NewControllerManagedBy(mgr).
    41  		For(&corev1.ConfigMap{}).
    42  		Complete(r)
    43  }
    44  
    45  // Reconcile the ConfigMap
    46  func (r *OverridesConfigMapsReconciler) Reconcile(ctx context.Context, req ctrl.Request) (ctrl.Result, error) {
    47  
    48  	if ctx == nil {
    49  		ctx = context.TODO()
    50  	}
    51  
    52  	// Get Verrazzano from the cluster
    53  	vzList := &installv1alpha1.VerrazzanoList{}
    54  	err := r.List(ctx, vzList)
    55  	if err != nil {
    56  		if errors.IsNotFound(err) {
    57  			return reconcile.Result{}, nil
    58  		}
    59  		zap.S().Errorf("Failed to fetch Verrazzano resource: %v", err)
    60  		return newRequeueWithDelay(), err
    61  	}
    62  
    63  	if vzList != nil && len(vzList.Items) > 0 {
    64  		vz := &vzList.Items[0]
    65  		res, err := r.reconcileInstallOverrideConfigMap(ctx, req, vz)
    66  		if err != nil {
    67  			zap.S().Errorf("Failed to reconcile ConfigMap: %v", err)
    68  			return newRequeueWithDelay(), err
    69  		}
    70  		return res, nil
    71  	}
    72  	return ctrl.Result{}, nil
    73  }
    74  
    75  // reconcileInstallOverrideConfigMap looks through the Verrazzano CR for the ConfigMap
    76  // if the request is from the same namespace as the CR
    77  func (r *OverridesConfigMapsReconciler) reconcileInstallOverrideConfigMap(ctx context.Context, req ctrl.Request, vz *installv1alpha1.Verrazzano) (ctrl.Result, error) {
    78  
    79  	// Get the ConfigMap present in the Verrazzano CR namespace
    80  	configMap := &corev1.ConfigMap{}
    81  	var currentCondition installv1alpha1.ConditionType
    82  	if len(vz.Status.Conditions) > 0 {
    83  		currentCondition = vz.Status.Conditions[len(vz.Status.Conditions)-1].Type
    84  	}
    85  
    86  	if currentCondition == installv1alpha1.CondInstallComplete || currentCondition == installv1alpha1.CondUpgradeComplete {
    87  		if err := controllers.CreateOrUpdateEffectiveConfigCM(ctx, r.Client, vz); err != nil {
    88  			return newRequeueWithDelay(), nil
    89  		}
    90  	}
    91  
    92  	if vz.Namespace == req.Namespace {
    93  		if err := r.Get(ctx, req.NamespacedName, configMap); err != nil {
    94  			// Do not reconcile if the ConfigMap was deleted
    95  			if errors.IsNotFound(err) {
    96  				if err := controllers.ProcDeletedOverride(r.StatusUpdater, r.Client, vz, req.Name, constants.ConfigMapKind); err != nil {
    97  					// Do not return an error as it's most likely due to timing
    98  					return newRequeueWithDelay(), nil
    99  				}
   100  				return reconcile.Result{}, nil
   101  			}
   102  			zap.S().Errorf("Failed to fetch ConfigMap in Verrazzano CR namespace: %v", err)
   103  			return newRequeueWithDelay(), err
   104  		}
   105  
   106  		if result, err := r.initLogger(*configMap); err != nil {
   107  			return result, err
   108  		}
   109  
   110  		componentCtx, err := spi.NewContext(r.log, r.Client, vz, nil, false)
   111  		if err != nil {
   112  			r.log.Errorf("Failed to construct component context: %v", err)
   113  			return newRequeueWithDelay(), err
   114  		}
   115  
   116  		// Check if the ConfigMap is listed as an override source under a component
   117  		if componentName, ok := controllers.VzContainsResource(componentCtx, configMap.Name, configMap.Kind); ok {
   118  			if configMap.DeletionTimestamp.IsZero() {
   119  				// Check if our finalizer is already present
   120  				if !controllerutil.ContainsFinalizer(configMap, constants.OverridesFinalizer) {
   121  					configMap.Finalizers = append(configMap.Finalizers, constants.OverridesFinalizer)
   122  					err := r.Update(context.TODO(), configMap)
   123  					if err != nil {
   124  						return newRequeueWithDelay(), err
   125  					}
   126  					return reconcile.Result{Requeue: true}, nil
   127  				}
   128  			} else {
   129  				// Requeue if other finalizers are present
   130  				if configMap.Finalizers != nil && !controllerutil.ContainsFinalizer(configMap, constants.OverridesFinalizer) {
   131  					return reconcile.Result{Requeue: true}, nil
   132  				}
   133  
   134  				// Now since only our finalizer is present, therefore we remove it to delete the ConfigMap
   135  				// and trigger verrazzano reconcile
   136  				controllerutil.RemoveFinalizer(configMap, constants.OverridesFinalizer)
   137  				err := r.Update(context.TODO(), configMap)
   138  				if err != nil {
   139  					return newRequeueWithDelay(), err
   140  				}
   141  			}
   142  
   143  			err := controllers.UpdateVerrazzanoForInstallOverrides(r.StatusUpdater, componentCtx, componentName)
   144  			if err != nil {
   145  				r.log.ErrorfThrottled("Failed to reconcile ConfigMap: %v", err)
   146  				return newRequeueWithDelay(), err
   147  			}
   148  			r.log.Infof("Updated Verrazzano Resource")
   149  		}
   150  	}
   151  	return ctrl.Result{}, nil
   152  }
   153  
   154  // initialize logger for ConfigMap
   155  func (r *OverridesConfigMapsReconciler) initLogger(cm corev1.ConfigMap) (ctrl.Result, error) {
   156  	// Get the resource logger needed to log message using 'progress' and 'once' methods
   157  	log, err := vzlog.EnsureResourceLogger(&vzlog.ResourceConfig{
   158  		Name:           cm.Name,
   159  		Namespace:      cm.Namespace,
   160  		ID:             string(cm.UID),
   161  		Generation:     cm.Generation,
   162  		ControllerName: "ConfigMaps",
   163  	})
   164  	if err != nil {
   165  		zap.S().Errorf("Failed to create resource logger for VerrazzanoConfigMap controller: %v", err)
   166  		return newRequeueWithDelay(), err
   167  	}
   168  	r.log = log
   169  	return ctrl.Result{}, nil
   170  }
   171  
   172  // Create a new Result that will cause a reconcile requeue after a short delay
   173  func newRequeueWithDelay() ctrl.Result {
   174  	return vzctrl.NewRequeueWithDelay(3, 5, time.Second)
   175  }