Skip to content

Commit

Permalink
fix: decode Prometheus scrape path from Kuberentes labels (#9662)
Browse files Browse the repository at this point in the history
(cherry picked from commit 2e21682)
  • Loading branch information
akrantz01 authored and powersj committed Oct 27, 2021
1 parent caec878 commit 5ffaa60
Show file tree
Hide file tree
Showing 2 changed files with 61 additions and 40 deletions.
59 changes: 29 additions & 30 deletions plugins/inputs/prometheus/kubernetes.go
Original file line number Diff line number Diff line change
Expand Up @@ -5,7 +5,6 @@ import (
"crypto/tls"
"encoding/json"
"fmt"
"log"
"net"
"net/http"
"net/url"
Expand Down Expand Up @@ -295,12 +294,15 @@ func registerPod(pod *corev1.Pod, p *Prometheus) {
if p.kubernetesPods == nil {
p.kubernetesPods = map[string]URLAndAddress{}
}
targetURL := getScrapeURL(pod)
if targetURL == nil {
targetURL, err := getScrapeURL(pod)
if err != nil {
p.Log.Errorf("could not parse URL: %s", err)
return
} else if targetURL == nil {
return
}

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

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

func getScrapeURL(pod *corev1.Pod) *string {
func getScrapeURL(pod *corev1.Pod) (*url.URL, error) {
ip := pod.Status.PodIP
if ip == "" {
// return as if scrape was disabled, we will be notified again once the pod
// has an IP
return nil
return nil, nil
}

scheme := pod.Annotations["prometheus.io/scheme"]
path := pod.Annotations["prometheus.io/path"]
pathAndQuery := pod.Annotations["prometheus.io/path"]
port := pod.Annotations["prometheus.io/port"]

if scheme == "" {
Expand All @@ -351,34 +348,36 @@ func getScrapeURL(pod *corev1.Pod) *string {
if port == "" {
port = "9102"
}
if path == "" {
path = "/metrics"
if pathAndQuery == "" {
pathAndQuery = "/metrics"
}

u := &url.URL{
Scheme: scheme,
Host: net.JoinHostPort(ip, port),
Path: path,
base, err := url.Parse(pathAndQuery)
if err != nil {
return nil, err
}

x := u.String()
base.Scheme = scheme
base.Host = net.JoinHostPort(ip, port)

return &x
return base, nil
}

func unregisterPod(pod *corev1.Pod, p *Prometheus) {
url := getScrapeURL(pod)
if url == nil {
targetURL, err := getScrapeURL(pod)
if err != nil {
p.Log.Errorf("failed to parse url: %s", err)
return
} else if targetURL == nil {
return
}

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

p.lock.Lock()
defer p.lock.Unlock()
if _, ok := p.kubernetesPods[*url]; ok {
delete(p.kubernetesPods, *url)
log.Printf("D! [inputs.prometheus] will stop scraping for %q", *url)
if _, ok := p.kubernetesPods[targetURL.String()]; ok {
delete(p.kubernetesPods, targetURL.String())
p.Log.Debugf("will stop scraping for %q", targetURL.String())
}
}
42 changes: 32 additions & 10 deletions plugins/inputs/prometheus/kubernetes_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -15,44 +15,66 @@ import (
func TestScrapeURLNoAnnotations(t *testing.T) {
p := &corev1.Pod{ObjectMeta: metav1.ObjectMeta{}}
p.Annotations = map[string]string{}
url := getScrapeURL(p)
url, err := getScrapeURL(p)
assert.NoError(t, err)
assert.Nil(t, url)
}

func TestScrapeURLAnnotationsNoScrape(t *testing.T) {
p := &corev1.Pod{ObjectMeta: metav1.ObjectMeta{}}
p.Name = "myPod"
p.Annotations = map[string]string{"prometheus.io/scrape": "false"}
url := getScrapeURL(p)
url, err := getScrapeURL(p)
assert.NoError(t, err)
assert.Nil(t, url)
}

func TestScrapeURLAnnotations(t *testing.T) {
p := pod()
p.Annotations = map[string]string{"prometheus.io/scrape": "true"}
url := getScrapeURL(p)
assert.Equal(t, "http://127.0.0.1:9102/metrics", *url)
url, err := getScrapeURL(p)
assert.NoError(t, err)
assert.Equal(t, "http://127.0.0.1:9102/metrics", url.String())
}

func TestScrapeURLAnnotationsCustomPort(t *testing.T) {
p := pod()
p.Annotations = map[string]string{"prometheus.io/scrape": "true", "prometheus.io/port": "9000"}
url := getScrapeURL(p)
assert.Equal(t, "http://127.0.0.1:9000/metrics", *url)
url, err := getScrapeURL(p)
assert.NoError(t, err)
assert.Equal(t, "http://127.0.0.1:9000/metrics", url.String())
}

func TestScrapeURLAnnotationsCustomPath(t *testing.T) {
p := pod()
p.Annotations = map[string]string{"prometheus.io/scrape": "true", "prometheus.io/path": "mymetrics"}
url := getScrapeURL(p)
assert.Equal(t, "http://127.0.0.1:9102/mymetrics", *url)
url, err := getScrapeURL(p)
assert.NoError(t, err)
assert.Equal(t, "http://127.0.0.1:9102/mymetrics", url.String())
}

func TestScrapeURLAnnotationsCustomPathWithSep(t *testing.T) {
p := pod()
p.Annotations = map[string]string{"prometheus.io/scrape": "true", "prometheus.io/path": "/mymetrics"}
url := getScrapeURL(p)
assert.Equal(t, "http://127.0.0.1:9102/mymetrics", *url)
url, err := getScrapeURL(p)
assert.NoError(t, err)
assert.Equal(t, "http://127.0.0.1:9102/mymetrics", url.String())
}

func TestScrapeURLAnnotationsCustomPathWithQueryParameters(t *testing.T) {
p := pod()
p.Annotations = map[string]string{"prometheus.io/scrape": "true", "prometheus.io/path": "/v1/agent/metrics?format=prometheus"}
url, err := getScrapeURL(p)
assert.NoError(t, err)
assert.Equal(t, "http://127.0.0.1:9102/v1/agent/metrics?format=prometheus", url.String())
}

func TestScrapeURLAnnotationsCustomPathWithFragment(t *testing.T) {
p := pod()
p.Annotations = map[string]string{"prometheus.io/scrape": "true", "prometheus.io/path": "/v1/agent/metrics#prometheus"}
url, err := getScrapeURL(p)
assert.NoError(t, err)
assert.Equal(t, "http://127.0.0.1:9102/v1/agent/metrics#prometheus", url.String())
}

func TestAddPod(t *testing.T) {
Expand Down

0 comments on commit 5ffaa60

Please sign in to comment.