mirror of
https://github.com/pushbits/server.git
synced 2025-07-17 16:37:29 +02:00
alertmanager interface
This commit is contained in:
parent
473a005f45
commit
8b465d0815
5 changed files with 163 additions and 4 deletions
|
@ -75,7 +75,7 @@ func main() {
|
||||||
log.Fatal(err)
|
log.Fatal(err)
|
||||||
}
|
}
|
||||||
|
|
||||||
engine := router.Create(c.Debug, cm, db, dp)
|
engine := router.Create(c.Debug, cm, db, dp, &c.Alertmanager)
|
||||||
|
|
||||||
err = runner.Run(engine, c.HTTP.ListenAddress, c.HTTP.Port)
|
err = runner.Run(engine, c.HTTP.ListenAddress, c.HTTP.Port)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
|
|
|
@ -60,3 +60,10 @@ crypto:
|
||||||
formatting:
|
formatting:
|
||||||
# Whether to use colored titles based on the message priority (<0: grey, 0-3: default, 4-10: yellow, 10-20: orange, >20: red).
|
# Whether to use colored titles based on the message priority (<0: grey, 0-3: default, 4-10: yellow, 10-20: orange, >20: red).
|
||||||
coloredtitle: false
|
coloredtitle: false
|
||||||
|
|
||||||
|
# This settings are only relevant if you want to use PushBits with alertmanager
|
||||||
|
alertmanager:
|
||||||
|
# The name of the entry in the alerts annotations that should be used for the title
|
||||||
|
annotationtitle: title
|
||||||
|
# The name of the entry in the alerts annotations that should be used for the message
|
||||||
|
annotationmessage: message
|
||||||
|
|
137
internal/api/alertmanager/handler.go
Normal file
137
internal/api/alertmanager/handler.go
Normal file
|
@ -0,0 +1,137 @@
|
||||||
|
package alertmanager
|
||||||
|
|
||||||
|
import (
|
||||||
|
"log"
|
||||||
|
"net/http"
|
||||||
|
"net/url"
|
||||||
|
"strings"
|
||||||
|
|
||||||
|
"github.com/gin-gonic/gin"
|
||||||
|
"github.com/pushbits/server/internal/api"
|
||||||
|
"github.com/pushbits/server/internal/authentication"
|
||||||
|
"github.com/pushbits/server/internal/model"
|
||||||
|
"github.com/pushbits/server/internal/pberrors"
|
||||||
|
)
|
||||||
|
|
||||||
|
type AlertmanagerHandler struct {
|
||||||
|
DP api.NotificationDispatcher
|
||||||
|
Settings AlertmanagerHandlerSettings
|
||||||
|
}
|
||||||
|
|
||||||
|
type AlertmanagerHandlerSettings struct {
|
||||||
|
TitleAnnotation string
|
||||||
|
MessageAnnotation string
|
||||||
|
}
|
||||||
|
|
||||||
|
type hookMessage struct {
|
||||||
|
Version string `json:"version"`
|
||||||
|
GroupKey string `json:"groupKey"`
|
||||||
|
Receiver string `json:"receiver"`
|
||||||
|
GroupLabels map[string]string `json:"groupLabels"`
|
||||||
|
CommonLabels map[string]string `json:"commonLabels"`
|
||||||
|
CommonAnnotations map[string]string `json:"commonAnnotiations"`
|
||||||
|
ExternalURL string `json:"externalURL"`
|
||||||
|
Alerts []alert `json:"alerts"`
|
||||||
|
}
|
||||||
|
|
||||||
|
type alert struct {
|
||||||
|
Labels map[string]string `json:"labels"`
|
||||||
|
Annotiations map[string]string `json:"annotiations"`
|
||||||
|
StartsAt string `json:"startsAt"`
|
||||||
|
EndsAt string `json:"endsAt"`
|
||||||
|
Status string `json:"status"`
|
||||||
|
}
|
||||||
|
|
||||||
|
// CreateAlert godoc
|
||||||
|
// @Summary Create an Alert
|
||||||
|
// @Description Creates an alert that is send to the channel as a notification. This endpoint is compatible with alertmanager webhooks.
|
||||||
|
// @ID post-alert
|
||||||
|
// @Tags Alertmanager
|
||||||
|
// @Accept json
|
||||||
|
// @Produce json
|
||||||
|
// @Param token query string true "Channels token, can also be provieded in the header"
|
||||||
|
// @Param data body hookMessage true "alertmanager webhook call"
|
||||||
|
// @Success 200 {object} []model.Notification
|
||||||
|
// @Failure 500,404,403 ""
|
||||||
|
// @Router /alert [post]
|
||||||
|
func (h *AlertmanagerHandler) CreateAlert(ctx *gin.Context) {
|
||||||
|
application := authentication.GetApplication(ctx)
|
||||||
|
log.Printf("Sending alert notification for application %s.", application.Name)
|
||||||
|
|
||||||
|
var hook hookMessage
|
||||||
|
if err := ctx.Bind(&hook); err != nil {
|
||||||
|
return
|
||||||
|
}
|
||||||
|
|
||||||
|
notifications := make([]model.Notification, len(hook.Alerts))
|
||||||
|
for i, alert := range hook.Alerts {
|
||||||
|
notification := alert.ToNotification(h.Settings.TitleAnnotation, h.Settings.MessageAnnotation)
|
||||||
|
notification.Sanitize(application)
|
||||||
|
messageID, err := h.DP.SendNotification(application, ¬ification)
|
||||||
|
if success := successOrAbort(ctx, http.StatusInternalServerError, err); !success {
|
||||||
|
return
|
||||||
|
}
|
||||||
|
|
||||||
|
notification.ID = messageID
|
||||||
|
notification.UrlEncodedID = url.QueryEscape(messageID)
|
||||||
|
notifications[i] = notification
|
||||||
|
}
|
||||||
|
ctx.JSON(http.StatusOK, ¬ifications)
|
||||||
|
}
|
||||||
|
|
||||||
|
func (alert *alert) ToNotification(titleAnnotation, messageAnnotation string) model.Notification {
|
||||||
|
title := strings.Builder{}
|
||||||
|
message := strings.Builder{}
|
||||||
|
|
||||||
|
switch alert.Status {
|
||||||
|
case "firing":
|
||||||
|
title.WriteString("[FIR] ")
|
||||||
|
case "resolved":
|
||||||
|
title.WriteString("[RES] ")
|
||||||
|
}
|
||||||
|
message.WriteString("STATUS: ")
|
||||||
|
message.WriteString(alert.Status)
|
||||||
|
message.WriteString("\n\n")
|
||||||
|
|
||||||
|
if titleString, ok := alert.Annotiations[titleAnnotation]; ok {
|
||||||
|
title.WriteString(titleString)
|
||||||
|
} else {
|
||||||
|
title.WriteString("Unknown Title")
|
||||||
|
}
|
||||||
|
title.WriteString(" - ")
|
||||||
|
title.WriteString(alert.StartsAt)
|
||||||
|
|
||||||
|
if messageString, ok := alert.Annotiations[messageAnnotation]; ok {
|
||||||
|
message.WriteString(messageString)
|
||||||
|
} else {
|
||||||
|
message.WriteString("Unknown Message")
|
||||||
|
}
|
||||||
|
|
||||||
|
message.WriteString("\n")
|
||||||
|
|
||||||
|
for labelName, labelValue := range alert.Labels {
|
||||||
|
message.WriteString("\n")
|
||||||
|
message.WriteString(labelName)
|
||||||
|
message.WriteString(": ")
|
||||||
|
message.WriteString(labelValue)
|
||||||
|
}
|
||||||
|
|
||||||
|
return model.Notification{
|
||||||
|
Message: message.String(),
|
||||||
|
Title: title.String(),
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
func successOrAbort(ctx *gin.Context, code int, err error) bool {
|
||||||
|
if err != nil {
|
||||||
|
// If we know the error force error code
|
||||||
|
switch err {
|
||||||
|
case pberrors.ErrorMessageNotFound:
|
||||||
|
ctx.AbortWithError(http.StatusNotFound, err)
|
||||||
|
default:
|
||||||
|
ctx.AbortWithError(code, err)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
return err == nil
|
||||||
|
}
|
|
@ -33,6 +33,12 @@ type Matrix struct {
|
||||||
Password string `required:"true"`
|
Password string `required:"true"`
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// Alertmanager holds information on how to parse alertmanager calls
|
||||||
|
type Alertmanager struct {
|
||||||
|
AnnotationTitle string `default:"title"`
|
||||||
|
AnnotationMessage string `default:"message"`
|
||||||
|
}
|
||||||
|
|
||||||
// Configuration holds values that can be configured by the user.
|
// Configuration holds values that can be configured by the user.
|
||||||
type Configuration struct {
|
type Configuration struct {
|
||||||
Debug bool `default:"false"`
|
Debug bool `default:"false"`
|
||||||
|
@ -55,6 +61,7 @@ type Configuration struct {
|
||||||
}
|
}
|
||||||
Crypto CryptoConfig
|
Crypto CryptoConfig
|
||||||
Formatting Formatting
|
Formatting Formatting
|
||||||
|
Alertmanager Alertmanager
|
||||||
}
|
}
|
||||||
|
|
||||||
func configFiles() []string {
|
func configFiles() []string {
|
||||||
|
|
|
@ -4,8 +4,10 @@ import (
|
||||||
"log"
|
"log"
|
||||||
|
|
||||||
"github.com/pushbits/server/internal/api"
|
"github.com/pushbits/server/internal/api"
|
||||||
|
"github.com/pushbits/server/internal/api/alertmanager"
|
||||||
"github.com/pushbits/server/internal/authentication"
|
"github.com/pushbits/server/internal/authentication"
|
||||||
"github.com/pushbits/server/internal/authentication/credentials"
|
"github.com/pushbits/server/internal/authentication/credentials"
|
||||||
|
"github.com/pushbits/server/internal/configuration"
|
||||||
"github.com/pushbits/server/internal/database"
|
"github.com/pushbits/server/internal/database"
|
||||||
"github.com/pushbits/server/internal/dispatcher"
|
"github.com/pushbits/server/internal/dispatcher"
|
||||||
|
|
||||||
|
@ -14,7 +16,7 @@ import (
|
||||||
)
|
)
|
||||||
|
|
||||||
// Create a Gin engine and setup all routes.
|
// Create a Gin engine and setup all routes.
|
||||||
func Create(debug bool, cm *credentials.Manager, db *database.Database, dp *dispatcher.Dispatcher) *gin.Engine {
|
func Create(debug bool, cm *credentials.Manager, db *database.Database, dp *dispatcher.Dispatcher, alertmanagerConfig *configuration.Alertmanager) *gin.Engine {
|
||||||
log.Println("Setting up HTTP routes.")
|
log.Println("Setting up HTTP routes.")
|
||||||
|
|
||||||
if !debug {
|
if !debug {
|
||||||
|
@ -27,6 +29,10 @@ func Create(debug bool, cm *credentials.Manager, db *database.Database, dp *disp
|
||||||
healthHandler := api.HealthHandler{DB: db}
|
healthHandler := api.HealthHandler{DB: db}
|
||||||
notificationHandler := api.NotificationHandler{DB: db, DP: dp}
|
notificationHandler := api.NotificationHandler{DB: db, DP: dp}
|
||||||
userHandler := api.UserHandler{AH: &applicationHandler, CM: cm, DB: db, DP: dp}
|
userHandler := api.UserHandler{AH: &applicationHandler, CM: cm, DB: db, DP: dp}
|
||||||
|
alertmanagerHandler := alertmanager.AlertmanagerHandler{DP: dp, Settings: alertmanager.AlertmanagerHandlerSettings{
|
||||||
|
TitleAnnotation: alertmanagerConfig.AnnotationTitle,
|
||||||
|
MessageAnnotation: alertmanagerConfig.AnnotationMessage,
|
||||||
|
}}
|
||||||
|
|
||||||
r := gin.Default()
|
r := gin.Default()
|
||||||
|
|
||||||
|
@ -59,5 +65,7 @@ func Create(debug bool, cm *credentials.Manager, db *database.Database, dp *disp
|
||||||
userGroup.PUT("/:id", api.RequireIDInURI(), userHandler.UpdateUser)
|
userGroup.PUT("/:id", api.RequireIDInURI(), userHandler.UpdateUser)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
r.POST("/alert", auth.RequireApplicationToken(), alertmanagerHandler.CreateAlert)
|
||||||
|
|
||||||
return r
|
return r
|
||||||
}
|
}
|
||||||
|
|
Loading…
Add table
Add a link
Reference in a new issue