ntfy-alertmanager/silence.go
Thorben Günther c919ec9af2
Add ability to silence alerts with ntfy action
For now only for the single alert mode.
This is implemented as an action button, that will send an API request
to ntfy-alertmanager itself instead of Alertmanager. Here ntfy-alertmanager
acts as a proxy and will then do the API request for actually creating
the silence in Alertmanager.
This is founded in a limitation of ntfy, that seemingly does not allow a
json body with more than one key.
2023-02-12 03:04:17 +01:00

116 lines
2.5 KiB
Go

package main
import (
"bytes"
"encoding/base64"
"encoding/json"
"io"
"net/http"
"time"
)
const dateLayout = "2006-01-02 15:04:05"
type silence struct {
Matchers []matcher `json:"matchers"`
StartsAt string `json:"startsAt"`
EndsAt string `json:"endsAt"`
CreatedBy string `json:"createdBy"`
Comment string `json:"comment"`
}
type matcher struct {
Name string `json:"name"`
Value string `json:"value"`
IsRegex bool `json:"isRegex"`
IsEqual bool `json:"isEqual"`
}
type silenceBody struct {
AlertManagerURL string `json:"alertmanagerURL"`
Labels map[string]interface{} `json:"labels"`
}
func (rcv *receiver) handleSilences(w http.ResponseWriter, r *http.Request) {
defer r.Body.Close()
if r.Method != http.MethodPost {
http.Error(w, "Only POST allowed", http.StatusMethodNotAllowed)
rcv.logger.Debugf("silences: illegal HTTP method: expected %q, got %q", "POST", r.Method)
return
}
b, err := io.ReadAll(r.Body)
if err != nil {
rcv.logger.Debugf("silences: %v", err)
return
}
b, err = base64.StdEncoding.DecodeString(string(b))
if err != nil {
rcv.logger.Debugf("silences: %v", err)
return
}
var sb silenceBody
err = json.Unmarshal(b, &sb)
if err != nil {
rcv.logger.Debugf("silences: %v", err)
return
}
var matchers []matcher
for key, value := range sb.Labels {
m := matcher{
Name: key,
Value: value.(string),
IsRegex: false,
IsEqual: true,
}
matchers = append(matchers, m)
}
silence := &silence{
StartsAt: time.Now().UTC().Format(dateLayout),
EndsAt: time.Now().Add(rcv.cfg.am.SilenceDuration).UTC().Format(dateLayout),
CreatedBy: "ntfy-alertmanager",
Comment: "",
Matchers: matchers,
}
b, err = json.Marshal(silence)
if err != nil {
rcv.logger.Debugf("silences: %v", err)
return
}
client := &http.Client{Timeout: time.Second * 3}
url := sb.AlertManagerURL + "/api/v2/silences"
req, err := http.NewRequest(http.MethodPost, url, bytes.NewBuffer(b))
if err != nil {
rcv.logger.Debugf("silences: %v", err)
return
}
req.Header.Add("Content-Type", "application/json")
resp, err := client.Do(req)
if err != nil {
rcv.logger.Debugf("silences: %v", err)
return
}
defer resp.Body.Close()
b, err = io.ReadAll(resp.Body)
if err != nil {
rcv.logger.Debugf("silences: %v", err)
return
}
if resp.StatusCode != http.StatusOK {
rcv.logger.Debugf("silences: received status code %d", resp.StatusCode)
return
}
rcv.logger.Debugf("silences: created new silence %s", string(b))
}