Skip to content

Commit

Permalink
MQTT receiver: Add a setting to append group key to the topic name
Browse files Browse the repository at this point in the history
  • Loading branch information
alexander-akhmetov committed Aug 28, 2024
1 parent 70248a7 commit 103ab89
Show file tree
Hide file tree
Showing 5 changed files with 61 additions and 10 deletions.
1 change: 1 addition & 0 deletions receivers/mqtt/config.go
Original file line number Diff line number Diff line change
Expand Up @@ -24,6 +24,7 @@ type Config struct {
Username string `json:"username,omitempty" yaml:"username,omitempty"`
Password string `json:"password,omitempty" yaml:"password,omitempty"`
InsecureSkipVerify bool `json:"insecureSkipVerify,omitempty" yaml:"insecureSkipVerify,omitempty"`
AddGroupKeyToTopic bool `json:"addGroupKeyToTopic,omitempty" yaml:"addGroupKeyToTopic,omitempty"`
}

func NewConfig(jsonData json.RawMessage, decryptFn receivers.DecryptFunc) (Config, error) {
Expand Down
18 changes: 18 additions & 0 deletions receivers/mqtt/config_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -85,6 +85,24 @@ func TestNewConfig(t *testing.T) {
Password: "testpasswd",
},
},
{
name: "Full valid configuration",
settings: FullValidConfigForTesting,
secureSettings: map[string][]byte{
"password": []byte("test-password"),
},
expectedConfig: Config{
Message: templates.DefaultMessageEmbed,
BrokerURL: "tcp://localhost:1883",
Topic: "grafana/alerts",
MessageFormat: MessageFormatJSON,
ClientID: "grafana-test-client-id",
Username: "test-username",
Password: "test-password",
InsecureSkipVerify: true,
AddGroupKeyToTopic: true,
},
},
}

for _, c := range cases {
Expand Down
13 changes: 12 additions & 1 deletion receivers/mqtt/mqtt.go
Original file line number Diff line number Diff line change
Expand Up @@ -6,6 +6,7 @@ import (
"encoding/json"
"errors"
"fmt"
"path"

"github.com/prometheus/alertmanager/notify"
"github.com/prometheus/alertmanager/types"
Expand Down Expand Up @@ -86,10 +87,20 @@ func (n *Notifier) Notify(ctx context.Context, as ...*types.Alert) (bool, error)
}
}()

topic := n.settings.Topic
if n.settings.AddGroupKeyToTopic {
groupKey, err := notify.ExtractGroupKey(ctx)
if err != nil {
n.log.Error("Failed to extract group key", "error", err.Error())
return false, fmt.Errorf("Failed to extract group key: %s", err.Error())
}
topic = path.Join(n.settings.Topic, string(groupKey))
}

err = n.client.Publish(
ctx,
message{
topic: n.settings.Topic,
topic: topic,
payload: []byte(msg),
},
)
Expand Down
36 changes: 28 additions & 8 deletions receivers/mqtt/mqtt_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -65,6 +65,15 @@ func TestNotify(t *testing.T) {
require.NoError(t, err)
tmpl.ExternalURL = externalURL

defaultAlert := &types.Alert{
Alert: model.Alert{
Labels: model.LabelSet{"alertname": "alert1", "lbl1": "val1"},
Annotations: model.LabelSet{"ann1": "annv1", "__dashboardUid__": "abcd", "__panelId__": "efgh"},
GeneratorURL: "a URL",
},
}
defaultAlertRenderedJSON := "{\"receiver\":\"\",\"status\":\"firing\",\"alerts\":[{\"status\":\"firing\",\"labels\":{\"alertname\":\"alert1\",\"lbl1\":\"val1\"},\"annotations\":{\"ann1\":\"annv1\"},\"startsAt\":\"0001-01-01T00:00:00Z\",\"endsAt\":\"0001-01-01T00:00:00Z\",\"generatorURL\":\"a URL\",\"fingerprint\":\"fac0861a85de433a\",\"silenceURL\":\"http://localhost/base/alerting/silence/new?alertmanager=grafana\\u0026matcher=alertname%3Dalert1\\u0026matcher=lbl1%3Dval1\",\"dashboardURL\":\"http://localhost/base/d/abcd\",\"panelURL\":\"http://localhost/base/d/abcd?viewPanel=efgh\",\"values\":null,\"valueString\":\"\"}],\"groupLabels\":{\"alertname\":\"\"},\"commonLabels\":{\"alertname\":\"alert1\",\"lbl1\":\"val1\"},\"commonAnnotations\":{\"ann1\":\"annv1\"},\"externalURL\":\"http://localhost/base\",\"version\":\"1\",\"groupKey\":\"alertname\",\"message\":\"**Firing**\\n\\nValue: [no value]\\nLabels:\\n - alertname = alert1\\n - lbl1 = val1\\nAnnotations:\\n - ann1 = annv1\\nSource: a URL\\nSilence: http://localhost/base/alerting/silence/new?alertmanager=grafana\\u0026matcher=alertname%3Dalert1\\u0026matcher=lbl1%3Dval1\\nDashboard: http://localhost/base/d/abcd\\nPanel: http://localhost/base/d/abcd?viewPanel=efgh\\n\"}"

cases := []struct {
name string
settings Config
Expand All @@ -83,17 +92,28 @@ func TestNotify(t *testing.T) {
MessageFormat: MessageFormatJSON,
},
alerts: []*types.Alert{
{
Alert: model.Alert{
Labels: model.LabelSet{"alertname": "alert1", "lbl1": "val1"},
Annotations: model.LabelSet{"ann1": "annv1", "__dashboardUid__": "abcd", "__panelId__": "efgh"},
GeneratorURL: "a URL",
},
},
defaultAlert,
},
expMessage: message{
topic: "alert1",
payload: []byte("{\"receiver\":\"\",\"status\":\"firing\",\"alerts\":[{\"status\":\"firing\",\"labels\":{\"alertname\":\"alert1\",\"lbl1\":\"val1\"},\"annotations\":{\"ann1\":\"annv1\"},\"startsAt\":\"0001-01-01T00:00:00Z\",\"endsAt\":\"0001-01-01T00:00:00Z\",\"generatorURL\":\"a URL\",\"fingerprint\":\"fac0861a85de433a\",\"silenceURL\":\"http://localhost/base/alerting/silence/new?alertmanager=grafana\\u0026matcher=alertname%3Dalert1\\u0026matcher=lbl1%3Dval1\",\"dashboardURL\":\"http://localhost/base/d/abcd\",\"panelURL\":\"http://localhost/base/d/abcd?viewPanel=efgh\",\"values\":null,\"valueString\":\"\"}],\"groupLabels\":{\"alertname\":\"\"},\"commonLabels\":{\"alertname\":\"alert1\",\"lbl1\":\"val1\"},\"commonAnnotations\":{\"ann1\":\"annv1\"},\"externalURL\":\"http://localhost/base\",\"version\":\"1\",\"groupKey\":\"alertname\",\"message\":\"**Firing**\\n\\nValue: [no value]\\nLabels:\\n - alertname = alert1\\n - lbl1 = val1\\nAnnotations:\\n - ann1 = annv1\\nSource: a URL\\nSilence: http://localhost/base/alerting/silence/new?alertmanager=grafana\\u0026matcher=alertname%3Dalert1\\u0026matcher=lbl1%3Dval1\\nDashboard: http://localhost/base/d/abcd\\nPanel: http://localhost/base/d/abcd?viewPanel=efgh\\n\"}"),
payload: []byte(defaultAlertRenderedJSON),
},
expError: nil,
},
{
name: "A single alert with the default template in JSON and group-key added to the topic",
settings: Config{
Topic: "alert1",
Message: templates.DefaultMessageEmbed,
MessageFormat: MessageFormatJSON,
AddGroupKeyToTopic: true,
},
alerts: []*types.Alert{
defaultAlert,
},
expMessage: message{
topic: "alert1/alertname",
payload: []byte(defaultAlertRenderedJSON),
},
expError: nil,
},
Expand Down
3 changes: 2 additions & 1 deletion receivers/mqtt/testing.go
Original file line number Diff line number Diff line change
Expand Up @@ -8,7 +8,8 @@ const FullValidConfigForTesting = `{
"clientId": "grafana-test-client-id",
"username": "test-username",
"password": "test-password",
"insecureSkipVerify": false
"insecureSkipVerify": true,
"addGroupKeyToTopic": true
}`

// FullValidSecretsForTesting is a string representation of JSON object that contains all fields that can be overridden from secrets
Expand Down

0 comments on commit 103ab89

Please sign in to comment.