Skip to content

Commit f5c618c

Browse files
authored
Merge pull request #136 from chrroberts-pure/requestid
Support passing the HTTP Header X-Request-ID into Purity API requests
2 parents f0153d3 + d866b43 commit f5c618c

Some content is hidden

Large Commits have some content hidden by default. Use the searchbox below for content that may be hidden.

51 files changed

+274
-247
lines changed

Makefile

Lines changed: 3 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -4,6 +4,7 @@ GOTEST=$(GOCMD) test
44
GOVET=$(GOCMD) vet
55
BINARY_NAME=pure-fa-om-exporter
66
MODULE_NAME=purestorage/fa-openmetrics-exporter
7+
UserAgentBase=Pure_FA_OpenMetrics_exporter
78
VERSION?=1.0.18
89
SERVICE_PORT?=9490
910
DOCKER_REGISTRY?= quay.io/purestorage/
@@ -26,11 +27,11 @@ init:
2627

2728
build: ## Build project and put the output binary in out/bin/
2829
mkdir -p out/bin
29-
CGO_ENABLED=0 GO111MODULE=on $(GOCMD) build -a -mod=readonly -tags 'netgo osusergo static_build' -ldflags="-X 'main.version=v$(VERSION)' -X 'purestorage/fa-openmetrics-exporter/internal/rest-client.UserAgentVersion=$(VERSION)'" -o out/bin/$(BINARY_NAME) cmd/fa-om-exporter/main.go
30+
CGO_ENABLED=0 GO111MODULE=on $(GOCMD) build -a -mod=readonly -tags 'netgo osusergo static_build' -ldflags="-X 'main.version=v$(VERSION)' -X 'purestorage/fa-openmetrics-exporter/internal/rest-client.UserAgentVersion=$(VERSION)' -X 'purestorage/fa-openmetrics-exporter/internal/rest-client.FARestUserAgentBase=$(UserAgentBase)'" -o out/bin/$(BINARY_NAME) cmd/fa-om-exporter/main.go
3031

3132
build-with-vendor: ## Build project using the vendor directory and put the output binary in out/bin/
3233
mkdir -p out/bin
33-
CGO_ENABLED=0 GO111MODULE=on $(GOCMD) build -a -mod=vendor -tags 'netgo osusergo static_build' -ldflags="-X 'main.version=v$(VERSION)' -X 'purestorage/fa-openmetrics-exporter/internal/rest-client.UserAgentVersion=$(VERSION)'" -o out/bin/$(BINARY_NAME) cmd/fa-om-exporter/main.go
34+
CGO_ENABLED=0 GO111MODULE=on $(GOCMD) build -a -mod=vendor -tags 'netgo osusergo static_build' -ldflags="-X 'main.version=v$(VERSION)' -X 'purestorage/fa-openmetrics-exporter/internal/rest-client.UserAgentVersion=$(VERSION)' -X 'purestorage/fa-openmetrics-exporter/internal/rest-client.FARestUserAgentBase=$(UserAgentBase)'" -o out/bin/$(BINARY_NAME) cmd/fa-om-exporter/main.go
3435

3536
clean: ## Remove build related file
3637
rm -fr ./bin

README.md

Lines changed: 6 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -91,6 +91,12 @@ The second option provides the FlashArray/api-token key-pair map for a list of a
9191

9292
The exporter can be started in TLS mode (HTTPS, mutually exclusive with the HTTP mode) by providing the X.509 certificate and key files in the command parameters. Self-signed certificates are also accepted.
9393

94+
### Supported Headers
95+
96+
#### X-Request-ID (Optional)
97+
98+
The `X-Request-ID` Header, as used in the Purity API, may be used when calling the OpenMetrics exporter by using the HTTP Header `X-Request-ID`. It will then be passed and used when requesting metrics from the Purity API.
99+
94100
### Usage
95101

96102
```shell

build/docker/Dockerfile

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,6 @@
11
FROM golang:alpine as build
22
ARG VERSION=1.0.18
3+
ARG UserAgentBase=Pure_FA_OpenMetrics_exporter
34

45
WORKDIR /usr/src/app
56

@@ -9,7 +10,7 @@ RUN go mod download && go mod verify
910

1011
COPY . .
1112

12-
RUN CGO_ENABLED=1 go build -mod=readonly -a -tags 'netgo osusergo static_build' -ldflags="-X 'main.version=v$VERSION' -X 'purestorage/fa-openmetrics-exporter/internal/rest-client.UserAgentVersion=$VERSION'" -v -o /usr/local/bin/pure-fa-om-exporter cmd/fa-om-exporter/main.go
13+
RUN CGO_ENABLED=1 go build -mod=readonly -a -tags 'netgo osusergo static_build' -ldflags="-X 'main.version=v$VERSION' -X 'purestorage/fa-openmetrics-exporter/internal/rest-client.FARestUserAgentBase=$UserAgentBase' -X 'purestorage/fa-openmetrics-exporter/internal/rest-client.UserAgentVersion=$VERSION'" -v -o /usr/local/bin/pure-fa-om-exporter cmd/fa-om-exporter/main.go
1314

1415

1516
# alpine is used here as it seems to be the minimal image that passes quay.io vulnerability scan

cmd/fa-om-exporter/main.go

Lines changed: 14 additions & 12 deletions
Original file line numberDiff line numberDiff line change
@@ -28,11 +28,11 @@ func fileExists(args []string) error {
2828
}
2929

3030
func isFile(filename string) bool {
31-
info, err := os.Stat(filename)
32-
if os.IsNotExist(err) {
33-
return false
34-
}
35-
return !info.IsDir()
31+
info, err := os.Stat(filename)
32+
if os.IsNotExist(err) {
33+
return false
34+
}
35+
return !info.IsDir()
3636
}
3737

3838
func main() {
@@ -72,14 +72,14 @@ func main() {
7272
}
7373
if (len(*cert) > 0 && len(*key) == 0) || (len(*cert) == 0 && len(*key) > 0) {
7474
log.Fatal("Both certificate and key must be specified to enable TLS")
75-
}
76-
if (len(*cert) > 0 && len(*key) > 0) {
75+
}
76+
if len(*cert) > 0 && len(*key) > 0 {
7777
if !isFile(*cert) {
7878
log.Fatal("TLS cert file not found")
79-
} else if !isFile (*key) {
79+
} else if !isFile(*key) {
8080
log.Fatal("TLS key file not found")
8181
}
82-
}
82+
}
8383
debug = *d
8484
addr := fmt.Sprintf("%s:%d", *host, *port)
8585
log.Printf("Start Pure FlashArray exporter %s on %s", version, addr)
@@ -143,16 +143,18 @@ func metricsHandler(w http.ResponseWriter, r *http.Request) {
143143
address, apitoken := arraytokens.GetArrayParams(endpoint)
144144
if len(authFields) == 2 && strings.ToLower(authFields[0]) == "bearer" {
145145
apitoken = authFields[1]
146-
address = endpoint
146+
address = endpoint
147147
}
148148
if apitoken == "" {
149149
http.Error(w, "Target authorization token is missing", http.StatusBadRequest)
150150
return
151151
}
152152

153-
uagent := r.Header.Get("User-Agent")
153+
uagent := r.Header.Get("User-Agent")
154+
rid := r.Header.Get("X-Request-ID")
155+
154156
registry := prometheus.NewRegistry()
155-
faclient := client.NewRestClient(address, apitoken, apiver, uagent, debug)
157+
faclient := client.NewRestClient(address, apitoken, apiver, uagent, rid, debug)
156158
if faclient.Error != nil {
157159
http.Error(w, "Error connecting to FlashArray. Check your management endpoint and/or api token are correct.", http.StatusBadRequest)
158160
return

internal/openmetrics-exporter/alerts_collector_test.go

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -52,7 +52,7 @@ func TestAlertsCollector(t *testing.T) {
5252

5353
want[fmt.Sprintf("label:{name:\"category\" value:\"%s\"} label:{name:\"code\" value:\"%s\"} label:{name:\"component_type\" value:\"%s\"} label:{name:\"created\" value:\"%s\"} label:{name:\"issue\" value:\"%s\"} label:{name:\"name\" value:\"%s\"} label:{name:\"severity\" value:\"%s\"} label:{name:\"summary\" value:\"%s\"} gauge:{value:%g}", alert[0], alert[1], alert[2], alert[3], alert[4], alert[5], alert[6], alert[7], n)] = true
5454
}
55-
c := client.NewRestClient(e, "fake-api-token", "latest", "test-user-agent-string", false)
55+
c := client.NewRestClient(e, "fake-api-token", "latest", "test-user-agent-string", "test-X-Request-Id-string", false)
5656
ac := NewAlertsCollector(c)
5757
metricsCheck(t, ac, want)
5858
server.Close()

internal/openmetrics-exporter/arrays_collector_test.go

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -49,7 +49,7 @@ func TestArraysCollector(t *testing.T) {
4949

5050
want[fmt.Sprintf("label:{name:\"array_name\" value:\"%s\"} label:{name:\"os\" value:\"%s\"} label:{name:\"subscription_type\" value:\"%s\"} label:{name:\"system_id\" value:\"%s\"} label:{name:\"version\" value:\"%s\"} gauge:{value:1}", a.Name, a.Os, s.Service, a.Id, a.Version)] = true
5151

52-
c := client.NewRestClient(e, "fake-api-token", "latest", "test-user-agent-string", false)
52+
c := client.NewRestClient(e, "fake-api-token", "latest", "test-user-agent-string", "test-X-Request-Id-string", false)
5353
ac := NewArraysCollector(c)
5454
metricsCheck(t, ac, want)
5555
server.Close()

internal/openmetrics-exporter/arrays_controllers_collector_test.go

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -39,7 +39,8 @@ func TestArrayControllersCollector(t *testing.T) {
3939
want[fmt.Sprintf("label:{name:\"mode\" value:\"%s\"} label:{name:\"model\"value:\"%s\"} label:{name:\"name\" value:\"%s\"} label:{name:\"status\" value:\"%s\"} label:{name:\"type\" value:\"%s\"} label:{name:\"version\" value:\"%s\"} gauge:{value:\"%g\"}", ctl.Mode, ctl.Model, ctl.Name, ctl.Status, ctl.Type, ctl.Version, (float64(ctl.ModeSince)/1000))] = true
4040
}
4141

42-
c := client.NewRestClient(e, "fake-api-token", "latest", "test-user-agent-string", false)
42+
c := client.NewRestClient(e, "fake-api-token", "latest", "test-user-agent-string", "test-X-Request-Id-string", false)
43+
4344
dc := NewControllersCollector(c)
4445
metricsCheck(t, dc, want)
4546
server.Close()

internal/openmetrics-exporter/arrays_performance_collector_test.go

Lines changed: 15 additions & 15 deletions
Original file line numberDiff line numberDiff line change
@@ -1,17 +1,16 @@
11
package collectors
22

3-
43
import (
4+
"encoding/json"
55
"fmt"
6-
"testing"
7-
"regexp"
8-
"strings"
96
"net/http"
107
"net/http/httptest"
11-
"encoding/json"
128
"os"
9+
"regexp"
10+
"strings"
11+
"testing"
1312

14-
"purestorage/fa-openmetrics-exporter/internal/rest-client"
13+
client "purestorage/fa-openmetrics-exporter/internal/rest-client"
1514
)
1615

1716
func TestArrayPerformanceCollector(t *testing.T) {
@@ -23,16 +22,16 @@ func TestArrayPerformanceCollector(t *testing.T) {
2322
server := httptest.NewTLSServer(http.HandlerFunc(func(w http.ResponseWriter, r *http.Request) {
2423
valid := regexp.MustCompile(`^/api/([0-9]+.[0-9]+)?/arrays/performance$`)
2524
if r.URL.Path == "/api/api_version" {
26-
w.Header().Set("Content-Type", "application/json")
27-
w.WriteHeader(http.StatusOK)
28-
w.Write([]byte(vers))
25+
w.Header().Set("Content-Type", "application/json")
26+
w.WriteHeader(http.StatusOK)
27+
w.Write([]byte(vers))
2928
} else if valid.MatchString(r.URL.Path) {
30-
w.Header().Set("x-auth-token", "faketoken")
31-
w.Header().Set("Content-Type", "application/json")
32-
w.WriteHeader(http.StatusOK)
33-
w.Write([]byte(res))
29+
w.Header().Set("x-auth-token", "faketoken")
30+
w.Header().Set("Content-Type", "application/json")
31+
w.WriteHeader(http.StatusOK)
32+
w.Write([]byte(res))
3433
}
35-
}))
34+
}))
3635
endp := strings.Split(server.URL, "/")
3736
e := endp[len(endp)-1]
3837
defer server.Close()
@@ -65,7 +64,8 @@ func TestArrayPerformanceCollector(t *testing.T) {
6564
want[fmt.Sprintf("label:{name:\"dimension\" value:\"bytes_per_read\"} gauge:{value:%g}", p.BytesPerRead)] = true
6665
want[fmt.Sprintf("label:{name:\"dimension\" value:\"bytes_per_write\"} gauge:{value:%g}", p.BytesPerWrite)] = true
6766
want[fmt.Sprintf("gauge:{value:%g}", p.QueueDepth)] = true
68-
c := client.NewRestClient(e, "fake-api-token", "latest", "test-user-agent-string", false)
67+
c := client.NewRestClient(e, "fake-api-token", "latest", "test-user-agent-string", "test-X-Request-Id-string", false)
68+
6969
pc := NewArraysPerformanceCollector(c)
7070
metricsCheck(t, pc, want)
7171
}

internal/openmetrics-exporter/arrays_space_collector_test.go

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -86,7 +86,8 @@ func TestArraySpaceCollector(t *testing.T) {
8686
want[fmt.Sprintf("label:{name:\"space\" value:\"empty\"} gauge:{value:%g}", a.Capacity-(float64(*a.Space.System)+float64(*a.Space.Replication)+float64(*a.Space.Shared)+float64(*a.Space.Snapshots)+float64(*a.Space.Unique)))] = true
8787
want[fmt.Sprintf("gauge:{value:%g}", (float64(*a.Space.System)+float64(*a.Space.Replication)+float64(*a.Space.Shared)+float64(*a.Space.Snapshots)+float64(*a.Space.Unique))/a.Capacity*100)] = true
8888
defer server.Close()
89-
c := client.NewRestClient(e, "fake-api-token", "latest", "test-user-agent-string", false)
89+
c := client.NewRestClient(e, "fake-api-token", "latest", "test-user-agent-string", "test-X-Request-Id-string", false)
90+
9091
ac := NewArraySpaceCollector(c)
9192
metricsCheck(t, ac, want)
9293
}
Lines changed: 15 additions & 15 deletions
Original file line numberDiff line numberDiff line change
@@ -1,17 +1,16 @@
11
package collectors
22

3-
43
import (
4+
"encoding/json"
55
"fmt"
6-
"testing"
7-
"regexp"
8-
"strings"
96
"net/http"
107
"net/http/httptest"
11-
"encoding/json"
128
"os"
9+
"regexp"
10+
"strings"
11+
"testing"
1312

14-
"purestorage/fa-openmetrics-exporter/internal/rest-client"
13+
client "purestorage/fa-openmetrics-exporter/internal/rest-client"
1514
)
1615

1716
func TestDirectoriesPerformanceCollector(t *testing.T) {
@@ -23,16 +22,16 @@ func TestDirectoriesPerformanceCollector(t *testing.T) {
2322
server := httptest.NewTLSServer(http.HandlerFunc(func(w http.ResponseWriter, r *http.Request) {
2423
valid := regexp.MustCompile(`^/api/([0-9]+.[0-9]+)?/directories/performance$`)
2524
if r.URL.Path == "/api/api_version" {
26-
w.Header().Set("Content-Type", "application/json")
27-
w.WriteHeader(http.StatusOK)
28-
w.Write([]byte(vers))
25+
w.Header().Set("Content-Type", "application/json")
26+
w.WriteHeader(http.StatusOK)
27+
w.Write([]byte(vers))
2928
} else if valid.MatchString(r.URL.Path) {
30-
w.Header().Set("x-auth-token", "faketoken")
31-
w.Header().Set("Content-Type", "application/json")
32-
w.WriteHeader(http.StatusOK)
33-
w.Write([]byte(res))
29+
w.Header().Set("x-auth-token", "faketoken")
30+
w.Header().Set("Content-Type", "application/json")
31+
w.WriteHeader(http.StatusOK)
32+
w.Write([]byte(res))
3433
}
35-
}))
34+
}))
3635
endp := strings.Split(server.URL, "/")
3736
e := endp[len(endp)-1]
3837
defer server.Close()
@@ -50,7 +49,8 @@ func TestDirectoriesPerformanceCollector(t *testing.T) {
5049
want[fmt.Sprintf("label:{name:\"dimension\" value:\"bytes_per_read\"} label:{name:\"name\" value:\"%s\"} gauge:{value:%g}", p.Name, p.BytesPerRead)] = true
5150
want[fmt.Sprintf("label:{name:\"dimension\" value:\"bytes_per_write\"} label:{name:\"name\" value:\"%s\"} gauge:{value:%g}", p.Name, p.BytesPerWrite)] = true
5251
}
53-
c := client.NewRestClient(e, "fake-api-token", "latest", "test-user-agent-string", false)
52+
c := client.NewRestClient(e, "fake-api-token", "latest", "test-user-agent-string", "test-X-Request-Id-string", false)
53+
5454
pc := NewDirectoriesPerformanceCollector(c)
5555
metricsCheck(t, pc, want)
5656
}

0 commit comments

Comments
 (0)