github.com/verrazzano/verrazzano@v1.7.0/platform-operator/experimental/controllers/integration/cascade/reconciler.go (about)

     1  // Copyright (c) 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 cascade
     5  
     6  import (
     7  	ctx "context"
     8  	moduleapi "github.com/verrazzano/verrazzano-modules/module-operator/apis/platform/v1alpha1"
     9  	"github.com/verrazzano/verrazzano-modules/pkg/controller/result"
    10  	"github.com/verrazzano/verrazzano-modules/pkg/controller/spi/controllerspi"
    11  	"github.com/verrazzano/verrazzano-modules/pkg/vzlog"
    12  	"github.com/verrazzano/verrazzano/platform-operator/experimental/event"
    13  	"github.com/verrazzano/verrazzano/platform-operator/internal/config"
    14  	"golang.org/x/net/context"
    15  	corev1 "k8s.io/api/core/v1"
    16  	"k8s.io/apimachinery/pkg/apis/meta/v1/unstructured"
    17  	"k8s.io/apimachinery/pkg/runtime"
    18  	"os"
    19  	"path"
    20  )
    21  
    22  // Reconcile reconciles the IntegrateCascadeRequestEvent (in the form of a configmap).
    23  // Cascaded means that a lifecycle event for certain modules, such as prometheus-operator,
    24  // require that all integration charts for other modules be installed/upgraded.  This controller
    25  // finds such modules and creates events that will cause the integration chart for each one to be
    26  // applied.
    27  func (r Reconciler) Reconcile(spictx controllerspi.ReconcileContext, u *unstructured.Unstructured) result.Result {
    28  	log := vzlog.DefaultLogger()
    29  
    30  	// Get the configmap and convert into an event
    31  	cm := &corev1.ConfigMap{}
    32  	if err := runtime.DefaultUnstructuredConverter.FromUnstructured(u.Object, cm); err != nil {
    33  		spictx.Log.ErrorfThrottled(err.Error())
    34  		// This is a fatal error, don't requeue
    35  		return result.NewResult()
    36  	}
    37  	ev, err := event.ConfigMapToModuleIntegrationEvent(log, cm)
    38  	if err != nil {
    39  		spictx.Log.ErrorfThrottled(err.Error())
    40  		return result.NewResultShortRequeueDelayWithError(err)
    41  	}
    42  
    43  	// Create a single integration event for all the modules that have integration charts
    44  	res := r.createIntegrationEvents(log, ev)
    45  	if res.ShouldRequeue() {
    46  		return res
    47  	}
    48  
    49  	// Delete the event.  This is safe to do since the integration controller
    50  	// is the only controller processing IntegrateCascadeRequestEvent events
    51  	if err := r.Client.Delete(ctx.TODO(), cm); err != nil {
    52  		log.ErrorfThrottled("Failed to delete event configmap %s", cm.Name)
    53  		return result.NewResultShortRequeueDelayWithError(err)
    54  	}
    55  	return result.NewResult()
    56  }
    57  
    58  // createIntegrationEvents creates integration events for all modules that have an integration chart,
    59  // except for the module that was just integrated (i.e. the module in the IntegrateCascadeRequestEvent)
    60  func (r Reconciler) createIntegrationEvents(log vzlog.VerrazzanoLogger, ev *event.ModuleIntegrationEvent) result.Result {
    61  	modules := moduleapi.ModuleList{}
    62  	err := r.Client.List(context.TODO(), &modules)
    63  	if err != nil {
    64  		log.ErrorfThrottled("Failed getting the list of modules in the cluster: %v", err)
    65  		return result.NewResultShortRequeueDelayWithError(err)
    66  	}
    67  
    68  	var requeue *result.Result
    69  	for i, module := range modules.Items {
    70  		// If this module was just integrated then ignore it
    71  		moduleName := module.Spec.ModuleName
    72  		if moduleName == ev.ModuleName {
    73  			continue
    74  		}
    75  
    76  		// Nothing to do if an integration chart doesn't exist for this module
    77  		moduleChartDir := path.Join(config.GetIntegrationChartsDir(), moduleName)
    78  		_, err := os.Stat(moduleChartDir)
    79  		if err != nil {
    80  			if os.IsNotExist(err) {
    81  				continue
    82  			}
    83  			log.ErrorfThrottled("Failed to check if integration chart exists for module %s: %v", moduleName, err)
    84  			res := result.NewResultShortRequeueDelayWithError(err)
    85  			requeue = &res
    86  		}
    87  
    88  		// Create an event requesting that this module be integrated.  Always use installed event so that the charts get applied.
    89  		// Even in the case where the original module got deleted, install action is needed to re-apply the integration
    90  		// charts for the module.
    91  		res := event.CreateNonCascadingModuleIntegrationEvent(log, r.Client, &modules.Items[i], event.Installed)
    92  		if res.ShouldRequeue() {
    93  			requeue = &res
    94  		}
    95  	}
    96  
    97  	if requeue != nil {
    98  		return *requeue
    99  	}
   100  	return result.NewResult()
   101  }