mirror of
https://github.com/prymitive/karma
synced 2026-02-13 20:59:53 +00:00
feat(backend): add support for custom headers (#368)
This will allow the AlertManager upstreams to be sent user defined HTTP headers.
This commit is contained in:
committed by
Łukasz Mierzwa
parent
c6f392ebd9
commit
ec14be0288
1
.gitignore
vendored
1
.gitignore
vendored
@@ -1,6 +1,7 @@
|
||||
.build
|
||||
.coverage
|
||||
.tests
|
||||
.vscode
|
||||
bindata_assetfs.go
|
||||
coverage.txt
|
||||
karma
|
||||
|
||||
@@ -41,6 +41,8 @@ alertmanager:
|
||||
ca: string
|
||||
cert: string
|
||||
key: string
|
||||
headers:
|
||||
any: string
|
||||
```
|
||||
|
||||
- `interval` - how often alerts should be refreshed, a string in
|
||||
@@ -85,9 +87,12 @@ alertmanager:
|
||||
TLS connections to this Alertmanager instance if it requires a TLS client
|
||||
authentication.
|
||||
Note that this option requires `tls:cert` to be also set.
|
||||
- `headers` - a map with a list of key: values which are header: value.
|
||||
These custom headers will be sent with every request to the alert manager
|
||||
instance.
|
||||
|
||||
Example with two production Alertmanager instances running in HA mode and a
|
||||
staging instance that is also proxied:
|
||||
staging instance that is also proxied and requires a custom auth header:
|
||||
|
||||
```yaml
|
||||
alertmanager:
|
||||
@@ -107,6 +112,8 @@ alertmanager:
|
||||
proxy: true
|
||||
tls:
|
||||
ca: /etc/ssl/staging-ca.crt
|
||||
headers:
|
||||
X-Auth-Token: aValidToken
|
||||
- name: protected
|
||||
uri: https://alertmanager-auth.prod.example.com
|
||||
timeout: 20s
|
||||
|
||||
@@ -5,6 +5,8 @@ alertmanager:
|
||||
uri: http://localhost:9093
|
||||
timeout: 10s
|
||||
proxy: true
|
||||
headers:
|
||||
X-Auth-Test: some-token-or-other-string
|
||||
- name: client-auth
|
||||
uri: https://localhost:9093
|
||||
timeout: 10s
|
||||
|
||||
@@ -61,6 +61,8 @@ type Alertmanager struct {
|
||||
status alertmanagerStatus
|
||||
// metrics tracked per alertmanager instance
|
||||
metrics alertmanagerMetrics
|
||||
// headers to send with each AlertManager request
|
||||
HTTPHeaders map[string]string
|
||||
}
|
||||
|
||||
func (am *Alertmanager) fetchStatus() alertmanagerStatus {
|
||||
@@ -80,7 +82,7 @@ func (am *Alertmanager) fetchStatus() alertmanagerStatus {
|
||||
resp := alertmanagerStatusResponse{}
|
||||
|
||||
// read raw body from the source
|
||||
source, err := am.reader.Read(url)
|
||||
source, err := am.reader.Read(url, am.HTTPHeaders)
|
||||
if err != nil {
|
||||
log.Errorf("[%s] %s request failed: %s", am.Name, uri.SanitizeURI(url), err)
|
||||
return status
|
||||
@@ -157,7 +159,7 @@ func (am *Alertmanager) pullSilences(version string) error {
|
||||
|
||||
start := time.Now()
|
||||
// read raw body from the source
|
||||
source, err := am.reader.Read(url)
|
||||
source, err := am.reader.Read(url, am.HTTPHeaders)
|
||||
if err != nil {
|
||||
log.Errorf("[%s] %s request failed: %s", am.Name, uri.SanitizeURI(url), err)
|
||||
return err
|
||||
@@ -222,7 +224,7 @@ func (am *Alertmanager) pullAlerts(version string) error {
|
||||
|
||||
start := time.Now()
|
||||
// read raw body from the source
|
||||
source, err := am.reader.Read(url)
|
||||
source, err := am.reader.Read(url, am.HTTPHeaders)
|
||||
if err != nil {
|
||||
log.Errorf("[%s] %s request failed: %s", am.Name, uri.SanitizeURI(url), err)
|
||||
return err
|
||||
|
||||
@@ -31,6 +31,7 @@ func NewAlertmanager(name, upstreamURI string, opts ...Option) (*Alertmanager, e
|
||||
colors: models.LabelsColorMap{},
|
||||
autocomplete: []models.Autocomplete{},
|
||||
knownLabels: []string{},
|
||||
HTTPHeaders: map[string]string{},
|
||||
metrics: alertmanagerMetrics{
|
||||
errors: map[string]float64{
|
||||
labelValueErrorsAlerts: 0,
|
||||
@@ -48,7 +49,7 @@ func NewAlertmanager(name, upstreamURI string, opts ...Option) (*Alertmanager, e
|
||||
}
|
||||
|
||||
var err error
|
||||
am.reader, err = uri.NewReader(am.URI, am.RequestTimeout, am.HTTPTransport)
|
||||
am.reader, err = uri.NewReader(am.URI, am.RequestTimeout, am.HTTPTransport, am.HTTPHeaders)
|
||||
if err != nil {
|
||||
return am, err
|
||||
}
|
||||
@@ -110,6 +111,15 @@ func WithRequestTimeout(timeout time.Duration) Option {
|
||||
}
|
||||
}
|
||||
|
||||
// WithHTTPHeaders option can be passed to NewAlertManager in order to set
|
||||
// a map of headers that will be passed with every request
|
||||
func WithHTTPHeaders(headers map[string]string) Option {
|
||||
return func(am *Alertmanager) error {
|
||||
am.HTTPHeaders = headers
|
||||
return nil
|
||||
}
|
||||
}
|
||||
|
||||
// WithHTTPTransport option can be passed to NewAlertmanager in order to set
|
||||
// a custom HTTP transport (http.RoundTripper implementation)
|
||||
func WithHTTPTransport(httpTransport http.RoundTripper) Option {
|
||||
|
||||
@@ -170,6 +170,7 @@ func (config *configSchema) Read() {
|
||||
URI: v.GetString("alertmanager.uri"),
|
||||
Timeout: v.GetDuration("alertmanager.timeout"),
|
||||
Proxy: v.GetBool("alertmanager.proxy"),
|
||||
Headers: make(map[string]string),
|
||||
},
|
||||
}
|
||||
}
|
||||
|
||||
@@ -64,6 +64,7 @@ func testReadConfig(t *testing.T) {
|
||||
ca: ""
|
||||
cert: ""
|
||||
key: ""
|
||||
headers: {}
|
||||
annotations:
|
||||
default:
|
||||
hidden: true
|
||||
|
||||
@@ -12,6 +12,7 @@ type alertmanagerConfig struct {
|
||||
Cert string
|
||||
Key string
|
||||
}
|
||||
Headers map[string]string
|
||||
}
|
||||
|
||||
type jiraRule struct {
|
||||
|
||||
@@ -46,7 +46,7 @@ func (r *FileURIReader) pathFromURI(uri string) (string, error) {
|
||||
return absolutePath, nil
|
||||
}
|
||||
|
||||
func (r *FileURIReader) Read(uri string) (io.ReadCloser, error) {
|
||||
func (r *FileURIReader) Read(uri string, _ map[string]string) (io.ReadCloser, error) {
|
||||
filename, err := r.pathFromURI(uri)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
|
||||
@@ -14,7 +14,7 @@ type HTTPURIReader struct {
|
||||
client http.Client
|
||||
}
|
||||
|
||||
func (r *HTTPURIReader) Read(uri string) (io.ReadCloser, error) {
|
||||
func (r *HTTPURIReader) Read(uri string, headers map[string]string) (io.ReadCloser, error) {
|
||||
log.Infof("GET %s timeout=%s", SanitizeURI(uri), r.client.Timeout)
|
||||
|
||||
request, err := http.NewRequest("GET", uri, nil)
|
||||
@@ -23,6 +23,10 @@ func (r *HTTPURIReader) Read(uri string) (io.ReadCloser, error) {
|
||||
}
|
||||
request.Header.Add("Accept-Encoding", "gzip")
|
||||
|
||||
for header, value := range headers {
|
||||
request.Header.Add(header, value)
|
||||
}
|
||||
|
||||
resp, err := r.client.Do(request)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
|
||||
@@ -10,12 +10,12 @@ import (
|
||||
|
||||
// Reader reads from a specific URI schema
|
||||
type Reader interface {
|
||||
Read(string) (io.ReadCloser, error)
|
||||
Read(string, map[string]string) (io.ReadCloser, error)
|
||||
}
|
||||
|
||||
// NewReader creates an instance of URIReader that can handle URI schema
|
||||
// for the passed uri string
|
||||
func NewReader(uri string, timeout time.Duration, clientTransport http.RoundTripper) (Reader, error) {
|
||||
func NewReader(uri string, timeout time.Duration, clientTransport http.RoundTripper, headers map[string]string) (Reader, error) {
|
||||
u, err := url.Parse(uri)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
|
||||
@@ -34,11 +34,12 @@ type httpTransportTest struct {
|
||||
useTLS bool
|
||||
tlsConfig *tls.Config
|
||||
failed bool
|
||||
headers map[string]string
|
||||
}
|
||||
|
||||
var httpTransportTests = []httpTransportTest{
|
||||
{
|
||||
// plain HTTP request, should work
|
||||
// plain HTTP request, should work
|
||||
},
|
||||
{
|
||||
// just enable TLS, will use proper RootCA certs so it should work
|
||||
@@ -50,6 +51,9 @@ var httpTransportTests = []httpTransportTest{
|
||||
tlsConfig: &tls.Config{RootCAs: x509.NewCertPool()},
|
||||
failed: true,
|
||||
},
|
||||
{
|
||||
headers: map[string]string{"X-Auth-Test": "tokenValue"},
|
||||
},
|
||||
}
|
||||
|
||||
type fileTransportTest struct {
|
||||
@@ -57,6 +61,7 @@ type fileTransportTest struct {
|
||||
failed bool
|
||||
timeout time.Duration
|
||||
size int64
|
||||
headers map[string]string
|
||||
}
|
||||
|
||||
var fileTransportTests = []fileTransportTest{
|
||||
@@ -124,12 +129,12 @@ func TestHTTPReader(t *testing.T) {
|
||||
tlsConfig = &tls.Config{RootCAs: caPool}
|
||||
}
|
||||
|
||||
transp, err := uri.NewReader(amURI, testCase.timeout, &http.Transport{TLSClientConfig: tlsConfig})
|
||||
transp, err := uri.NewReader(amURI, testCase.timeout, &http.Transport{TLSClientConfig: tlsConfig}, testCase.headers)
|
||||
if err != nil {
|
||||
t.Errorf("[%v] failed to create new HTTP transport: %s", testCase, err)
|
||||
}
|
||||
|
||||
source, err := transp.Read(amURI)
|
||||
source, err := transp.Read(amURI, testCase.headers)
|
||||
if err != nil {
|
||||
if !testCase.failed {
|
||||
t.Errorf("[%v] unexpected failure while creating reader: %s", testCase, err)
|
||||
@@ -152,12 +157,12 @@ func TestHTTPReader(t *testing.T) {
|
||||
func TestFileReader(t *testing.T) {
|
||||
//log.SetLevel(log.FatalLevel)
|
||||
for _, testCase := range fileTransportTests {
|
||||
transp, err := uri.NewReader(testCase.uri, testCase.timeout, &http.Transport{})
|
||||
transp, err := uri.NewReader(testCase.uri, testCase.timeout, &http.Transport{}, testCase.headers)
|
||||
if err != nil {
|
||||
t.Errorf("[%v] failed to create new transport: %s", testCase, err)
|
||||
}
|
||||
|
||||
source, err := transp.Read(testCase.uri)
|
||||
source, err := transp.Read(testCase.uri, testCase.headers)
|
||||
if err != nil {
|
||||
if !testCase.failed {
|
||||
t.Errorf("[%v] unexpected failure while creating reader: %s", testCase, err)
|
||||
|
||||
1
main.go
1
main.go
@@ -116,6 +116,7 @@ func setupUpstreams() {
|
||||
alertmanager.WithRequestTimeout(s.Timeout),
|
||||
alertmanager.WithProxy(s.Proxy),
|
||||
alertmanager.WithHTTPTransport(httpTransport), // we will pass a nil unless TLS.CA or TLS.Cert is set
|
||||
alertmanager.WithHTTPHeaders(s.Headers),
|
||||
)
|
||||
if err != nil {
|
||||
log.Fatalf("Failed to create Alertmanager '%s' with URI '%s': %s", s.Name, s.URI, err)
|
||||
|
||||
Reference in New Issue
Block a user