mirror of
https://github.com/prymitive/karma
synced 2026-05-05 03:16:51 +00:00
feat(backend): add external_uri config option for alertmanager upstreams
Fixes #899
This commit is contained in:
@@ -39,6 +39,7 @@ alertmanager:
|
||||
servers:
|
||||
- name: string
|
||||
uri: string
|
||||
external_uri: string
|
||||
timeout: duration
|
||||
proxy: bool
|
||||
tls:
|
||||
@@ -63,23 +64,28 @@ alertmanager:
|
||||
every alert in the UI and for filtering alerts using `@alertmanager=NAME`
|
||||
filter
|
||||
- `uri` - base URI of this Alertmanager server. Supported URI schemes are
|
||||
`http://`, `https://` and `file://`. `file://` scheme is only useful for
|
||||
testing with JSON files, see [mock](/internal/mock/) dir for examples, files
|
||||
in this directory are used for running tests and when running demo instance
|
||||
of karma with `make run`.
|
||||
`http://` and `https://`.
|
||||
If URI contains basic auth info
|
||||
(`https://user:password@alertmanager.example.com`) and you don't want it to
|
||||
be visible to users then ensure `proxy: true` is also set.
|
||||
be visible to users then ensure `proxy: true` is also set in order to avoid
|
||||
leaking auth information to the browser.
|
||||
Without proxy mode full URI needs to be passed to karma web UI code.
|
||||
With proxy mode all requests will be routed via karma HTTP server and since
|
||||
karma has full URI in the config it only needs Alertmanager name in that
|
||||
request.
|
||||
`proxy: true` in order to avoid leaking auth information to the browser.
|
||||
To set a different URI for all browser requests (can be any valid URI) see
|
||||
`external_uri` option below.
|
||||
- `external_uri` - base URI of this Alertmanager server used for all browser
|
||||
requests, which currently means requests sent to alertmanager when creating,
|
||||
editing or deleting silences from karma web UI (unless proxy mode is set, see
|
||||
above).
|
||||
This option cannot be used when `proxy` is enabled.
|
||||
- `timeout` - timeout for requests send to this Alertmanager server, a string in
|
||||
[time.Duration](https://golang.org/pkg/time/#ParseDuration) format.
|
||||
- `proxy` - if enabled requests from user browsers to this Alertmanager will be
|
||||
proxied via karma. This applies to requests made when managing silences via
|
||||
karma (creating or expiring silences).
|
||||
THis option cannot be used when `external_uri` is set.
|
||||
- `tls:ca` - path to CA certificate used to establish TLS connection to this
|
||||
Alertmanager instance (for URIs using `https://` scheme). If unset or empty
|
||||
string is set then Go will try to find system CA certificates using well known
|
||||
@@ -740,6 +746,18 @@ ALERTMANAGER_URI=https://alertmanager.example.com karma
|
||||
karma --alertmanager.uri https://alertmanager.example.com
|
||||
```
|
||||
|
||||
### Alertmanager external URI
|
||||
|
||||
To set the `external_uri` key from `alertmanager.servers` map
|
||||
`ALERTMANAGER_EXTERNAL_URI` env or `--alertmanager.external_uri` flag can be
|
||||
used.
|
||||
Examples:
|
||||
|
||||
```shell
|
||||
ALERTMANAGER_EXTERNAL_URI=https://alertmanager.example.com karma
|
||||
karma --alertmanager.external_uri https://alertmanager.example.com
|
||||
```
|
||||
|
||||
### Alertmanager name
|
||||
|
||||
To set the `name` key from `alertmanager.servers` map `ALERTMANAGER_NAME` env or
|
||||
|
||||
@@ -6,6 +6,7 @@ import (
|
||||
|
||||
type uriTest struct {
|
||||
rawURI string
|
||||
extURI string
|
||||
proxy bool
|
||||
publicURI string
|
||||
}
|
||||
@@ -46,11 +47,35 @@ var uriTests = []uriTest{
|
||||
proxy: true,
|
||||
publicURI: "/proxy/alertmanager/test",
|
||||
},
|
||||
{
|
||||
rawURI: "http://user:pass@alertmanager.example.com",
|
||||
extURI: "http://am.example.com",
|
||||
proxy: true,
|
||||
publicURI: "/proxy/alertmanager/test",
|
||||
},
|
||||
{
|
||||
rawURI: "http://alertmanager.example.com",
|
||||
extURI: "http://am.example.com",
|
||||
proxy: true,
|
||||
publicURI: "/proxy/alertmanager/test",
|
||||
},
|
||||
{
|
||||
rawURI: "http://user:pass@alertmanager.example.com",
|
||||
extURI: "http://am.example.com",
|
||||
proxy: false,
|
||||
publicURI: "http://am.example.com",
|
||||
},
|
||||
{
|
||||
rawURI: "http://alertmanager.example.com",
|
||||
extURI: "http://am.example.com",
|
||||
proxy: false,
|
||||
publicURI: "http://am.example.com",
|
||||
},
|
||||
}
|
||||
|
||||
func TestAlertmanagerURI(t *testing.T) {
|
||||
for _, test := range uriTests {
|
||||
am, err := NewAlertmanager("test", test.rawURI, WithProxy(test.proxy))
|
||||
am, err := NewAlertmanager("test", test.rawURI, WithExternalURI(test.extURI), WithProxy(test.proxy))
|
||||
if err != nil {
|
||||
t.Error(err)
|
||||
}
|
||||
|
||||
@@ -34,6 +34,7 @@ type alertmanagerMetrics struct {
|
||||
// Alertmanager represents Alertmanager upstream instance
|
||||
type Alertmanager struct {
|
||||
URI string `json:"uri"`
|
||||
ExternalURI string `json:"-"`
|
||||
RequestTimeout time.Duration `json:"timeout"`
|
||||
Name string `json:"name"`
|
||||
// whenever this instance should be proxied
|
||||
@@ -207,6 +208,9 @@ func (am *Alertmanager) PublicURI() string {
|
||||
}
|
||||
return uri
|
||||
}
|
||||
if am.ExternalURI != "" {
|
||||
return am.ExternalURI
|
||||
}
|
||||
return am.URI
|
||||
}
|
||||
|
||||
|
||||
@@ -3,6 +3,7 @@ package alertmanager
|
||||
import (
|
||||
"fmt"
|
||||
"net/http"
|
||||
"net/url"
|
||||
"sync"
|
||||
"time"
|
||||
|
||||
@@ -23,6 +24,7 @@ var (
|
||||
func NewAlertmanager(name, upstreamURI string, opts ...Option) (*Alertmanager, error) {
|
||||
am := &Alertmanager{
|
||||
URI: upstreamURI,
|
||||
ExternalURI: "",
|
||||
RequestTimeout: time.Second * 10,
|
||||
Name: name,
|
||||
lock: sync.RWMutex{},
|
||||
@@ -64,6 +66,10 @@ func RegisterAlertmanager(am *Alertmanager) error {
|
||||
return fmt.Errorf("alertmanager upstream '%s' already exist", am.Name)
|
||||
}
|
||||
|
||||
if am.ExternalURI != "" && am.ProxyRequests {
|
||||
return fmt.Errorf("alertmanager upstream '%s' is configured with both proxy and external_uri, only one of those options can be enabled", am.Name)
|
||||
}
|
||||
|
||||
for _, existingAM := range upstreams {
|
||||
if existingAM.URI == am.URI {
|
||||
return fmt.Errorf("alertmanager upstream '%s' already collects from '%s'", existingAM.Name, existingAM.URI)
|
||||
@@ -128,3 +134,16 @@ func WithHTTPTransport(httpTransport http.RoundTripper) Option {
|
||||
return nil
|
||||
}
|
||||
}
|
||||
|
||||
// WithExternalURI option allows to set custom ExternalURI on our instance
|
||||
func WithExternalURI(uri string) Option {
|
||||
return func(am *Alertmanager) error {
|
||||
// first validate that this is a valid URI
|
||||
_, err := url.Parse(uri)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
am.ExternalURI = uri
|
||||
return nil
|
||||
}
|
||||
}
|
||||
|
||||
@@ -30,6 +30,8 @@ func init() {
|
||||
"Name for the Alertmanager server (only used with simplified config)")
|
||||
pflag.String("alertmanager.uri", "",
|
||||
"Alertmanager server URI (only used with simplified config)")
|
||||
pflag.String("alertmanager.external_uri", "",
|
||||
"Alertmanager server URI used for web UI links (only used with simplified config)")
|
||||
pflag.Duration("alertmanager.timeout", time.Second*40,
|
||||
"Timeout for requests sent to the Alertmanager server (only used with simplified config)")
|
||||
pflag.Bool("alertmanager.proxy", false,
|
||||
@@ -247,11 +249,12 @@ func (config *configSchema) Read() {
|
||||
log.Info("Using simple config with a single Alertmanager server")
|
||||
config.Alertmanager.Servers = []alertmanagerConfig{
|
||||
{
|
||||
Name: v.GetString("alertmanager.name"),
|
||||
URI: v.GetString("alertmanager.uri"),
|
||||
Timeout: v.GetDuration("alertmanager.timeout"),
|
||||
Proxy: v.GetBool("alertmanager.proxy"),
|
||||
Headers: make(map[string]string),
|
||||
Name: v.GetString("alertmanager.name"),
|
||||
URI: v.GetString("alertmanager.uri"),
|
||||
ExternalURI: v.GetString("alertmanager.external_uri"),
|
||||
Timeout: v.GetDuration("alertmanager.timeout"),
|
||||
Proxy: v.GetBool("alertmanager.proxy"),
|
||||
Headers: make(map[string]string),
|
||||
},
|
||||
}
|
||||
}
|
||||
@@ -266,12 +269,13 @@ func (config *configSchema) LogValues() {
|
||||
servers := []alertmanagerConfig{}
|
||||
for _, s := range cfg.Alertmanager.Servers {
|
||||
server := alertmanagerConfig{
|
||||
Name: s.Name,
|
||||
URI: uri.SanitizeURI(s.URI),
|
||||
Timeout: s.Timeout,
|
||||
TLS: s.TLS,
|
||||
Proxy: s.Proxy,
|
||||
Headers: s.Headers,
|
||||
Name: s.Name,
|
||||
URI: uri.SanitizeURI(s.URI),
|
||||
ExternalURI: uri.SanitizeURI(s.ExternalURI),
|
||||
Timeout: s.Timeout,
|
||||
TLS: s.TLS,
|
||||
Proxy: s.Proxy,
|
||||
Headers: s.Headers,
|
||||
}
|
||||
servers = append(servers, server)
|
||||
}
|
||||
|
||||
@@ -19,6 +19,7 @@ func resetEnv() {
|
||||
karmaEnvVariables := []string{
|
||||
"ALERTMANAGER_INTERVAL",
|
||||
"ALERTMANAGER_URI",
|
||||
"ALERTMANAGER_EXTERNAL_URI",
|
||||
"ALERTMANAGER_NAME",
|
||||
"ALERTMANAGET_TIMEOUT",
|
||||
"ANNOTATIONS_DEFAULT_HIDDEN",
|
||||
@@ -58,6 +59,7 @@ func testReadConfig(t *testing.T) {
|
||||
servers:
|
||||
- name: default
|
||||
uri: http://localhost
|
||||
external_uri: http://example.com
|
||||
timeout: 40s
|
||||
proxy: false
|
||||
tls:
|
||||
@@ -155,6 +157,7 @@ func TestReadConfig(t *testing.T) {
|
||||
log.SetLevel(log.ErrorLevel)
|
||||
os.Setenv("ALERTMANAGER_INTERVAL", "1s")
|
||||
os.Setenv("ALERTMANAGER_URI", "http://localhost")
|
||||
os.Setenv("ALERTMANAGER_EXTERNAL_URI", "http://example.com")
|
||||
os.Setenv("ANNOTATIONS_DEFAULT_HIDDEN", "true")
|
||||
os.Setenv("ANNOTATIONS_VISIBLE", "summary")
|
||||
os.Setenv("CUSTOM_CSS", "/custom.css")
|
||||
|
||||
@@ -6,11 +6,12 @@ import (
|
||||
)
|
||||
|
||||
type alertmanagerConfig struct {
|
||||
Name string
|
||||
URI string
|
||||
Timeout time.Duration
|
||||
Proxy bool
|
||||
TLS struct {
|
||||
Name string
|
||||
URI string
|
||||
ExternalURI string `yaml:"external_uri" mapstructure:"external_uri"`
|
||||
Timeout time.Duration
|
||||
Proxy bool
|
||||
TLS struct {
|
||||
CA string
|
||||
Cert string
|
||||
Key string
|
||||
|
||||
1
main.go
1
main.go
@@ -126,6 +126,7 @@ func setupUpstreams() {
|
||||
am, err := alertmanager.NewAlertmanager(
|
||||
s.Name,
|
||||
s.URI,
|
||||
alertmanager.WithExternalURI(s.ExternalURI),
|
||||
alertmanager.WithRequestTimeout(s.Timeout),
|
||||
alertmanager.WithProxy(s.Proxy),
|
||||
alertmanager.WithHTTPTransport(httpTransport), // we will pass a nil unless TLS.CA or TLS.Cert is set
|
||||
|
||||
Reference in New Issue
Block a user