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 }