matrix-alertmanager-receiver/main.go

136 lines
3.7 KiB
Go
Raw Normal View History

2020-04-06 18:12:43 +02:00
package main
import (
"os"
"fmt"
"log"
"flag"
2020-04-06 18:12:43 +02:00
"net/http"
2020-04-29 18:09:58 +02:00
"encoding/json"
2020-05-03 09:57:05 +02:00
"github.com/BurntSushi/toml"
2020-04-06 18:42:26 +02:00
"github.com/matrix-org/gomatrix"
"github.com/prometheus/alertmanager/template"
2020-04-06 18:12:43 +02:00
)
2020-05-03 09:57:05 +02:00
var logger *log.Logger
var config Configuration
2020-05-03 09:57:05 +02:00
type Configuration struct {
Homeserver string
TargetRoomID string
MXID string
MXToken string
HTTPPort int
HTTPAddress string
2020-05-03 09:57:05 +02:00
}
func getMatrixMessageFor(alert template.Alert) gomatrix.HTMLMessage {
var prefix string
switch alert.Status {
case "firing":
prefix = "<strong><font color=\"#ff0000\">FIRING</font></strong> "
case "resolved":
prefix = "<strong><font color=\"#33cc33\">RESOLVED</font></strong> "
default:
prefix = fmt.Sprintf("<strong>%v</strong> ", alert.Status)
}
return gomatrix.GetHTMLMessage("m.text", prefix + alert.Labels["name"] + " >> " + alert.Annotations["summary"])
2020-04-29 18:09:58 +02:00
}
2020-05-03 09:57:05 +02:00
func getMatrixClient(homeserver string, user string, token string, targetRoomID string) *gomatrix.Client {
logger.Printf("Connecting to Matrix Homserver %v as %v.", homeserver, user)
matrixClient, err := gomatrix.NewClient(homeserver, user, token)
2020-04-06 18:42:26 +02:00
if err != nil {
2020-05-03 09:57:05 +02:00
logger.Fatalf("Could not log in to Matrix Homeserver (%v): %v", homeserver, err)
2020-04-06 18:42:26 +02:00
}
2020-04-29 18:09:58 +02:00
joinedRooms, err := matrixClient.JoinedRooms()
2020-04-06 18:42:26 +02:00
if err != nil {
2020-05-03 09:57:05 +02:00
logger.Fatalf("Could not fetch Matrix rooms: %v", err)
2020-04-29 18:09:58 +02:00
}
alreadyJoinedTarget := false
for _, roomID := range joinedRooms.JoinedRooms {
2020-05-03 09:57:05 +02:00
if targetRoomID == roomID {
2020-04-29 18:09:58 +02:00
alreadyJoinedTarget = true
}
}
2020-05-03 09:57:05 +02:00
if alreadyJoinedTarget {
logger.Printf("%v is already part of %v.", user, targetRoomID,)
} else {
logger.Printf("Joining %v.", targetRoomID)
_, err := matrixClient.JoinRoom(targetRoomID, "", nil)
2020-04-29 18:09:58 +02:00
if err != nil {
2020-05-03 09:57:05 +02:00
logger.Fatalf("Failed to join %v: %v", targetRoomID, err)
2020-04-29 18:09:58 +02:00
}
2020-04-06 18:42:26 +02:00
}
2020-04-06 18:12:43 +02:00
2020-05-03 09:57:05 +02:00
return matrixClient
}
func handleIncomingHooks( w http.ResponseWriter, r *http.Request,
matrixClient *gomatrix.Client, targetRoomID string) {
2020-04-06 18:12:43 +02:00
2020-05-03 09:57:05 +02:00
if r.Method != http.MethodPost {
w.WriteHeader(http.StatusMethodNotAllowed)
return
}
2020-04-06 18:12:43 +02:00
2020-05-03 09:57:05 +02:00
payload := template.Data{}
if err := json.NewDecoder(r.Body).Decode(&payload); err != nil {
w.WriteHeader(http.StatusBadRequest)
}
logger.Printf("Received valid hook from %v", r.RemoteAddr)
2020-04-29 18:09:58 +02:00
2020-05-03 09:57:05 +02:00
for _, alert := range payload.Alerts {
msg := getMatrixMessageFor(alert)
logger.Printf("> %v", msg.Body)
_, err := matrixClient.SendMessageEvent(targetRoomID, "m.room.message", msg)
2020-05-03 09:57:05 +02:00
if err != nil {
logger.Printf(">> Could not forward to Matrix: %v", err)
2020-05-03 08:54:18 +02:00
}
2020-05-03 09:57:05 +02:00
}
w.WriteHeader(http.StatusOK)
}
func main() {
// Initialize logger.
logger = log.New(os.Stdout, "", log.Flags())
// We use a configuration file since we need to specify secrets, and read
// everything else from it to keep things simple.
var configPath = flag.String("config", "/etc/matrix-alertmanager-receiver.toml", "Path to configuration file")
flag.Parse()
2020-04-29 18:09:58 +02:00
2020-05-03 09:57:05 +02:00
logger.Printf("Reading configuration from %v.", *configPath)
md, err := toml.DecodeFile(*configPath, &config)
2020-05-03 09:57:05 +02:00
if err != nil {
logger.Fatalf("Could not parse configuration file (%v): %v", *configPath, err)
}
2020-04-29 18:09:58 +02:00
2020-05-03 09:57:05 +02:00
for _, field := range []string{"Homeserver", "MXID", "MXToken", "TargetRoomID", "HTTPPort"} {
if ! md.IsDefined(field) {
logger.Fatalf("Field %v is not set in config. Exiting.", field)
2020-04-29 18:09:58 +02:00
}
2020-05-03 09:57:05 +02:00
}
2020-04-29 18:09:58 +02:00
2020-05-03 09:57:05 +02:00
// Initialize Matrix client.
matrixClient := getMatrixClient(
config.Homeserver, config.MXID, config.MXToken, config.TargetRoomID)
// Initialize HTTP server.
http.HandleFunc("/alert", func(w http.ResponseWriter, r *http.Request) {
handleIncomingHooks(w, r, matrixClient, config.TargetRoomID)
2020-04-06 18:12:43 +02:00
})
var listenAddr = fmt.Sprintf("%v:%v", config.HTTPAddress, config.HTTPPort)
2020-04-06 18:12:43 +02:00
logger.Printf("Listening for HTTP requests (webhooks) on %v", listenAddr)
2020-05-03 09:57:05 +02:00
logger.Fatal(http.ListenAndServe(listenAddr, nil))
2020-04-06 18:12:43 +02:00
}