Skip to content

Commit

Permalink
feat: map GeneratorURL values
Browse files Browse the repository at this point in the history
Signed-off-by: Sebastian Hoß <[email protected]>
  • Loading branch information
sebhoss committed Oct 29, 2023
1 parent 45ccc21 commit 8738fca
Show file tree
Hide file tree
Showing 4 changed files with 41 additions and 13 deletions.
30 changes: 25 additions & 5 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -10,6 +10,7 @@ SPDX-License-Identifier: GPL-3.0-or-later
- Add templating mechanism for alerts based on Golang's [html/template](https://pkg.go.dev/html/template)
- Allow arbitrary rooms as receivers with optional pretty URLs
- Mapping of `ExternalURL` values for misconfigured Alertmanager instances
- Mapping of `GeneratorURL` values for misconfigured Prometheus instances
- Computation of `SilenceURL` and arbitrary other values.
- Replace TOML with YAML format
- Add Prometheus metrics for received alerts, sent notifications, and templating failures
Expand All @@ -23,7 +24,7 @@ Configure your Alertmanager(s) to use this service as a webhook receiver like th
receivers:
- name: matrix
webhook_configs:
- url: "http://example.com:<port>/<alerts-path-prefix>/{roomID}"
- url: "https://example.com:<port>/<alerts-path-prefix>/{roomID}"
```
The values for `<port>` and `<alerts-path-prefix>` are configuration options of this service and need to match whatever you wrote into your Alertmanager configuration. The value for `{roomID}` must be a valid Matrix room ID or a pre-defined pretty URL (see below). The following snippet shows the same configuration with all options specified:
Expand All @@ -32,10 +33,10 @@ The values for `<port>` and `<alerts-path-prefix>` are configuration options of
receivers:
- name: some-room
webhook_configs:
- url: "http://example.com:12345/alerts/!PFFZ6G9E07n2tnbiUD:matrix.example.com"
- url: "https://example.com:12345/alerts/!PFFZ6G9E07n2tnbiUD:matrix.example.com"
- name: other-room
webhook_configs:
- url: "http://example.com:12345/alerts/!HJFZ28f4jKJfmaHLEk:matrix.example.com"
- url: "https://example.com:12345/alerts/!HJFZ28f4jKJfmaHLEk:matrix.example.com"
```

Note that you can use the `matrix.room-mapping` configuration option to expose 'pretty' URLs and hide those Matrix room IDs from your Alertmanager configuration:
Expand All @@ -44,10 +45,10 @@ Note that you can use the `matrix.room-mapping` configuration option to expose '
receivers:
- name: some-room
webhook_configs:
- url: "http://example.com:12345/alerts/pager"
- url: "https://example.com:12345/alerts/pager"
- name: other-room
webhook_configs:
- url: "http://example.com:12345/alerts/ticket"
- url: "https://example.com:12345/alerts/ticket"
```

## CLI Arguments
Expand Down Expand Up @@ -84,6 +85,11 @@ templating:
# key is the original value taken from the Alertmanager payload
# value is the mapped value which will be available as '.ExternalURL' in templates
"http://alertmanager:9093": https://alertmanager.example.com
# mapping of GeneratorURL values
generator-url-mapping:
# key is the original value taken from the Alertmanager payload
# value is the mapped value which will be available as '.GeneratorURL' in templates
"http://prometheus:8080": https://prometheus.example.com
# computation of arbitrary values based on matching alert annotations, labels, or status
# values will be evaluated top to bottom, last entry wins
Expand Down Expand Up @@ -144,6 +150,7 @@ Template are written using Golang's [html/template](https://pkg.go.dev/html/temp
- `CommonLabels`: The CommonLabels value of the original [payload](https://prometheus.io/docs/alerting/latest/notifications/#data) sent by the Alertmanager.
- `CommonAnnotations`: The CommonAnnotations value of the original [payload](https://prometheus.io/docs/alerting/latest/notifications/#data) sent by the Alertmanager.
- `ExternalURL`: The ExternalURL value of the original [payload](https://prometheus.io/docs/alerting/latest/notifications/#data) sent by the Alertmanager mapped by the mapping section in the configuration file. If no entry exists in the map, the original value will be available as-is in the template.
- `GeneratorURL`: The GeneratorURL value of the original [alert data](https://prometheus.io/docs/alerting/latest/notifications/#alert) send by the Alertmanager mapped by the mapping section in the configuration file. If no entry exists in the map, the original value will be available as-is in the template.
- `SilenceURL`: The calculated URL to silence an alert. This should be used like this `<a href="{{ .SilenceURL }}">Silence</a>` or similar.
- `ComputedValues`: Map of computed values defined in the configuration file.

Expand All @@ -160,6 +167,19 @@ templating:

Using the above configuration, all alerts whose `ExternalURL` original value is `http://alertmanager:9093` will be `https://alertmanager.example.com` and `http://alerts:12345` will be mapped to `https://alerts.example.com`.

#### GeneratorURL

The `GeneratorURL` as sent by an Alertmanager contains the backlink to the Prometheus instance that created the alert. In general, you should set the correct URL your Prometheus can be reached with using the `--web.external-url` Prometheus CLI flag. In case you cannot change the configuration of your Prometheus, use the `templating.generator-url-mapping` configuration of this alertmanager-receiver. Each key is the full original value as sent by a Prometheus and each value is what you want to use in your templates.

```yaml
templating:
generator-url-mapping:
"http://prometheus:8080": https://prometheus.example.com
"http://metrics:12345": https://metrics.example.com
```

Using the above configuration, all alerts whose `GeneratorURL` original value is `http://prometheus:8080` will be `https://prometheus.example.com` and `http://metrics:12345` will be mapped to `https://metrics.example.com`.

#### Computed Values

You can make additional arbitrary values available in your templates by using the `templating.computed-values` key. There are several ways to configure when these values are available in your template and which value they have.
Expand Down
11 changes: 9 additions & 2 deletions alertmanager/templating.go
Original file line number Diff line number Diff line change
Expand Up @@ -42,6 +42,7 @@ type templateData struct {
CommonAnnotations map[string]string `json:"commonAnnotations"`
SilenceURL string
ExternalURL string
GeneratorURL string
ComputedValues map[string]string
}

Expand All @@ -66,11 +67,16 @@ func CreateTemplatingFunc(ctx context.Context, configuration config.Templating)
selectedTemplate = resolved
}

externalUrl := externalURL(data.ExternalURL, configuration.ExternalURLMapping)
externalUrl := maybeMapValue(data.ExternalURL, configuration.ExternalURLMapping)
slog.DebugContext(ctx, "ExternalURL mapped",
slog.String("original-url", data.ExternalURL),
slog.String("mapped-url", externalUrl))

generatorUrl := maybeMapValue(alert.GeneratorURL, configuration.GeneratorURLMapping)
slog.DebugContext(ctx, "GeneratorURL mapped",
slog.String("original-url", data.ExternalURL),
slog.String("mapped-url", externalUrl))

silenceUrl := silenceURL(alert, externalUrl)
slog.DebugContext(ctx, "Silence URL computed", slog.String("silence-url", silenceUrl))

Expand All @@ -85,6 +91,7 @@ func CreateTemplatingFunc(ctx context.Context, configuration config.Templating)
CommonAnnotations: data.GroupLabels,
SilenceURL: silenceUrl,
ExternalURL: externalUrl,
GeneratorURL: generatorUrl,
ComputedValues: values,
})
if err != nil {
Expand Down Expand Up @@ -139,7 +146,7 @@ func computeValues(alert amtemplate.Alert, values []config.ComputedValue) map[st
return computedValues
}

func externalURL(original string, mapping map[string]string) string {
func maybeMapValue(original string, mapping map[string]string) string {
if replacement, ok := mapping[original]; ok {
return replacement
}
Expand Down
4 changes: 2 additions & 2 deletions alertmanager/templating_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -12,7 +12,7 @@ import (
"testing"
)

func TestExternalURL(t *testing.T) {
func TestMaybeMapValue(t *testing.T) {
testCases := map[string]struct {
original string
mapping map[string]string
Expand Down Expand Up @@ -60,7 +60,7 @@ func TestExternalURL(t *testing.T) {
}
for name, testCase := range testCases {
t.Run(name, func(t *testing.T) {
assert.Equal(t, testCase.expected, externalURL(testCase.original, testCase.mapping))
assert.Equal(t, testCase.expected, maybeMapValue(testCase.original, testCase.mapping))
})
}
}
Expand Down
9 changes: 5 additions & 4 deletions config/model.go
Original file line number Diff line number Diff line change
Expand Up @@ -57,10 +57,11 @@ func (m *Matrix) LogValue() slog.Value {
}

type Templating struct {
ExternalURLMapping KeyValue `json:"external-url-mapping"`
ComputedValues []ComputedValue `json:"computed-values"`
Firing string `json:"firing-template"`
Resolved string `json:"resolved-template"`
ExternalURLMapping KeyValue `json:"external-url-mapping"`
GeneratorURLMapping KeyValue `json:"generator-url-mapping"`
ComputedValues []ComputedValue `json:"computed-values"`
Firing string `json:"firing-template"`
Resolved string `json:"resolved-template"`
}

func (t *Templating) LogValue() slog.Value {
Expand Down

0 comments on commit 8738fca

Please sign in to comment.