github.com/verrazzano/verrazzano@v1.7.1/application-operator/controllers/metricstrait/operator.go (about)

     1  // Copyright (c) 2022, 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 metricstrait
     5  
     6  import (
     7  	"context"
     8  
     9  	promoperapi "github.com/prometheus-operator/prometheus-operator/pkg/apis/monitoring/v1"
    10  	vzapi "github.com/verrazzano/verrazzano/application-operator/apis/oam/v1alpha1"
    11  	"github.com/verrazzano/verrazzano/application-operator/constants"
    12  	vznav "github.com/verrazzano/verrazzano/application-operator/controllers/navigation"
    13  	"github.com/verrazzano/verrazzano/application-operator/controllers/reconcileresults"
    14  	"github.com/verrazzano/verrazzano/pkg/log/vzlog"
    15  	"k8s.io/apimachinery/pkg/apis/meta/v1/unstructured"
    16  	ctrl "sigs.k8s.io/controller-runtime"
    17  	"sigs.k8s.io/controller-runtime/pkg/client"
    18  	"sigs.k8s.io/controller-runtime/pkg/controller/controllerutil"
    19  	"sigs.k8s.io/controller-runtime/pkg/reconcile"
    20  )
    21  
    22  // doOperatorReconcile reconciles a metrics trait to work with the Prometheus Operator
    23  // This reconciler will create a ServiceMonitor for each metrics trait application to hook up metrics with Prometheus
    24  func (r *Reconciler) doOperatorReconcile(ctx context.Context, trait *vzapi.MetricsTrait, log vzlog.VerrazzanoLogger) (ctrl.Result, error) {
    25  	log.Debugf("Entering the Service Monitor reconcile process for trait: %s", trait.Name)
    26  	if trait.DeletionTimestamp.IsZero() {
    27  		return r.reconcileOperatorTraitCreateOrUpdate(ctx, trait, log)
    28  	}
    29  	return r.reconcileOperatorTraitDelete(ctx, trait, log)
    30  }
    31  
    32  func (r *Reconciler) reconcileOperatorTraitCreateOrUpdate(ctx context.Context, trait *vzapi.MetricsTrait, log vzlog.VerrazzanoLogger) (ctrl.Result, error) {
    33  	log.Debugf("Creating or Updating the Service Monitor from trait: %s", trait.Name)
    34  	var err error
    35  	// Add finalizer if required.
    36  	if err := r.addFinalizerIfRequired(ctx, trait, log); err != nil {
    37  		return reconcile.Result{}, err
    38  	}
    39  
    40  	// Fetch workload resource using information from the trait
    41  	var workload *unstructured.Unstructured
    42  	if workload, err = vznav.FetchWorkloadFromTrait(ctx, r, log, trait); err != nil || workload == nil {
    43  		return reconcile.Result{}, err
    44  	}
    45  
    46  	// Construct the trait defaults from the trait and the workload resources
    47  	traitDefaults, supported, err := r.fetchTraitDefaults(ctx, workload, log)
    48  	if err != nil {
    49  		return reconcile.Result{}, err
    50  	}
    51  	if !supported || traitDefaults == nil {
    52  		return reconcile.Result{Requeue: false}, nil
    53  	}
    54  
    55  	// If the user has specified a non-default (i.e. not the legacy Prometheus) scraper, then we have already updated the scrape config,
    56  	// so do not attempt to create/update a ServiceMonitor.
    57  	if !r.isLegacyPrometheusScraper(trait, traitDefaults) {
    58  		return reconcile.Result{}, nil
    59  	}
    60  
    61  	// Find the child resources of the workload based on the childResourceKinds from the
    62  	// workload definition, workload uid and the ownerReferences of the children.
    63  	var children []*unstructured.Unstructured
    64  	if children, err = vznav.FetchWorkloadChildren(ctx, r, log, workload); err != nil {
    65  		return reconcile.Result{}, err
    66  	}
    67  
    68  	// Create or update the related resources of the trait and collect the outcomes.
    69  	status := r.createOrUpdateRelatedWorkloads(ctx, trait, workload, traitDefaults, children, log)
    70  
    71  	var opResult controllerutil.OperationResult
    72  	var rel vzapi.QualifiedResourceRelation
    73  	// update the ServiceMonitor if trait is enabled, delete it if trait is disabled
    74  	if isEnabled(trait) {
    75  		rel, opResult, err = r.updateServiceMonitor(ctx, trait, workload, traitDefaults, log)
    76  	} else {
    77  		serviceMonitorName, err := createServiceMonitorName(trait, 0)
    78  		if err != nil {
    79  			return reconcile.Result{}, log.ErrorfNewErr("Failed to create Service Monitor name: %v", err)
    80  		}
    81  		opResult, err = r.deleteServiceMonitor(ctx, trait.Namespace, serviceMonitorName, trait, log)
    82  		if client.IgnoreNotFound(err) != nil {
    83  			return reconcile.Result{}, log.ErrorfNewErr("Failed to delete Service Monitor %s for disabled metrics trait: %v", serviceMonitorName, err)
    84  		}
    85  		rel = vzapi.QualifiedResourceRelation{APIVersion: promoperapi.SchemeGroupVersion.String(), Kind: promoperapi.ServiceMonitorsKind, Namespace: trait.Namespace, Name: serviceMonitorName, Role: scraperRole}
    86  	}
    87  	status.RecordOutcome(rel, opResult, err)
    88  
    89  	return r.updateTraitStatus(ctx, trait, status, log)
    90  }
    91  
    92  func (r *Reconciler) reconcileOperatorTraitDelete(ctx context.Context, trait *vzapi.MetricsTrait, log vzlog.VerrazzanoLogger) (ctrl.Result, error) {
    93  	log.Debugf("Deleting the Service Monitor from trait: %s", trait.Name)
    94  	status := r.deleteOrUpdateObsoleteResources(ctx, trait, &reconcileresults.ReconcileResults{}, log)
    95  	// Only remove the finalizer if all related resources were successfully updated.
    96  	if !status.ContainsErrors() {
    97  		if err := r.removeFinalizerIfRequired(ctx, trait, log); err != nil {
    98  			return reconcile.Result{}, err
    99  		}
   100  	}
   101  	return ctrl.Result{}, nil
   102  }
   103  
   104  // fetchTraitDefaults fetches metrics trait default values.
   105  // These default values are workload type dependent.
   106  func (r *Reconciler) fetchTraitDefaults(ctx context.Context, workload *unstructured.Unstructured, log vzlog.VerrazzanoLogger) (*vzapi.MetricsTraitSpec, bool, error) {
   107  	apiVerKind, err := vznav.GetAPIVersionKindOfUnstructured(workload)
   108  	if err != nil {
   109  		return nil, true, log.ErrorfNewErr("Failed to get the API version from the workload: %v", err)
   110  	}
   111  
   112  	workloadType := GetSupportedWorkloadType(apiVerKind)
   113  	switch workloadType {
   114  	case constants.WorkloadTypeWeblogic:
   115  		spec, err := r.NewTraitDefaultsForWLSDomainWorkload(ctx, workload)
   116  		return spec, true, err
   117  	case constants.WorkloadTypeCoherence:
   118  		spec, err := r.NewTraitDefaultsForCOHWorkload(ctx, workload)
   119  		return spec, true, err
   120  	case constants.WorkloadTypeGeneric:
   121  		spec, err := r.NewTraitDefaultsForGenericWorkload()
   122  		return spec, true, err
   123  	default:
   124  		// Log the kind/workload is unsupported and return a nil trait.
   125  		log.Debugf("unsupported kind %s of workload %s", apiVerKind, vznav.GetNamespacedNameFromUnstructured(workload))
   126  		return nil, false, nil
   127  	}
   128  
   129  }