Book a Demo!
CoCalc Logo Icon
StoreFeaturesDocsShareSupportNewsAboutPoliciesSign UpSign In
aos
GitHub Repository: aos/grafana-agent
Path: blob/main/component/prometheus/operator/configgen/config_gen_servicemonitor.go
5403 views
1
package configgen
2
3
import (
4
"fmt"
5
"net/url"
6
"sort"
7
"strings"
8
9
promopv1 "github.com/prometheus-operator/prometheus-operator/pkg/apis/monitoring/v1"
10
namespacelabeler "github.com/prometheus-operator/prometheus-operator/pkg/namespace-labeler"
11
commonConfig "github.com/prometheus/common/config"
12
"github.com/prometheus/common/model"
13
"github.com/prometheus/prometheus/config"
14
promk8s "github.com/prometheus/prometheus/discovery/kubernetes"
15
"github.com/prometheus/prometheus/model/relabel"
16
metav1 "k8s.io/apimachinery/pkg/apis/meta/v1"
17
)
18
19
func (cg *ConfigGenerator) GenerateServiceMonitorConfig(m *promopv1.ServiceMonitor, ep promopv1.Endpoint, i int) (cfg *config.ScrapeConfig, err error) {
20
c := config.DefaultScrapeConfig
21
cfg = &c
22
23
cfg.ScrapeInterval = config.DefaultGlobalConfig.ScrapeInterval
24
cfg.ScrapeTimeout = config.DefaultGlobalConfig.ScrapeTimeout
25
cfg.JobName = fmt.Sprintf("serviceMonitor/%s/%s/%d", m.Namespace, m.Name, i)
26
cfg.HonorLabels = ep.HonorLabels
27
if ep.HonorTimestamps != nil {
28
cfg.HonorTimestamps = *ep.HonorTimestamps
29
}
30
dConfig := cg.generateK8SSDConfig(m.Spec.NamespaceSelector, m.Namespace, promk8s.RoleEndpoint, m.Spec.AttachMetadata)
31
cfg.ServiceDiscoveryConfigs = append(cfg.ServiceDiscoveryConfigs, dConfig)
32
33
if ep.Interval != "" {
34
if cfg.ScrapeInterval, err = model.ParseDuration(string(ep.Interval)); err != nil {
35
return nil, fmt.Errorf("parsing interval from serviceMonitor: %w", err)
36
}
37
}
38
if ep.ScrapeTimeout != "" {
39
if cfg.ScrapeTimeout, err = model.ParseDuration(string(ep.ScrapeTimeout)); err != nil {
40
return nil, fmt.Errorf("parsing timeout from serviceMonitor: %w", err)
41
}
42
}
43
if ep.Path != "" {
44
cfg.MetricsPath = ep.Path
45
}
46
if ep.ProxyURL != nil {
47
if u, err := url.Parse(*ep.ProxyURL); err != nil {
48
return nil, fmt.Errorf("parsing ProxyURL from serviceMonitor: %w", err)
49
} else {
50
cfg.HTTPClientConfig.ProxyURL = commonConfig.URL{URL: u}
51
}
52
}
53
if ep.Params != nil {
54
cfg.Params = ep.Params
55
}
56
if ep.Scheme != "" {
57
cfg.Scheme = ep.Scheme
58
}
59
if ep.FollowRedirects != nil {
60
cfg.HTTPClientConfig.FollowRedirects = *ep.FollowRedirects
61
}
62
if ep.EnableHttp2 != nil {
63
cfg.HTTPClientConfig.EnableHTTP2 = *ep.EnableHttp2
64
}
65
if ep.TLSConfig != nil {
66
if cfg.HTTPClientConfig.TLSConfig, err = cg.generateSafeTLS(ep.TLSConfig.SafeTLSConfig); err != nil {
67
return nil, err
68
}
69
}
70
if ep.BearerTokenSecret.Name != "" {
71
return nil, fmt.Errorf("bearer tokens in serviceMonitors not supported yet: %w", err)
72
}
73
if ep.BasicAuth != nil {
74
return nil, fmt.Errorf("basic auth in serviceMonitors not supported yet: %w", err)
75
}
76
// TODO: Add support for ep.OAuth2 and ep.Authorization
77
78
relabels := cg.initRelabelings()
79
80
// Filter targets by services selected by the monitor.
81
82
// Exact label matches.
83
var labelKeys []string
84
for k := range m.Spec.Selector.MatchLabels {
85
labelKeys = append(labelKeys, k)
86
}
87
sort.Strings(labelKeys)
88
for _, k := range labelKeys {
89
regex, err := relabel.NewRegexp(fmt.Sprintf("(%s);true", m.Spec.Selector.MatchLabels[k]))
90
if err != nil {
91
return nil, fmt.Errorf("parsing MatchLabels regex: %w", err)
92
}
93
relabels.add(&relabel.Config{
94
SourceLabels: model.LabelNames{"__meta_kubernetes_service_label_" + sanitizeLabelName(k), "__meta_kubernetes_service_labelpresent_" + sanitizeLabelName(k)},
95
Action: "keep",
96
Regex: regex,
97
})
98
}
99
100
// Set based label matching. We have to map the valid relations
101
// `In`, `NotIn`, `Exists`, and `DoesNotExist`, into relabeling rules.
102
for _, exp := range m.Spec.Selector.MatchExpressions {
103
switch exp.Operator {
104
case metav1.LabelSelectorOpIn:
105
regex, err := relabel.NewRegexp(fmt.Sprintf("(%s);true", strings.Join(exp.Values, "|")))
106
if err != nil {
107
return nil, fmt.Errorf("parsing MatchExpressions regex: %w", err)
108
}
109
relabels.add(&relabel.Config{
110
SourceLabels: model.LabelNames{"__meta_kubernetes_service_label_" + sanitizeLabelName(exp.Key), "__meta_kubernetes_service_labelpresent_" + sanitizeLabelName(exp.Key)},
111
Action: "keep",
112
Regex: regex,
113
})
114
case metav1.LabelSelectorOpNotIn:
115
regex, err := relabel.NewRegexp(fmt.Sprintf("(%s);true", strings.Join(exp.Values, "|")))
116
if err != nil {
117
return nil, fmt.Errorf("parsing MatchExpressions regex: %w", err)
118
}
119
relabels.add(&relabel.Config{
120
SourceLabels: model.LabelNames{"__meta_kubernetes_service_label_" + sanitizeLabelName(exp.Key), "__meta_kubernetes_service_labelpresent_" + sanitizeLabelName(exp.Key)},
121
Action: "drop",
122
Regex: regex,
123
})
124
case metav1.LabelSelectorOpExists:
125
relabels.add(&relabel.Config{
126
SourceLabels: model.LabelNames{"__meta_kubernetes_service_labelpresent_" + sanitizeLabelName(exp.Key)},
127
Action: "keep",
128
Regex: regexTrue,
129
})
130
case metav1.LabelSelectorOpDoesNotExist:
131
relabels.add(&relabel.Config{
132
SourceLabels: model.LabelNames{"__meta_kubernetes_service_labelpresent_" + sanitizeLabelName(exp.Key)},
133
Action: "drop",
134
Regex: regexTrue,
135
})
136
}
137
}
138
139
// Filter targets based on correct port for the endpoint.
140
if ep.Port != "" {
141
regex, err := relabel.NewRegexp(ep.Port)
142
if err != nil {
143
return nil, fmt.Errorf("parsing Port as regex: %w", err)
144
}
145
relabels.add(&relabel.Config{
146
SourceLabels: model.LabelNames{"__meta_kubernetes_endpoint_port_name"},
147
Action: "keep",
148
Regex: regex,
149
})
150
} else if ep.TargetPort != nil { //nolint:staticcheck // Ignore SA1019 this field is marked as deprecated.
151
//nolint:staticcheck // Ignore SA1019 this field is marked as deprecated.
152
regex, err := relabel.NewRegexp(ep.TargetPort.String())
153
if err != nil {
154
return nil, fmt.Errorf("parsing TargetPort as regex: %w", err)
155
}
156
if ep.TargetPort.StrVal != "" {
157
relabels.add(&relabel.Config{
158
SourceLabels: model.LabelNames{"__meta_kubernetes_pod_container_port_name"},
159
Action: "keep",
160
Regex: regex,
161
})
162
}
163
} else if ep.TargetPort.IntVal != 0 { //nolint:staticcheck // Ignore SA1019 this field is marked as deprecated.
164
regex, err := relabel.NewRegexp(ep.TargetPort.String()) //nolint:staticcheck // Ignore SA1019 this field is marked as deprecated.
165
if err != nil {
166
return nil, fmt.Errorf("parsing TargetPort as regex: %w", err)
167
}
168
relabels.add(&relabel.Config{
169
SourceLabels: model.LabelNames{"__meta_kubernetes_pod_container_port_number"},
170
Action: "keep",
171
Regex: regex,
172
})
173
}
174
175
sourceLabels := model.LabelNames{"__meta_kubernetes_endpoint_address_target_kind", "__meta_kubernetes_endpoint_address_target_name"}
176
// Relabel namespace and pod and service labels into proper labels.
177
// Relabel node labels with meta labels available with Prometheus >= v2.3.
178
relabels.add(&relabel.Config{
179
SourceLabels: sourceLabels,
180
Separator: ";",
181
Regex: regexNode,
182
Replacement: "${1}",
183
TargetLabel: "node",
184
})
185
// Relabel pod labels for >=v2.3 meta labels
186
relabels.add(&relabel.Config{
187
SourceLabels: sourceLabels,
188
Separator: ";",
189
Regex: regexPod,
190
Replacement: "${1}",
191
TargetLabel: "pod",
192
})
193
relabels.add(&relabel.Config{
194
SourceLabels: model.LabelNames{"__meta_kubernetes_namespace"},
195
TargetLabel: "namespace",
196
}, &relabel.Config{
197
SourceLabels: model.LabelNames{"__meta_kubernetes_service_name"},
198
TargetLabel: "service",
199
}, &relabel.Config{
200
SourceLabels: model.LabelNames{"__meta_kubernetes_pod_container_name"},
201
TargetLabel: "container",
202
}, &relabel.Config{
203
SourceLabels: model.LabelNames{"__meta_kubernetes_pod_name"},
204
TargetLabel: "pod",
205
})
206
207
if ep.FilterRunning == nil || *ep.FilterRunning {
208
relabels.add(&relabel.Config{
209
SourceLabels: model.LabelNames{"__meta_kubernetes_pod_phase"},
210
Action: "drop",
211
Regex: regexFilterRunning,
212
})
213
}
214
// Relabel targetLabels from Service onto target.
215
for _, l := range m.Spec.TargetLabels {
216
relabels.add(&relabel.Config{
217
SourceLabels: model.LabelNames{"__meta_kubernetes_service_label_" + sanitizeLabelName(l)},
218
Replacement: "${1}",
219
Regex: regexAnything,
220
TargetLabel: string(sanitizeLabelName(l)),
221
})
222
}
223
for _, l := range m.Spec.PodTargetLabels {
224
relabels.add(&relabel.Config{
225
SourceLabels: model.LabelNames{"__meta_kubernetes_pod_label_" + sanitizeLabelName(l)},
226
Replacement: "${1}",
227
Regex: regexAnything,
228
TargetLabel: string(sanitizeLabelName(l)),
229
})
230
}
231
232
// By default, generate a safe job name from the service name. We also keep
233
// this around if a jobLabel is set in case the targets don't actually have a
234
// value for it.
235
236
relabels.add(&relabel.Config{
237
SourceLabels: model.LabelNames{"__meta_kubernetes_service_name"},
238
Replacement: "${1}",
239
TargetLabel: "job",
240
})
241
if m.Spec.JobLabel != "" {
242
relabels.add(&relabel.Config{
243
Replacement: "${1}",
244
TargetLabel: "job",
245
Regex: regexAnything,
246
SourceLabels: model.LabelNames{"__meta_kubernetes_service_label_" + sanitizeLabelName(m.Spec.JobLabel)},
247
})
248
}
249
250
// A single service may potentially have multiple metrics
251
// endpoints, therefore the endpoints labels is filled with the ports name or
252
// as a fallback the port number.
253
254
if ep.Port != "" {
255
relabels.add(&relabel.Config{
256
Replacement: ep.Port,
257
TargetLabel: "endpoint",
258
})
259
} else if ep.TargetPort != nil && ep.TargetPort.String() != "" {
260
relabels.add(&relabel.Config{
261
TargetLabel: "endpoint",
262
Replacement: ep.TargetPort.String(),
263
})
264
}
265
266
labeler := namespacelabeler.New("", nil, false)
267
err = relabels.addFromV1(labeler.GetRelabelingConfigs(m.TypeMeta, m.ObjectMeta, ep.RelabelConfigs)...)
268
if err != nil {
269
return nil, err
270
}
271
cfg.RelabelConfigs = relabels.configs
272
273
metricRelabels := relabeler{}
274
err = metricRelabels.addFromV1(labeler.GetRelabelingConfigs(m.TypeMeta, m.ObjectMeta, ep.MetricRelabelConfigs)...)
275
if err != nil {
276
return nil, err
277
}
278
cfg.MetricRelabelConfigs = metricRelabels.configs
279
280
cfg.SampleLimit = uint(m.Spec.SampleLimit)
281
cfg.TargetLimit = uint(m.Spec.TargetLimit)
282
cfg.LabelLimit = uint(m.Spec.LabelLimit)
283
cfg.LabelNameLengthLimit = uint(m.Spec.LabelNameLengthLimit)
284
cfg.LabelValueLengthLimit = uint(m.Spec.LabelValueLengthLimit)
285
286
return cfg, nil
287
}
288
289