Skip to content

Commit 2e21682

Browse files
authored
fix: decode Prometheus scrape path from Kuberentes labels (#9662)
1 parent d729c0a commit 2e21682

2 files changed

Lines changed: 61 additions & 40 deletions

File tree

plugins/inputs/prometheus/kubernetes.go

Lines changed: 29 additions & 30 deletions
Original file line numberDiff line numberDiff line change
@@ -5,7 +5,6 @@ import (
55
"crypto/tls"
66
"encoding/json"
77
"fmt"
8-
"log"
98
"net"
109
"net/http"
1110
"net/url"
@@ -295,12 +294,15 @@ func registerPod(pod *corev1.Pod, p *Prometheus) {
295294
if p.kubernetesPods == nil {
296295
p.kubernetesPods = map[string]URLAndAddress{}
297296
}
298-
targetURL := getScrapeURL(pod)
299-
if targetURL == nil {
297+
targetURL, err := getScrapeURL(pod)
298+
if err != nil {
299+
p.Log.Errorf("could not parse URL: %s", err)
300+
return
301+
} else if targetURL == nil {
300302
return
301303
}
302304

303-
log.Printf("D! [inputs.prometheus] will scrape metrics from %q", *targetURL)
305+
p.Log.Debugf("will scrape metrics from %q", targetURL.String())
304306
// add annotation as metrics tags
305307
tags := pod.Annotations
306308
if tags == nil {
@@ -312,12 +314,7 @@ func registerPod(pod *corev1.Pod, p *Prometheus) {
312314
for k, v := range pod.Labels {
313315
tags[k] = v
314316
}
315-
URL, err := url.Parse(*targetURL)
316-
if err != nil {
317-
log.Printf("E! [inputs.prometheus] could not parse URL %q: %s", *targetURL, err.Error())
318-
return
319-
}
320-
podURL := p.AddressToURL(URL, URL.Hostname())
317+
podURL := p.AddressToURL(targetURL, targetURL.Hostname())
321318

322319
// Locks earlier if using cAdvisor calls - makes a new list each time
323320
// rather than updating and removing from the same list
@@ -327,22 +324,22 @@ func registerPod(pod *corev1.Pod, p *Prometheus) {
327324
}
328325
p.kubernetesPods[podURL.String()] = URLAndAddress{
329326
URL: podURL,
330-
Address: URL.Hostname(),
331-
OriginalURL: URL,
327+
Address: targetURL.Hostname(),
328+
OriginalURL: targetURL,
332329
Tags: tags,
333330
}
334331
}
335332

336-
func getScrapeURL(pod *corev1.Pod) *string {
333+
func getScrapeURL(pod *corev1.Pod) (*url.URL, error) {
337334
ip := pod.Status.PodIP
338335
if ip == "" {
339336
// return as if scrape was disabled, we will be notified again once the pod
340337
// has an IP
341-
return nil
338+
return nil, nil
342339
}
343340

344341
scheme := pod.Annotations["prometheus.io/scheme"]
345-
path := pod.Annotations["prometheus.io/path"]
342+
pathAndQuery := pod.Annotations["prometheus.io/path"]
346343
port := pod.Annotations["prometheus.io/port"]
347344

348345
if scheme == "" {
@@ -351,34 +348,36 @@ func getScrapeURL(pod *corev1.Pod) *string {
351348
if port == "" {
352349
port = "9102"
353350
}
354-
if path == "" {
355-
path = "/metrics"
351+
if pathAndQuery == "" {
352+
pathAndQuery = "/metrics"
356353
}
357354

358-
u := &url.URL{
359-
Scheme: scheme,
360-
Host: net.JoinHostPort(ip, port),
361-
Path: path,
355+
base, err := url.Parse(pathAndQuery)
356+
if err != nil {
357+
return nil, err
362358
}
363359

364-
x := u.String()
360+
base.Scheme = scheme
361+
base.Host = net.JoinHostPort(ip, port)
365362

366-
return &x
363+
return base, nil
367364
}
368365

369366
func unregisterPod(pod *corev1.Pod, p *Prometheus) {
370-
url := getScrapeURL(pod)
371-
if url == nil {
367+
targetURL, err := getScrapeURL(pod)
368+
if err != nil {
369+
p.Log.Errorf("failed to parse url: %s", err)
370+
return
371+
} else if targetURL == nil {
372372
return
373373
}
374374

375-
log.Printf("D! [inputs.prometheus] registered a delete request for %q in namespace %q",
376-
pod.Name, pod.Namespace)
375+
p.Log.Debugf("registered a delete request for %q in namespace %q", pod.Name, pod.Namespace)
377376

378377
p.lock.Lock()
379378
defer p.lock.Unlock()
380-
if _, ok := p.kubernetesPods[*url]; ok {
381-
delete(p.kubernetesPods, *url)
382-
log.Printf("D! [inputs.prometheus] will stop scraping for %q", *url)
379+
if _, ok := p.kubernetesPods[targetURL.String()]; ok {
380+
delete(p.kubernetesPods, targetURL.String())
381+
p.Log.Debugf("will stop scraping for %q", targetURL.String())
383382
}
384383
}

plugins/inputs/prometheus/kubernetes_test.go

Lines changed: 32 additions & 10 deletions
Original file line numberDiff line numberDiff line change
@@ -15,44 +15,66 @@ import (
1515
func TestScrapeURLNoAnnotations(t *testing.T) {
1616
p := &corev1.Pod{ObjectMeta: metav1.ObjectMeta{}}
1717
p.Annotations = map[string]string{}
18-
url := getScrapeURL(p)
18+
url, err := getScrapeURL(p)
19+
assert.NoError(t, err)
1920
assert.Nil(t, url)
2021
}
2122

2223
func TestScrapeURLAnnotationsNoScrape(t *testing.T) {
2324
p := &corev1.Pod{ObjectMeta: metav1.ObjectMeta{}}
2425
p.Name = "myPod"
2526
p.Annotations = map[string]string{"prometheus.io/scrape": "false"}
26-
url := getScrapeURL(p)
27+
url, err := getScrapeURL(p)
28+
assert.NoError(t, err)
2729
assert.Nil(t, url)
2830
}
2931

3032
func TestScrapeURLAnnotations(t *testing.T) {
3133
p := pod()
3234
p.Annotations = map[string]string{"prometheus.io/scrape": "true"}
33-
url := getScrapeURL(p)
34-
assert.Equal(t, "http://127.0.0.1:9102/metrics", *url)
35+
url, err := getScrapeURL(p)
36+
assert.NoError(t, err)
37+
assert.Equal(t, "http://127.0.0.1:9102/metrics", url.String())
3538
}
3639

3740
func TestScrapeURLAnnotationsCustomPort(t *testing.T) {
3841
p := pod()
3942
p.Annotations = map[string]string{"prometheus.io/scrape": "true", "prometheus.io/port": "9000"}
40-
url := getScrapeURL(p)
41-
assert.Equal(t, "http://127.0.0.1:9000/metrics", *url)
43+
url, err := getScrapeURL(p)
44+
assert.NoError(t, err)
45+
assert.Equal(t, "http://127.0.0.1:9000/metrics", url.String())
4246
}
4347

4448
func TestScrapeURLAnnotationsCustomPath(t *testing.T) {
4549
p := pod()
4650
p.Annotations = map[string]string{"prometheus.io/scrape": "true", "prometheus.io/path": "mymetrics"}
47-
url := getScrapeURL(p)
48-
assert.Equal(t, "http://127.0.0.1:9102/mymetrics", *url)
51+
url, err := getScrapeURL(p)
52+
assert.NoError(t, err)
53+
assert.Equal(t, "http://127.0.0.1:9102/mymetrics", url.String())
4954
}
5055

5156
func TestScrapeURLAnnotationsCustomPathWithSep(t *testing.T) {
5257
p := pod()
5358
p.Annotations = map[string]string{"prometheus.io/scrape": "true", "prometheus.io/path": "/mymetrics"}
54-
url := getScrapeURL(p)
55-
assert.Equal(t, "http://127.0.0.1:9102/mymetrics", *url)
59+
url, err := getScrapeURL(p)
60+
assert.NoError(t, err)
61+
assert.Equal(t, "http://127.0.0.1:9102/mymetrics", url.String())
62+
}
63+
64+
func TestScrapeURLAnnotationsCustomPathWithQueryParameters(t *testing.T) {
65+
p := pod()
66+
p.Annotations = map[string]string{"prometheus.io/scrape": "true", "prometheus.io/path": "/v1/agent/metrics?format=prometheus"}
67+
url, err := getScrapeURL(p)
68+
assert.NoError(t, err)
69+
assert.Equal(t, "http://127.0.0.1:9102/v1/agent/metrics?format=prometheus", url.String())
70+
}
71+
72+
func TestScrapeURLAnnotationsCustomPathWithFragment(t *testing.T) {
73+
p := pod()
74+
p.Annotations = map[string]string{"prometheus.io/scrape": "true", "prometheus.io/path": "/v1/agent/metrics#prometheus"}
75+
url, err := getScrapeURL(p)
76+
assert.NoError(t, err)
77+
assert.Equal(t, "http://127.0.0.1:9102/v1/agent/metrics#prometheus", url.String())
5678
}
5779

5880
func TestAddPod(t *testing.T) {

0 commit comments

Comments
 (0)