feat: add alertmanager handler
All checks were successful
Go / build (push) Successful in 43s

This commit is contained in:
Bastien Riviere 2023-09-11 18:54:24 +02:00
parent 1bc747c18b
commit 773555491a
Signed by: babariviere
GPG key ID: 4E5F0839249F162E
4 changed files with 82 additions and 0 deletions

70
bridge/alertmanager.go Normal file
View file

@ -0,0 +1,70 @@
package bridge
import (
"encoding/json"
"log/slog"
"net/http"
"strings"
"time"
)
type AlertmanagerEvent struct {
Receiver string `json:"receiver"`
Status string `json:"status"`
Alerts []struct {
Status string `json:"status"`
Labels map[string]string `json:"labels"`
Annotations map[string]string `json:"annotations"`
StartsAt time.Time `json:"startsAt"`
EndsAt time.Time `json:"endsAt"`
GeneratorURL string `json:"generatorURL"`
Fingerprint string `json:"fingerprint"`
} `json:"alerts"`
GroupLabels map[string]string `json:"groupLabels"`
CommonLabels map[string]string `json:"commonLabels"`
CommonAnnotations map[string]string `json:"commonAnnotations"`
ExternalURL string `json:"externalURL"`
Version string `json:"version"`
GroupKey string `json:"groupKey"`
TruncatedAlerts int `json:"truncatedAlerts"`
}
type AlertmanagerHandler struct{}
func NewAlertmanagerHandler() AlertmanagerHandler {
return AlertmanagerHandler{}
}
func (d AlertmanagerHandler) ProduceNotifications(r *http.Request) ([]Notification, error) {
l := slog.With(slog.String("handler", "alertmanager"))
dec := json.NewDecoder(r.Body)
defer r.Body.Close()
var event AlertmanagerEvent
if err := dec.Decode(&event); err != nil {
l.Error("invalid message format", "error", err)
return nil, err
}
notifications := make([]Notification, 0, len(event.Alerts))
for _, alert := range event.Alerts {
if alert.Annotations["summary"] == "" {
continue
}
var not Notification
not.Title = "[" + strings.ToUpper(event.Status) + "] " + alert.Annotations["summary"]
not.Body = alert.Annotations["description"]
if runbook := alert.Annotations["runbook_url"]; runbook != "" {
not.Actions = append(not.Actions, NewViewAction("Runbook", runbook))
}
if event.Status == "resolved" {
not.Tags = []string{"resolved"}
}
notifications = append(notifications, not)
}
return notifications, nil
}

View file

@ -12,6 +12,7 @@ type HandlerType int
const (
HandlerFlux HandlerType = iota + 1
HandlerDiscordEmbed
HandlerAlertmanager
)
func (h HandlerType) String() string {
@ -20,6 +21,8 @@ func (h HandlerType) String() string {
return "flux"
case HandlerDiscordEmbed:
return "discord_embed"
case HandlerAlertmanager:
return "alertmanager"
}
panic("unreachable")
}
@ -153,6 +156,8 @@ func readHandlerType(d *scfg.Directive) (HandlerType, error) {
return HandlerFlux, nil
case "discord_embed":
return HandlerDiscordEmbed, nil
case "alertmanager":
return HandlerAlertmanager, nil
default:
return 0, fmt.Errorf("invalid handler type %q", ty)
}

View file

@ -22,6 +22,11 @@ data:
type "discord_embed"
topic "forgejo"
}
handler "/alerts" {
type "alertmanager"
topic "infra"
}
---
apiVersion: apps/v1
kind: Deployment

View file

@ -76,6 +76,8 @@ func main() {
h = bridge.NewFluxHandler()
case config.HandlerDiscordEmbed:
h = bridge.NewDiscordEmbedHandler()
case config.HandlerAlertmanager:
h = bridge.NewAlertmanagerHandler()
}
slog.Debug("Registering bridge", "route", route, "handler", handler.Type)