Skip to content

Commit 96cfda1

Browse files
authored
Merge branch 'PureStorage-OpenConnect:main' into update-grafana-dash-and-docs
2 parents f38e2b9 + 0143e48 commit 96cfda1

File tree

10 files changed

+271
-101
lines changed

10 files changed

+271
-101
lines changed

.github/workflows/release.yaml

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -10,7 +10,7 @@ jobs:
1010
runs-on: ubuntu-latest
1111
steps:
1212
- uses: actions/checkout@v3
13-
- uses: wangyoucao577/go-release-action@v1.30
13+
- uses: wangyoucao577/go-release-action@v1
1414
with:
1515
github_token: ${{ secrets.GITHUB_TOKEN }}
1616
goos: linux

Makefile

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -3,7 +3,7 @@ GOTEST=$(GOCMD) test
33
GOVET=$(GOCMD) vet
44
BINARY_NAME=pure-fb-om-exporter
55
MODULE_NAME=purestorage/fb-openmetrics-exporter
6-
VERSION?=1.0.6
6+
VERSION?=1.0.7
77
SERVICE_PORT?=9491
88
DOCKER_REGISTRY?= quay.io/purestorage/
99
EXPORT_RESULT?=false # for CI please set EXPORT_RESULT to true

README.md

Lines changed: 6 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -74,21 +74,25 @@ Authentication is used by the exporter as the mechanism to cross authenticate to
7474
The first option requires specifying the api-token value as the authorization parameter of the specific job in the Prometheus configuration file.
7575
The second option provides the FlashBlade/api-token key-pair map for a list of arrays in a simple YAML configuration file that is passed as parameter to the exporter. This makes possible to write more concise Prometheus configuration files and also to configure other scrapers that cannot use the HTTP authentication header.
7676

77+
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.
78+
7779
### Usage
7880

7981
```shell
8082

81-
usage: pure-fb-om-exporter [-h|--help] [-a|--address "<value>"] [-p|--port <integer>] [-d|--debug] [-t|--tokens <file>]
83+
usage: pure-fb-om-exporter [-h|--help] [-a|--address "<value>"] [-p|--port <integer>] [-d|--debug] [-t|--tokens <file>] [-k|--key <file>] [-c|--cert <file>]
8284

8385
Pure Storage FB OpenMetrics exporter
8486

8587
Arguments:
8688

8789
-h --help Print help information
8890
-a --address IP address for this exporter to bind to. Default: 0.0.0.0
89-
-p --port Port for this exporter to listen. Default: 9490
91+
-p --port Port for this exporter to listen. Default: 9491
9092
-d --debug Enable debug. Default: false
9193
-t --tokens API token(s) map file
94+
-c --cert SSL/TLS certificate file. Required only for TLS
95+
-k --key SSL/TLS private key file. Required only for TLS
9296
```
9397

9498
The array token configuration file must have to following syntax:

build/docker/Dockerfile

Lines changed: 8 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,5 @@
11
FROM golang:alpine as build
2-
ARG VERSION=1.0.6
2+
ARG VERSION=1.0.7
33

44
WORKDIR /usr/src/app
55

@@ -13,7 +13,13 @@ RUN CGO_ENABLED=1 go build -a -tags 'netgo osusergo static_build' -ldflags="-X m
1313

1414
# alpine is used here as it seems to be the minimal image that passes quay.io vulnerability scan
1515
FROM alpine
16+
# update ssl packages for CVEs
17+
RUN apk update && apk upgrade --no-cache libcrypto3 libssl3
1618
COPY --from=build /usr/local/bin/pure-fb-om-exporter /pure-fb-om-exporter
19+
20+
# create an empty tokens file for use with volumes if required. You can use a mounted volume to /etc/pure-fb-om-exporter/ to pass the `tokens.yaml` file. File must be named `tokens.yaml`.
21+
RUN mkdir /etc/pure-fb-om-exporter && touch /etc/pure-fb-om-exporter/tokens.yaml
22+
1723
EXPOSE 9491
1824
ENTRYPOINT ["/pure-fb-om-exporter"]
19-
CMD ["--address", "0.0.0.0", "--port", "9491"]
25+
CMD ["--address", "0.0.0.0", "--port", "9491", "--tokens", "/etc/pure-fb-om-exporter/tokens.yaml"]

cmd/fb-om-exporter/main.go

Lines changed: 68 additions & 44 deletions
Original file line numberDiff line numberDiff line change
@@ -12,57 +12,77 @@ import (
1212
client "purestorage/fb-openmetrics-exporter/internal/rest-client"
1313
"strings"
1414

15-
"github.com/akamensky/argparse"
15+
"github.com/akamensky/argparse"
1616
"github.com/prometheus/client_golang/prometheus"
1717
"github.com/prometheus/client_golang/prometheus/promhttp"
18-
"gopkg.in/yaml.v3"
18+
"gopkg.in/yaml.v3"
1919
)
2020

2121
var version string = "development"
2222
var debug bool = false
2323
var arraytokens config.FlashBladeList
2424

25-
func FileExists(args []string) error {
26-
_, err := os.Stat(args[0])
27-
return err
25+
func fileExists(args []string) error {
26+
_, err := os.Stat(args[0])
27+
return err
28+
}
29+
30+
func isFile(filename string) bool {
31+
info, err := os.Stat(filename)
32+
if os.IsNotExist(err) {
33+
return false
34+
}
35+
return !info.IsDir()
2836
}
2937

3038
func main() {
3139

32-
parser := argparse.NewParser("pure-fb-om-exporter", "Pure Storage FB OpenMetrics exporter")
33-
host := parser.String("a", "address", &argparse.Options{Required: false, Help: "IP address for this exporter to bind to", Default: "0.0.0.0"})
34-
port := parser.Int("p", "port", &argparse.Options{Required: false, Help: "Port for this exporter to listen", Default: 9491})
35-
d := parser.Flag("d", "debug", &argparse.Options{Required: false, Help: "Enable debug", Default: false})
36-
at := parser.File("t", "tokens", os.O_RDONLY, 0600, &argparse.Options{Required: false, Validate: FileExists, Help: "API token(s) map file"})
37-
err := parser.Parse(os.Args)
38-
if err != nil {
39-
log.Fatalf("Error in token file: %v", err)
40-
}
41-
if !isNilFile(*at) {
42-
defer at.Close()
43-
buf := make([]byte, 1024)
44-
arrlist := ""
45-
for {
46-
n, err := at.Read(buf)
47-
if err == io.EOF {
48-
break
49-
}
50-
if err != nil {
51-
log.Fatalf("Reading token file: %v", err)
52-
}
53-
if n > 0 {
54-
arrlist = arrlist + string(buf[:n])
55-
}
56-
}
57-
buf = []byte(arrlist)
58-
err := yaml.Unmarshal(buf, &arraytokens)
59-
if err != nil {
60-
log.Fatalf("Unmarshalling token file: %v", err)
61-
}
62-
}
63-
debug = *d
64-
addr := fmt.Sprintf("%s:%d", *host, *port)
65-
log.Printf("Start Pure FlashBlade exporter %s on %s", version, addr)
40+
parser := argparse.NewParser("pure-fb-om-exporter", "Pure Storage FB OpenMetrics exporter")
41+
host := parser.String("a", "address", &argparse.Options{Required: false, Help: "IP address for this exporter to bind to", Default: "0.0.0.0"})
42+
port := parser.Int("p", "port", &argparse.Options{Required: false, Help: "Port for this exporter to listen", Default: 9491})
43+
d := parser.Flag("d", "debug", &argparse.Options{Required: false, Help: "Enable debug", Default: false})
44+
at := parser.File("t", "tokens", os.O_RDONLY, 0600, &argparse.Options{Required: false, Validate: fileExists, Help: "API token(s) map file"})
45+
cert := parser.String("c", "cert", &argparse.Options{Required: false, Help: "SSL/TLS certificate file. Required only for TLS"})
46+
key := parser.String("k", "key", &argparse.Options{Required: false, Help: "SSL/TLS private key file. Required only for TLS"})
47+
err := parser.Parse(os.Args)
48+
if err != nil {
49+
log.Fatalf("Error in token file: %v", err)
50+
}
51+
if !isNilFile(*at) {
52+
defer at.Close()
53+
buf := make([]byte, 1024)
54+
arrlist := ""
55+
for {
56+
n, err := at.Read(buf)
57+
if err == io.EOF {
58+
break
59+
}
60+
if err != nil {
61+
log.Fatalf("Reading token file: %v", err)
62+
}
63+
if n > 0 {
64+
arrlist = arrlist + string(buf[:n])
65+
}
66+
}
67+
buf = []byte(arrlist)
68+
err := yaml.Unmarshal(buf, &arraytokens)
69+
if err != nil {
70+
log.Fatalf("Unmarshalling token file: %v", err)
71+
}
72+
}
73+
if (len(*cert) > 0 && len(*key) == 0) || (len(*cert) == 0 && len(*key) > 0) {
74+
log.Fatal("Both certificate and key must be specified to enable TLS")
75+
}
76+
if len(*cert) > 0 && len(*key) > 0 {
77+
if !isFile(*cert) {
78+
log.Fatal("TLS cert file not found")
79+
} else if !isFile(*key) {
80+
log.Fatal("TLS key file not found")
81+
}
82+
}
83+
debug = *d
84+
addr := fmt.Sprintf("%s:%d", *host, *port)
85+
log.Printf("Start Pure FlashBlade exporter %s on %s", version, addr)
6686

6787
http.HandleFunc("/", index)
6888
http.HandleFunc("/metrics/array", func(w http.ResponseWriter, r *http.Request) {
@@ -80,7 +100,11 @@ func main() {
80100
http.HandleFunc("/metrics", func(w http.ResponseWriter, r *http.Request) {
81101
metricsHandler(w, r)
82102
})
83-
log.Fatal(http.ListenAndServe(addr, nil))
103+
if isFile(*cert) && isFile(*key) {
104+
log.Fatal(http.ListenAndServeTLS(addr, *cert, *key, nil))
105+
} else {
106+
log.Fatal(http.ListenAndServe(addr, nil))
107+
}
84108
}
85109

86110
func metricsHandler(w http.ResponseWriter, r *http.Request) {
@@ -112,8 +136,8 @@ func metricsHandler(w http.ResponseWriter, r *http.Request) {
112136
authHeader := r.Header.Get("Authorization")
113137
authFields := strings.Fields(authHeader)
114138
address, apitoken := arraytokens.GetArrayParams(endpoint)
115-
if len(authFields) == 2 && strings.ToLower(authFields[0]) == "bearer" {
116-
apitoken = authFields[1]
139+
if len(authFields) == 2 && strings.ToLower(authFields[0]) == "bearer" {
140+
apitoken = authFields[1]
117141
address = endpoint
118142
}
119143
if apitoken == "" {
@@ -187,6 +211,6 @@ func index(w http.ResponseWriter, r *http.Request) {
187211
}
188212

189213
func isNilFile(f os.File) bool {
190-
var tf os.File
191-
return f == tf
214+
var tf os.File
215+
return f == tf
192216
}

examples/config/k8s/pure-fb-exporter-deployment.yaml

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -24,7 +24,7 @@ spec:
2424
- name: pure-fb-om-exporter
2525
image: quay.io/purestorage/pure-fb-om-exporter
2626
args:
27-
- '--host=0.0.0.0'
27+
- '--address=0.0.0.0'
2828
- '--port=9491'
2929
ports:
3030
- name: web

go.mod

Lines changed: 9 additions & 10 deletions
Original file line numberDiff line numberDiff line change
@@ -4,22 +4,21 @@ go 1.20
44

55
require (
66
github.com/akamensky/argparse v1.4.0
7-
github.com/go-resty/resty/v2 v2.7.0
8-
github.com/google/go-cmp v0.5.9
9-
github.com/prometheus/client_golang v1.16.0
10-
github.com/prometheus/client_model v0.4.0
7+
github.com/go-resty/resty/v2 v2.10.0
8+
github.com/google/go-cmp v0.6.0
9+
github.com/prometheus/client_golang v1.17.0
10+
github.com/prometheus/client_model v0.5.0
1111
gopkg.in/yaml.v3 v3.0.1
1212
)
1313

1414
require (
1515
github.com/beorn7/perks v1.0.1 // indirect
1616
github.com/cespare/xxhash/v2 v2.2.0 // indirect
17-
github.com/golang/protobuf v1.5.3 // indirect
1817
github.com/kr/text v0.2.0 // indirect
19-
github.com/matttproud/golang_protobuf_extensions v1.0.4 // indirect
20-
github.com/prometheus/common v0.44.0 // indirect
21-
github.com/prometheus/procfs v0.11.1 // indirect
22-
golang.org/x/net v0.14.0 // indirect
23-
golang.org/x/sys v0.11.0 // indirect
18+
github.com/matttproud/golang_protobuf_extensions/v2 v2.0.0 // indirect
19+
github.com/prometheus/common v0.45.0 // indirect
20+
github.com/prometheus/procfs v0.12.0 // indirect
21+
golang.org/x/net v0.18.0 // indirect
22+
golang.org/x/sys v0.14.0 // indirect
2423
google.golang.org/protobuf v1.31.0 // indirect
2524
)

0 commit comments

Comments
 (0)