github.com/verrazzano/verrazzano@v1.7.0/application-operator/controllers/metricstrait/monitor.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 metricstrait
     5  
     6  import (
     7  	"context"
     8  
     9  	"github.com/crossplane/oam-kubernetes-runtime/pkg/oam"
    10  	promoperapi "github.com/prometheus-operator/prometheus-operator/pkg/apis/monitoring/v1"
    11  	vzapi "github.com/verrazzano/verrazzano/application-operator/apis/oam/v1alpha1"
    12  	"github.com/verrazzano/verrazzano/application-operator/controllers/clusters"
    13  	"github.com/verrazzano/verrazzano/application-operator/internal/metrics"
    14  	"github.com/verrazzano/verrazzano/pkg/log/vzlog"
    15  	"k8s.io/apimachinery/pkg/apis/meta/v1/unstructured"
    16  	"sigs.k8s.io/controller-runtime/pkg/controller/controllerutil"
    17  )
    18  
    19  // updateServiceMonitor creates or updates a service monitor given the trait and workload parameters
    20  // A service monitor emulates a scrape config for Prometheus with the Prometheus Operator
    21  func (r *Reconciler) updateServiceMonitor(ctx context.Context, trait *vzapi.MetricsTrait, workload *unstructured.Unstructured, traitDefaults *vzapi.MetricsTraitSpec, log vzlog.VerrazzanoLogger) (vzapi.QualifiedResourceRelation, controllerutil.OperationResult, error) {
    22  	var rel vzapi.QualifiedResourceRelation
    23  
    24  	// If the metricsTrait is being disabled then return nil for the config
    25  	if !isEnabled(trait) || workload == nil {
    26  		return rel, controllerutil.OperationResultNone, nil
    27  	}
    28  
    29  	// Creating a service monitor with name and namespace
    30  	pmName, err := createServiceMonitorName(trait, 0)
    31  	if err != nil {
    32  		return rel, controllerutil.OperationResultNone, log.ErrorfNewErr("Failed to create Service Monitor name: %v", err)
    33  	}
    34  
    35  	// Fetch the secret by name if it is provided in either the trait or the trait defaults.
    36  	secret, err := fetchSourceCredentialsSecretIfRequired(ctx, trait, traitDefaults, workload, r.Client)
    37  	if err != nil {
    38  		return rel, controllerutil.OperationResultNone, log.ErrorfNewErr("Failed to fetch metrics source credentials: %v", err)
    39  	}
    40  
    41  	// Determine whether Istio is enabled for the workload
    42  	useHTTPS, err := useHTTPSForScrapeTarget(ctx, r.Client, trait)
    43  	if err != nil {
    44  		return rel, controllerutil.OperationResultNone, log.ErrorfNewErr("Failed to determine if Istio was enabled for the target: %v", err)
    45  	}
    46  
    47  	wlsWorkload, err := isWLSWorkload(workload)
    48  	if err != nil {
    49  		return rel, controllerutil.OperationResultNone, log.ErrorfNewErr("Failed to determine if workload %s/&s was of type WLS: %v", workload.GetNamespace(), workload.GetName(), err)
    50  	}
    51  	vzPromLabels := !wlsWorkload
    52  
    53  	log.Debugf("Creating or updating the Service Monitor for workload %s/%s", workload.GetNamespace(), workload.GetName())
    54  	scrapeInfo := metrics.ScrapeInfo{
    55  		Ports:              len(getPortSpecs(trait, traitDefaults)),
    56  		BasicAuthSecret:    secret,
    57  		IstioEnabled:       &useHTTPS,
    58  		VZPrometheusLabels: &vzPromLabels,
    59  		ClusterName:        clusters.GetClusterName(ctx, r.Client),
    60  	}
    61  
    62  	// Fill in the scrape info if it is populated in the trait
    63  	if trait.Spec.Path != nil {
    64  		scrapeInfo.Path = trait.Spec.Path
    65  	}
    66  
    67  	// Populate the keep labels to match the oam pod labels
    68  	scrapeInfo.KeepLabels = map[string]string{
    69  		"__meta_kubernetes_pod_label_app_oam_dev_name":      trait.Labels[oam.LabelAppName],
    70  		"__meta_kubernetes_pod_label_app_oam_dev_component": trait.Labels[oam.LabelAppComponent],
    71  	}
    72  
    73  	serviceMonitor := promoperapi.ServiceMonitor{}
    74  	serviceMonitor.SetName(pmName)
    75  	serviceMonitor.SetNamespace(workload.GetNamespace())
    76  	result, err := controllerutil.CreateOrUpdate(ctx, r.Client, &serviceMonitor, func() error {
    77  		return metrics.PopulateServiceMonitor(scrapeInfo, &serviceMonitor, log)
    78  	})
    79  	if err != nil {
    80  		return rel, controllerutil.OperationResultNone, log.ErrorfNewErr("Failed to create or update the service monitor for workload %s/%s: %v", workload.GetNamespace(), workload.GetName(), err)
    81  	}
    82  
    83  	rel = vzapi.QualifiedResourceRelation{APIVersion: promoperapi.SchemeGroupVersion.String(), Kind: promoperapi.ServiceMonitorsKind, Namespace: serviceMonitor.Namespace, Name: serviceMonitor.Name, Role: scraperRole}
    84  	return rel, result, nil
    85  }
    86  
    87  // deleteServiceMonitor deletes the object responsible for transporting metrics from the source to Prometheus
    88  func (r *Reconciler) deleteServiceMonitor(ctx context.Context, namespace string, name string, trait *vzapi.MetricsTrait, log vzlog.VerrazzanoLogger) (controllerutil.OperationResult, error) {
    89  	if trait.DeletionTimestamp.IsZero() && isEnabled(trait) {
    90  		log.Debugf("Maintaining Service Monitor name: %s namespace: %s because the trait is enabled and not in the deletion process", name, namespace)
    91  		return controllerutil.OperationResultNone, nil
    92  	}
    93  
    94  	// If the trait is being deleted or is not enabled, delete the Service Monitor
    95  	log.Debugf("Deleting Service Monitor name: %s namespace: %s from resource relation", name, namespace)
    96  	serviceMonitor := promoperapi.ServiceMonitor{}
    97  	serviceMonitor.SetName(name)
    98  	serviceMonitor.SetNamespace(namespace)
    99  	if err := r.Delete(ctx, &serviceMonitor); err != nil {
   100  		return controllerutil.OperationResultNone, err
   101  	}
   102  	return controllerutil.OperationResultUpdated, nil
   103  }