diff --git a/agents/prometheusoperator/lib.go b/agents/prometheusoperator/lib.go index ab61934d..ba3a68e6 100644 --- a/agents/prometheusoperator/lib.go +++ b/agents/prometheusoperator/lib.go @@ -76,25 +76,33 @@ func (agent *PrometheusOperator) CreateOrUpdate(sp api.StatsAccessor, new *api.A in.Labels = meta_util.OverwriteKeys(sp.ServiceMonitorAdditionalLabels(), new.Prometheus.ServiceMonitor.Labels) core_util.EnsureOwnerReference(&in.ObjectMeta, owner) + in.Spec.TargetLabels = new.Prometheus.ServiceMonitor.TargetLabels + in.Spec.PodTargetLabels = new.Prometheus.ServiceMonitor.PodTargetLabels + in.Spec.NamespaceSelector = promapi.NamespaceSelector{ MatchNames: []string{sp.GetNamespace()}, } + podLabel := promapi.RelabelConfig{ + SourceLabels: []promapi.LabelName{"__meta_kubernetes_endpoint_address_target_name"}, + TargetLabel: "pod", + Action: "replace", + } for _, p := range svc.Spec.Ports { - in.Spec.Endpoints = upsertMonitoringEndpoint(in.Spec.Endpoints, promapi.Endpoint{ - Port: p.Name, - Interval: promapi.Duration(new.Prometheus.ServiceMonitor.Interval), - Path: sp.Path(), - HonorLabels: true, - Scheme: func() *promapi.Scheme { s := promapi.Scheme(sp.Scheme()); return &s }(), - TLSConfig: sp.TLSConfig(), - RelabelConfigs: []promapi.RelabelConfig{ - { - SourceLabels: []promapi.LabelName{"__meta_kubernetes_endpoint_address_target_name"}, - TargetLabel: "pod", - Action: "replace", - }, - }, - }) + ep := promapi.Endpoint{ + Port: p.Name, + Interval: promapi.Duration(new.Prometheus.ServiceMonitor.Interval), + Path: sp.Path(), + HonorLabels: true, + Scheme: func() *promapi.Scheme { s := promapi.Scheme(sp.Scheme()); return &s }(), + TLSConfig: sp.TLSConfig(), + RelabelConfigs: []promapi.RelabelConfig{podLabel}, + } + mep := findEndpoint(new.Prometheus.ServiceMonitor.Endpoints, ep.Port) + if mep != nil { + ep.RelabelConfigs = append([]promapi.RelabelConfig{podLabel}, mep.RelabelConfigs...) + ep.MetricRelabelConfigs = mep.MetricRelabelConfigs + } + in.Spec.Endpoints = upsertMonitoringEndpoint(in.Spec.Endpoints, ep) } in.Spec.Selector = metav1.LabelSelector{ MatchLabels: svc.Labels, @@ -105,6 +113,15 @@ func (agent *PrometheusOperator) CreateOrUpdate(sp api.StatsAccessor, new *api.A return vt, err } +func findEndpoint(endpoints []api.Endpoint, port string) *api.Endpoint { + for _, ep := range endpoints { + if ep.Port == port { + return &ep + } + } + return nil +} + func (agent *PrometheusOperator) Delete(sp api.StatsAccessor) (kutil.VerbType, error) { if !discovery.ExistsGroupKind(agent.k8sClient.Discovery(), promapi.SchemeGroupVersion.Group, promapi.ServiceMonitorsKind) { return kutil.VerbUnchanged, errors.New("cluster does not support Prometheus operator") diff --git a/api/v1/openapi_generated.go b/api/v1/openapi_generated.go index 4b26157a..887df742 100644 --- a/api/v1/openapi_generated.go +++ b/api/v1/openapi_generated.go @@ -36,6 +36,7 @@ func GetOpenAPIDefinitions(ref common.ReferenceCallback) map[string]common.OpenA "kmodules.xyz/monitoring-agent-api/api/v1.ClientConfig": schema_kmodulesxyz_monitoring_agent_api_api_v1_ClientConfig(ref), "kmodules.xyz/monitoring-agent-api/api/v1.ConnectionSpec": schema_kmodulesxyz_monitoring_agent_api_api_v1_ConnectionSpec(ref), "kmodules.xyz/monitoring-agent-api/api/v1.DashboardSpec": schema_kmodulesxyz_monitoring_agent_api_api_v1_DashboardSpec(ref), + "kmodules.xyz/monitoring-agent-api/api/v1.Endpoint": schema_kmodulesxyz_monitoring_agent_api_api_v1_Endpoint(ref), "kmodules.xyz/monitoring-agent-api/api/v1.GrafanaConfig": schema_kmodulesxyz_monitoring_agent_api_api_v1_GrafanaConfig(ref), "kmodules.xyz/monitoring-agent-api/api/v1.GrafanaContext": schema_kmodulesxyz_monitoring_agent_api_api_v1_GrafanaContext(ref), "kmodules.xyz/monitoring-agent-api/api/v1.MonitoringPresets": schema_kmodulesxyz_monitoring_agent_api_api_v1_MonitoringPresets(ref), @@ -266,6 +267,56 @@ func schema_kmodulesxyz_monitoring_agent_api_api_v1_DashboardSpec(ref common.Ref } } +func schema_kmodulesxyz_monitoring_agent_api_api_v1_Endpoint(ref common.ReferenceCallback) common.OpenAPIDefinition { + return common.OpenAPIDefinition{ + Schema: spec.Schema{ + SchemaProps: spec.SchemaProps{ + Description: "Endpoint defines an endpoint serving Prometheus metrics to be scraped by Prometheus.", + Type: []string{"object"}, + Properties: map[string]spec.Schema{ + "port": { + SchemaProps: spec.SchemaProps{ + Description: "port defines the name of the Service port which this endpoint refers to.\n\nIt takes precedence over `targetPort`.", + Type: []string{"string"}, + Format: "", + }, + }, + "metricRelabelings": { + SchemaProps: spec.SchemaProps{ + Description: "metricRelabelings defines the relabeling rules to apply to the samples before ingestion.", + Type: []string{"array"}, + Items: &spec.SchemaOrArray{ + Schema: &spec.Schema{ + SchemaProps: spec.SchemaProps{ + Default: map[string]interface{}{}, + Ref: ref("github.com/prometheus-operator/prometheus-operator/pkg/apis/monitoring/v1.RelabelConfig"), + }, + }, + }, + }, + }, + "relabelings": { + SchemaProps: spec.SchemaProps{ + Description: "relabelings defines the relabeling rules to apply the target's metadata labels.\n\nThe Operator automatically adds relabelings for a few standard Kubernetes fields.\n\nThe original scrape job's name is available via the `__tmp_prometheus_job_name` label.\n\nMore info: https://prometheus.io/docs/prometheus/latest/configuration/configuration/#relabel_config", + Type: []string{"array"}, + Items: &spec.SchemaOrArray{ + Schema: &spec.Schema{ + SchemaProps: spec.SchemaProps{ + Default: map[string]interface{}{}, + Ref: ref("github.com/prometheus-operator/prometheus-operator/pkg/apis/monitoring/v1.RelabelConfig"), + }, + }, + }, + }, + }, + }, + }, + }, + Dependencies: []string{ + "github.com/prometheus-operator/prometheus-operator/pkg/apis/monitoring/v1.RelabelConfig"}, + } +} + func schema_kmodulesxyz_monitoring_agent_api_api_v1_GrafanaConfig(ref common.ReferenceCallback) common.OpenAPIDefinition { return common.OpenAPIDefinition{ Schema: spec.Schema{ @@ -747,9 +798,56 @@ func schema_kmodulesxyz_monitoring_agent_api_api_v1_ServiceMonitorSpec(ref commo Format: "", }, }, + "targetLabels": { + SchemaProps: spec.SchemaProps{ + Description: "targetLabels defines the labels which are transferred from the associated Kubernetes `Service` object onto the ingested metrics.", + Type: []string{"array"}, + Items: &spec.SchemaOrArray{ + Schema: &spec.Schema{ + SchemaProps: spec.SchemaProps{ + Default: "", + Type: []string{"string"}, + Format: "", + }, + }, + }, + }, + }, + "podTargetLabels": { + SchemaProps: spec.SchemaProps{ + Description: "podTargetLabels defines the labels which are transferred from the associated Kubernetes `Pod` object onto the ingested metrics.", + Type: []string{"array"}, + Items: &spec.SchemaOrArray{ + Schema: &spec.Schema{ + SchemaProps: spec.SchemaProps{ + Default: "", + Type: []string{"string"}, + Format: "", + }, + }, + }, + }, + }, + "endpoints": { + SchemaProps: spec.SchemaProps{ + Description: "endpoints defines the list of endpoints part of this ServiceMonitor. Defines how to scrape metrics from Kubernetes [Endpoints](https://kubernetes.io/docs/concepts/services-networking/service/#endpoints) objects. In most cases, an Endpoints object is backed by a Kubernetes [Service](https://kubernetes.io/docs/concepts/services-networking/service/) object with the same name and labels.", + Type: []string{"array"}, + Items: &spec.SchemaOrArray{ + Schema: &spec.Schema{ + SchemaProps: spec.SchemaProps{ + Default: map[string]interface{}{}, + Ref: ref("kmodules.xyz/monitoring-agent-api/api/v1.Endpoint"), + }, + }, + }, + }, + }, }, + Required: []string{"endpoints"}, }, }, + Dependencies: []string{ + "kmodules.xyz/monitoring-agent-api/api/v1.Endpoint"}, } } diff --git a/api/v1/types.go b/api/v1/types.go index 31d26edc..4bd4a9d1 100644 --- a/api/v1/types.go +++ b/api/v1/types.go @@ -74,6 +74,53 @@ type ServiceMonitorSpec struct { // Interval at which metrics should be scraped // +optional Interval string `json:"interval,omitempty"` + + // targetLabels defines the labels which are transferred from the + // associated Kubernetes `Service` object onto the ingested metrics. + // + // +optional + TargetLabels []string `json:"targetLabels,omitempty"` + // podTargetLabels defines the labels which are transferred from the + // associated Kubernetes `Pod` object onto the ingested metrics. + // + // +optional + PodTargetLabels []string `json:"podTargetLabels,omitempty"` + + // endpoints defines the list of endpoints part of this ServiceMonitor. + // Defines how to scrape metrics from Kubernetes [Endpoints](https://kubernetes.io/docs/concepts/services-networking/service/#endpoints) objects. + // In most cases, an Endpoints object is backed by a Kubernetes [Service](https://kubernetes.io/docs/concepts/services-networking/service/) object with the same name and labels. + // +required + Endpoints []Endpoint `json:"endpoints"` +} + +// Endpoint defines an endpoint serving Prometheus metrics to be scraped by +// Prometheus. +// +// +k8s:openapi-gen=true +type Endpoint struct { + // port defines the name of the Service port which this endpoint refers to. + // + // It takes precedence over `targetPort`. + // +optional + Port string `json:"port,omitempty"` + + // metricRelabelings defines the relabeling rules to apply to the + // samples before ingestion. + // + // +optional + MetricRelabelConfigs []promapi.RelabelConfig `json:"metricRelabelings,omitempty"` + + // relabelings defines the relabeling rules to apply the target's + // metadata labels. + // + // The Operator automatically adds relabelings for a few standard Kubernetes fields. + // + // The original scrape job's name is available via the `__tmp_prometheus_job_name` label. + // + // More info: https://prometheus.io/docs/prometheus/latest/configuration/configuration/#relabel_config + // + // +optional + RelabelConfigs []promapi.RelabelConfig `json:"relabelings,omitempty"` } type PrometheusExporterSpec struct { diff --git a/api/v1/zz_generated.deepcopy.go b/api/v1/zz_generated.deepcopy.go index 39099e97..2c7644e1 100644 --- a/api/v1/zz_generated.deepcopy.go +++ b/api/v1/zz_generated.deepcopy.go @@ -24,6 +24,7 @@ package v1 import ( apiv1 "kmodules.xyz/client-go/api/v1" + monitoringv1 "github.com/prometheus-operator/prometheus-operator/pkg/apis/monitoring/v1" corev1 "k8s.io/api/core/v1" ) @@ -151,6 +152,36 @@ func (in *DashboardSpec) DeepCopy() *DashboardSpec { return out } +// DeepCopyInto is an autogenerated deepcopy function, copying the receiver, writing into out. in must be non-nil. +func (in *Endpoint) DeepCopyInto(out *Endpoint) { + *out = *in + if in.MetricRelabelConfigs != nil { + in, out := &in.MetricRelabelConfigs, &out.MetricRelabelConfigs + *out = make([]monitoringv1.RelabelConfig, len(*in)) + for i := range *in { + (*in)[i].DeepCopyInto(&(*out)[i]) + } + } + if in.RelabelConfigs != nil { + in, out := &in.RelabelConfigs, &out.RelabelConfigs + *out = make([]monitoringv1.RelabelConfig, len(*in)) + for i := range *in { + (*in)[i].DeepCopyInto(&(*out)[i]) + } + } + return +} + +// DeepCopy is an autogenerated deepcopy function, copying the receiver, creating a new Endpoint. +func (in *Endpoint) DeepCopy() *Endpoint { + if in == nil { + return nil + } + out := new(Endpoint) + in.DeepCopyInto(out) + return out +} + // DeepCopyInto is an autogenerated deepcopy function, copying the receiver, writing into out. in must be non-nil. func (in *GrafanaConfig) DeepCopyInto(out *GrafanaConfig) { *out = *in @@ -411,6 +442,23 @@ func (in *ServiceMonitorSpec) DeepCopyInto(out *ServiceMonitorSpec) { (*out)[key] = val } } + if in.TargetLabels != nil { + in, out := &in.TargetLabels, &out.TargetLabels + *out = make([]string, len(*in)) + copy(*out, *in) + } + if in.PodTargetLabels != nil { + in, out := &in.PodTargetLabels, &out.PodTargetLabels + *out = make([]string, len(*in)) + copy(*out, *in) + } + if in.Endpoints != nil { + in, out := &in.Endpoints, &out.Endpoints + *out = make([]Endpoint, len(*in)) + for i := range *in { + (*in)[i].DeepCopyInto(&(*out)[i]) + } + } return }