Skip to content

Commit 0a1ba63

Browse files
committed
Add CLI flag to add additional HTTP headers
1 parent 7765023 commit 0a1ba63

File tree

6 files changed

+72
-0
lines changed

6 files changed

+72
-0
lines changed

.golangci.yml

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -24,6 +24,7 @@ linters:
2424
- tagliatelle
2525
- varnamelen
2626
- wrapcheck
27+
- funlen
2728
exclusions:
2829
generated: lax
2930
presets:

README.md

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -26,6 +26,8 @@ Flags:
2626
--cert-file string Specify the Certificate File for TLS authentication (CHECK_PROMETHEUS_CERT_FILE)
2727
--key-file string Specify the Key File for TLS authentication (CHECK_PROMETHEUS_KEY_FILE)
2828
-t, --timeout int Timeout in seconds for the CheckPlugin (default 30)
29+
--header strings Additional HTTP header to include in the request. Can be used multiple times.
30+
Keys and values are separated by a colon (--header "X-Custom: example").
2931
-h, --help help for check_prometheus
3032
-v, --version version for check_prometheus
3133
```

cmd/config.go

Lines changed: 15 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -23,6 +23,7 @@ type Config struct {
2323
KeyFile string `env:"CHECK_PROMETHEUS_KEY_FILE"`
2424
Hostname string `env:"CHECK_PROMETHEUS_HOSTNAME"`
2525
URL string `env:"CHECK_PROMETHEUS_URL"`
26+
Headers []string
2627
Port int
2728
Info bool
2829
Insecure bool
@@ -106,6 +107,20 @@ func (c *Config) NewClient() *client.Client {
106107
rt = config.NewBasicAuthRoundTripper(u, p, rt)
107108
}
108109

110+
// If extra headers are set, parse them and add them to the request
111+
if len(c.Headers) > 0 {
112+
headers := make(map[string]string)
113+
114+
for _, h := range c.Headers {
115+
head := strings.Split(h, ":")
116+
if len(head) == 2 {
117+
headers[strings.TrimSpace(head[0])] = strings.TrimSpace(head[1])
118+
}
119+
}
120+
121+
rt = client.NewHeadersRoundTripper(headers, rt)
122+
}
123+
109124
return client.NewClient(u.String(), rt)
110125
}
111126

cmd/health_test.go

Lines changed: 15 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -144,6 +144,21 @@ func TestHealthCmd(t *testing.T) {
144144
args: []string{"run", "../main.go", "--user", "passwordmissing", "health"},
145145
expected: "[UNKNOWN] - specify the user name and password for server authentication <user:password> (*errors.errorString)\nexit status 3\n",
146146
},
147+
{
148+
name: "health-extra-header",
149+
server: httptest.NewServer(http.HandlerFunc(func(w http.ResponseWriter, r *http.Request) {
150+
foobar := r.Header.Get("X-Foobar")
151+
if foobar == "Barfoo" {
152+
w.WriteHeader(http.StatusOK)
153+
w.Write([]byte(`Prometheus Server is Healthy.`))
154+
return
155+
}
156+
w.WriteHeader(http.StatusUnauthorized)
157+
w.Write([]byte(`Wrong Header!`))
158+
})),
159+
args: []string{"run", "../main.go", "--header", "X-Foobar: Barfoo", "health"},
160+
expected: "[OK] - states: ok=1\n\\_ [OK] Prometheus Server is Healthy.\n\n",
161+
},
147162
}
148163

149164
for _, test := range tests {

cmd/root.go

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -61,6 +61,9 @@ func init() {
6161
"Specify the Key File for TLS authentication (CHECK_PROMETHEUS_KEY_FILE)")
6262
pfs.IntVarP(&Timeout, "timeout", "t", Timeout,
6363
"Timeout in seconds for the CheckPlugin")
64+
pfs.StringSliceVarP(&cliConfig.Headers, "header", "", nil,
65+
`Additional HTTP header to include in the request. Can be used multiple times.
66+
Keys and values are separated by a colon (--header "X-Custom: example").`)
6467

6568
rootCmd.Flags().SortFlags = false
6669
pfs.SortFlags = false

internal/client/client.go

Lines changed: 36 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -85,3 +85,39 @@ func (c *Client) GetStatus(ctx context.Context, endpoint string) (returncode int
8585

8686
return check.Unknown, resp.StatusCode, respBody, err
8787
}
88+
89+
type headersRoundTripper struct {
90+
headers map[string]string
91+
rt http.RoundTripper
92+
}
93+
94+
// NewHeadersRoundTripper adds the given headers to a request
95+
func NewHeadersRoundTripper(headers map[string]string, rt http.RoundTripper) http.RoundTripper {
96+
return &headersRoundTripper{headers, rt}
97+
}
98+
99+
func (rt *headersRoundTripper) RoundTrip(req *http.Request) (*http.Response, error) {
100+
// RoundTrip should not modify the request, except for
101+
// consuming and closing the Request's Body.
102+
req = cloneRequest(req)
103+
104+
for key, value := range rt.headers {
105+
req.Header.Add(key, value)
106+
}
107+
108+
return rt.rt.RoundTrip(req)
109+
}
110+
111+
// cloneRequest returns a clone of the provided *http.Request
112+
func cloneRequest(r *http.Request) *http.Request {
113+
// Shallow copy of the struct.
114+
r2 := new(http.Request)
115+
*r2 = *r
116+
// Deep copy of the Header.
117+
r2.Header = make(http.Header)
118+
for k, s := range r.Header {
119+
r2.Header[k] = s
120+
}
121+
122+
return r2
123+
}

0 commit comments

Comments
 (0)