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 Sep 26, 2024
1 parent 27f4e81 commit 568bc2c
Show file tree
Hide file tree
Showing 5 changed files with 77 additions and 20 deletions.
21 changes: 11 additions & 10 deletions receivers/mqtt/config.go
Original file line number Diff line number Diff line change
Expand Up @@ -17,16 +17,17 @@ const (
)

type Config struct {
BrokerURL string `json:"brokerUrl,omitempty" yaml:"brokerUrl,omitempty"`
ClientID string `json:"clientId,omitempty" yaml:"clientId,omitempty"`
Topic string `json:"topic,omitempty" yaml:"topic,omitempty"`
Message string `json:"message,omitempty" yaml:"message,omitempty"`
MessageFormat string `json:"messageFormat,omitempty" yaml:"messageFormat,omitempty"`
Username string `json:"username,omitempty" yaml:"username,omitempty"`
Password string `json:"password,omitempty" yaml:"password,omitempty"`
QoS receivers.OptionalNumber `json:"qos,omitempty" yaml:"qos,omitempty"`
Retain bool `json:"retain,omitempty" yaml:"retain,omitempty"`
TLSConfig *receivers.TLSConfig `json:"tlsConfig,omitempty" yaml:"tlsConfig,omitempty"`
BrokerURL string `json:"brokerUrl,omitempty" yaml:"brokerUrl,omitempty"`
ClientID string `json:"clientId,omitempty" yaml:"clientId,omitempty"`
Topic string `json:"topic,omitempty" yaml:"topic,omitempty"`
Message string `json:"message,omitempty" yaml:"message,omitempty"`
MessageFormat string `json:"messageFormat,omitempty" yaml:"messageFormat,omitempty"`
Username string `json:"username,omitempty" yaml:"username,omitempty"`
Password string `json:"password,omitempty" yaml:"password,omitempty"`
QoS receivers.OptionalNumber `json:"qos,omitempty" yaml:"qos,omitempty"`
Retain bool `json:"retain,omitempty" yaml:"retain,omitempty"`
TLSConfig *receivers.TLSConfig `json:"tlsConfig,omitempty" yaml:"tlsConfig,omitempty"`
AddGroupKeyToTopic bool `json:"addGroupKeyToTopic,omitempty" yaml:"addGroupKeyToTopic,omitempty"`
}

func NewConfig(jsonData json.RawMessage, decryptFn receivers.DecryptFunc) (Config, error) {
Expand Down
25 changes: 25 additions & 0 deletions receivers/mqtt/config_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -120,6 +120,31 @@ func TestNewConfig(t *testing.T) {
},
},
},
{
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",
QoS: "0",
TLSConfig: &receivers.TLSConfig{
InsecureSkipVerify: false,
ServerName: "localhost",
CACertificate: "test-tls-ca-certificate",
ClientKey: "test-tls-client-key",
ClientCertificate: "test-tls-client-certificate",
},
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 @@ -96,10 +97,20 @@ func (n *Notifier) Notify(ctx context.Context, as ...*types.Alert) (bool, error)
return false, fmt.Errorf("Failed to parse QoS: %s", err.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),
retain: n.settings.Retain,
qos: int(qos),
Expand Down
35 changes: 27 additions & 8 deletions receivers/mqtt/mqtt_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -92,6 +92,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 @@ -110,17 +119,11 @@ 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),
retain: false,
qos: 0,
},
Expand Down Expand Up @@ -150,6 +153,22 @@ func TestNotify(t *testing.T) {
retain: true,
qos: 1,
},
},
{
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 @@ -15,7 +15,8 @@ const FullValidConfigForTesting = `{
"caCertificate": "test-tls-ca-certificate",
"clientCertificate": "test-tls-client-certificate",
"clientKey": "test-tls-client-key"
}
},
"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 568bc2c

Please sign in to comment.