add test api to send channel message
This commit is contained in:
parent
5f2569d999
commit
d6d1013e0a
|
@ -33,6 +33,7 @@ func (alert *AlertAPI) Init() {
|
||||||
api.HandleAPIMethod(api.DELETE, "/alerting/channel", alert.RequirePermission(alert.deleteChannel, enum.PermissionAlertChannelWrite))
|
api.HandleAPIMethod(api.DELETE, "/alerting/channel", alert.RequirePermission(alert.deleteChannel, enum.PermissionAlertChannelWrite))
|
||||||
api.HandleAPIMethod(api.PUT, "/alerting/channel/:channel_id", alert.RequirePermission(alert.updateChannel, enum.PermissionAlertChannelWrite))
|
api.HandleAPIMethod(api.PUT, "/alerting/channel/:channel_id", alert.RequirePermission(alert.updateChannel, enum.PermissionAlertChannelWrite))
|
||||||
api.HandleAPIMethod(api.GET, "/alerting/channel/_search", alert.RequirePermission(alert.searchChannel, enum.PermissionAlertChannelRead))
|
api.HandleAPIMethod(api.GET, "/alerting/channel/_search", alert.RequirePermission(alert.searchChannel, enum.PermissionAlertChannelRead))
|
||||||
|
api.HandleAPIMethod(api.POST, "/alerting/channel/test", alert.RequirePermission(alert.testChannel, enum.PermissionAlertChannelWrite))
|
||||||
|
|
||||||
api.HandleAPIMethod(api.GET, "/alerting/alert/_search", alert.RequirePermission(alert.searchAlert, enum.PermissionAlertHistoryRead))
|
api.HandleAPIMethod(api.GET, "/alerting/alert/_search", alert.RequirePermission(alert.searchAlert, enum.PermissionAlertHistoryRead))
|
||||||
api.HandleAPIMethod(api.GET, "/alerting/alert/:alert_id", alert.RequirePermission(alert.getAlert, enum.PermissionAlertHistoryRead))
|
api.HandleAPIMethod(api.GET, "/alerting/alert/:alert_id", alert.RequirePermission(alert.getAlert, enum.PermissionAlertHistoryRead))
|
||||||
|
|
|
@ -6,9 +6,11 @@ package alerting
|
||||||
|
|
||||||
import (
|
import (
|
||||||
"fmt"
|
"fmt"
|
||||||
|
"infini.sh/console/service/alerting/common"
|
||||||
"net/http"
|
"net/http"
|
||||||
"strconv"
|
"strconv"
|
||||||
"strings"
|
"strings"
|
||||||
|
"time"
|
||||||
|
|
||||||
log "github.com/cihub/seelog"
|
log "github.com/cihub/seelog"
|
||||||
"infini.sh/console/model/alerting"
|
"infini.sh/console/model/alerting"
|
||||||
|
@ -33,10 +35,7 @@ func (h *AlertAPI) createChannel(w http.ResponseWriter, req *http.Request, ps ht
|
||||||
return
|
return
|
||||||
}
|
}
|
||||||
|
|
||||||
h.WriteJSON(w, util.MapStr{
|
h.WriteCreatedOKJSON(w, obj.ID)
|
||||||
"_id": obj.ID,
|
|
||||||
"result": "created",
|
|
||||||
}, 200)
|
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -60,11 +59,7 @@ func (h *AlertAPI) getChannel(w http.ResponseWriter, req *http.Request, ps httpr
|
||||||
return
|
return
|
||||||
}
|
}
|
||||||
|
|
||||||
h.WriteJSON(w, util.MapStr{
|
h.WriteGetOKJSON(w, id, obj)
|
||||||
"found": true,
|
|
||||||
"_id": id,
|
|
||||||
"_source": obj,
|
|
||||||
}, 200)
|
|
||||||
}
|
}
|
||||||
|
|
||||||
func (h *AlertAPI) updateChannel(w http.ResponseWriter, req *http.Request, ps httprouter.Params) {
|
func (h *AlertAPI) updateChannel(w http.ResponseWriter, req *http.Request, ps httprouter.Params) {
|
||||||
|
@ -101,10 +96,7 @@ func (h *AlertAPI) updateChannel(w http.ResponseWriter, req *http.Request, ps ht
|
||||||
return
|
return
|
||||||
}
|
}
|
||||||
|
|
||||||
h.WriteJSON(w, util.MapStr{
|
h.WriteUpdatedOKJSON(w, id)
|
||||||
"_id": obj.ID,
|
|
||||||
"result": "updated",
|
|
||||||
}, 200)
|
|
||||||
}
|
}
|
||||||
|
|
||||||
func (h *AlertAPI) deleteChannel(w http.ResponseWriter, req *http.Request, ps httprouter.Params) {
|
func (h *AlertAPI) deleteChannel(w http.ResponseWriter, req *http.Request, ps httprouter.Params) {
|
||||||
|
@ -179,3 +171,43 @@ func (h *AlertAPI) searchChannel(w http.ResponseWriter, req *http.Request, ps ht
|
||||||
}
|
}
|
||||||
h.Write(w, res.Raw)
|
h.Write(w, res.Raw)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
func (h *AlertAPI) testChannel(w http.ResponseWriter, req *http.Request, ps httprouter.Params) {
|
||||||
|
obj := alerting.Channel{}
|
||||||
|
err := h.DecodeJSON(req, &obj)
|
||||||
|
if err != nil {
|
||||||
|
h.WriteError(w, err.Error(), http.StatusInternalServerError)
|
||||||
|
log.Error(err)
|
||||||
|
return
|
||||||
|
}
|
||||||
|
ctx := map[string]interface{}{
|
||||||
|
"title": "test title",
|
||||||
|
"message": "test message",
|
||||||
|
"rule_id": util.GetUUID(),
|
||||||
|
"rule_name": "test rule",
|
||||||
|
"resource_id": util.GetUUID(),
|
||||||
|
"resource_name": "test resource",
|
||||||
|
"event_id": util.GetUUID(),
|
||||||
|
"timestamp": time.Now().UnixMilli(),
|
||||||
|
"first_group_value": "first group value",
|
||||||
|
"first_threshold": "90",
|
||||||
|
"priority": "critical",
|
||||||
|
"results": []util.MapStr{
|
||||||
|
{"threshold": "90",
|
||||||
|
"priority": "critical",
|
||||||
|
"group_values": []string{"first group value", "second group value"},
|
||||||
|
"issue_timestamp": time.Now().UnixMilli()-500,
|
||||||
|
"result_value": 90,
|
||||||
|
"relation_values": util.MapStr{"a": 100, "b": 90},
|
||||||
|
},
|
||||||
|
},
|
||||||
|
|
||||||
|
}
|
||||||
|
_, err, _ = common.PerformChannel(&obj, ctx)
|
||||||
|
if err != nil {
|
||||||
|
h.WriteError(w, err.Error(), http.StatusInternalServerError)
|
||||||
|
log.Error(err)
|
||||||
|
return
|
||||||
|
}
|
||||||
|
h.WriteAckOKJSON(w)
|
||||||
|
}
|
|
@ -80,10 +80,7 @@ func (h *EmailAPI) createEmailServer(w http.ResponseWriter, req *http.Request, p
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
h.WriteJSON(w, util.MapStr{
|
h.WriteCreatedOKJSON(w, obj.ID)
|
||||||
"_id": obj.ID,
|
|
||||||
"result": "created",
|
|
||||||
}, 200)
|
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -107,11 +104,7 @@ func (h *EmailAPI) getEmailServer(w http.ResponseWriter, req *http.Request, ps h
|
||||||
return
|
return
|
||||||
}
|
}
|
||||||
|
|
||||||
h.WriteJSON(w, util.MapStr{
|
h.WriteGetOKJSON(w, id, obj)
|
||||||
"found": true,
|
|
||||||
"_id": id,
|
|
||||||
"_source": obj,
|
|
||||||
}, 200)
|
|
||||||
}
|
}
|
||||||
|
|
||||||
func (h *EmailAPI) updateEmailServer(w http.ResponseWriter, req *http.Request, ps httprouter.Params) {
|
func (h *EmailAPI) updateEmailServer(w http.ResponseWriter, req *http.Request, ps httprouter.Params) {
|
||||||
|
@ -161,10 +154,7 @@ func (h *EmailAPI) updateEmailServer(w http.ResponseWriter, req *http.Request, p
|
||||||
log.Error(err)
|
log.Error(err)
|
||||||
}
|
}
|
||||||
|
|
||||||
h.WriteJSON(w, util.MapStr{
|
h.WriteUpdatedOKJSON(w, obj.ID)
|
||||||
"_id": obj.ID,
|
|
||||||
"result": "updated",
|
|
||||||
}, 200)
|
|
||||||
}
|
}
|
||||||
|
|
||||||
func (h *EmailAPI) deleteEmailServer(w http.ResponseWriter, req *http.Request, ps httprouter.Params) {
|
func (h *EmailAPI) deleteEmailServer(w http.ResponseWriter, req *http.Request, ps httprouter.Params) {
|
||||||
|
@ -202,10 +192,7 @@ func (h *EmailAPI) deleteEmailServer(w http.ResponseWriter, req *http.Request, p
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
h.WriteJSON(w, util.MapStr{
|
h.WriteDeletedOKJSON(w, obj.ID)
|
||||||
"_id": obj.ID,
|
|
||||||
"result": "deleted",
|
|
||||||
}, 200)
|
|
||||||
}
|
}
|
||||||
|
|
||||||
func checkEmailServerReferenced(srv *model.EmailServer) error {
|
func checkEmailServerReferenced(srv *model.EmailServer) error {
|
||||||
|
|
|
@ -0,0 +1,87 @@
|
||||||
|
/* Copyright © INFINI Ltd. All rights reserved.
|
||||||
|
* Web: https://infinilabs.com
|
||||||
|
* Email: hello#infini.ltd */
|
||||||
|
|
||||||
|
package common
|
||||||
|
|
||||||
|
import (
|
||||||
|
"bytes"
|
||||||
|
"fmt"
|
||||||
|
"infini.sh/console/model/alerting"
|
||||||
|
"infini.sh/console/service/alerting/action"
|
||||||
|
"infini.sh/console/service/alerting/funcs"
|
||||||
|
"infini.sh/framework/core/orm"
|
||||||
|
"text/template"
|
||||||
|
)
|
||||||
|
|
||||||
|
func PerformChannel(channel *alerting.Channel, ctx map[string]interface{}) ([]byte, error, []byte) {
|
||||||
|
var (
|
||||||
|
act action.Action
|
||||||
|
message []byte
|
||||||
|
err error
|
||||||
|
)
|
||||||
|
channel, err = RetrieveChannel(channel)
|
||||||
|
if err != nil {
|
||||||
|
return nil, err, nil
|
||||||
|
}
|
||||||
|
switch channel.Type {
|
||||||
|
|
||||||
|
case alerting.ChannelWebhook:
|
||||||
|
message, err = ResolveMessage(channel.Webhook.Body, ctx)
|
||||||
|
if err != nil {
|
||||||
|
return nil, err, message
|
||||||
|
}
|
||||||
|
wh := *channel.Webhook
|
||||||
|
urlBytes, err := ResolveMessage(wh.URL, ctx)
|
||||||
|
if err != nil {
|
||||||
|
return nil, err, message
|
||||||
|
}
|
||||||
|
wh.URL = string(urlBytes)
|
||||||
|
act = &action.WebhookAction{
|
||||||
|
Data: &wh,
|
||||||
|
Message: string(message),
|
||||||
|
}
|
||||||
|
case alerting.ChannelEmail:
|
||||||
|
message, err = ResolveMessage(channel.Email.Body, ctx)
|
||||||
|
if err != nil {
|
||||||
|
return nil, err, message
|
||||||
|
}
|
||||||
|
subjectBytes, err := ResolveMessage(channel.Email.Subject, ctx)
|
||||||
|
if err != nil {
|
||||||
|
return nil, err, nil
|
||||||
|
}
|
||||||
|
act = &action.EmailAction{
|
||||||
|
Data: channel.Email,
|
||||||
|
Subject: string(subjectBytes),
|
||||||
|
Body: string(message),
|
||||||
|
}
|
||||||
|
default:
|
||||||
|
return nil, fmt.Errorf("unsupported action type: %s", channel.Type), message
|
||||||
|
}
|
||||||
|
executeResult, err := act.Execute()
|
||||||
|
return executeResult, err, message
|
||||||
|
}
|
||||||
|
|
||||||
|
func ResolveMessage(messageTemplate string, ctx map[string]interface{}) ([]byte, error){
|
||||||
|
msg := messageTemplate
|
||||||
|
tmpl, err := template.New("alert-message").Funcs(funcs.GenericFuncMap()).Parse(msg)
|
||||||
|
if err !=nil {
|
||||||
|
return nil, fmt.Errorf("parse message temlate error: %w", err)
|
||||||
|
}
|
||||||
|
msgBuffer := &bytes.Buffer{}
|
||||||
|
err = tmpl.Execute(msgBuffer, ctx)
|
||||||
|
return msgBuffer.Bytes(), err
|
||||||
|
}
|
||||||
|
|
||||||
|
func RetrieveChannel(ch *alerting.Channel) (*alerting.Channel, error) {
|
||||||
|
if ch == nil {
|
||||||
|
return nil, fmt.Errorf("empty channel")
|
||||||
|
}
|
||||||
|
if ch.ID != "" {
|
||||||
|
_, err := orm.Get(ch)
|
||||||
|
if err != nil {
|
||||||
|
return nil, err
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return ch, nil
|
||||||
|
}
|
|
@ -5,7 +5,6 @@
|
||||||
package elasticsearch
|
package elasticsearch
|
||||||
|
|
||||||
import (
|
import (
|
||||||
"bytes"
|
|
||||||
"context"
|
"context"
|
||||||
"fmt"
|
"fmt"
|
||||||
"github.com/Knetic/govaluate"
|
"github.com/Knetic/govaluate"
|
||||||
|
@ -13,8 +12,7 @@ import (
|
||||||
"infini.sh/console/model"
|
"infini.sh/console/model"
|
||||||
"infini.sh/console/model/alerting"
|
"infini.sh/console/model/alerting"
|
||||||
alerting2 "infini.sh/console/service/alerting"
|
alerting2 "infini.sh/console/service/alerting"
|
||||||
"infini.sh/console/service/alerting/action"
|
"infini.sh/console/service/alerting/common"
|
||||||
"infini.sh/console/service/alerting/funcs"
|
|
||||||
"infini.sh/framework/core/elastic"
|
"infini.sh/framework/core/elastic"
|
||||||
"infini.sh/console/model/insight"
|
"infini.sh/console/model/insight"
|
||||||
"infini.sh/framework/core/kv"
|
"infini.sh/framework/core/kv"
|
||||||
|
@ -25,7 +23,6 @@ import (
|
||||||
"sort"
|
"sort"
|
||||||
"strconv"
|
"strconv"
|
||||||
"strings"
|
"strings"
|
||||||
"text/template"
|
|
||||||
"time"
|
"time"
|
||||||
)
|
)
|
||||||
|
|
||||||
|
@ -857,12 +854,12 @@ func attachTitleMessageToCtx(title, message string, paramsCtx map[string]interfa
|
||||||
tplBytes []byte
|
tplBytes []byte
|
||||||
err error
|
err error
|
||||||
)
|
)
|
||||||
tplBytes, err = resolveMessage(message, paramsCtx)
|
tplBytes, err = common.ResolveMessage(message, paramsCtx)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return fmt.Errorf("resolve message template error: %w", err)
|
return fmt.Errorf("resolve message template error: %w", err)
|
||||||
}
|
}
|
||||||
paramsCtx[alerting2.ParamMessage] = string(tplBytes)
|
paramsCtx[alerting2.ParamMessage] = string(tplBytes)
|
||||||
tplBytes, err = resolveMessage(title, paramsCtx)
|
tplBytes, err = common.ResolveMessage(title, paramsCtx)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return fmt.Errorf("resolve title template error: %w", err)
|
return fmt.Errorf("resolve title template error: %w", err)
|
||||||
}
|
}
|
||||||
|
@ -962,7 +959,7 @@ func performChannels(channels []alerting.Channel, ctx map[string]interface{}) ([
|
||||||
var errCount int
|
var errCount int
|
||||||
var actionResults []alerting.ActionExecutionResult
|
var actionResults []alerting.ActionExecutionResult
|
||||||
for _, channel := range channels {
|
for _, channel := range channels {
|
||||||
resBytes, err, messageBytes := performChannel(&channel, ctx)
|
resBytes, err, messageBytes := common.PerformChannel(&channel, ctx)
|
||||||
var errStr string
|
var errStr string
|
||||||
if err != nil {
|
if err != nil {
|
||||||
errCount++
|
errCount++
|
||||||
|
@ -980,64 +977,8 @@ func performChannels(channels []alerting.Channel, ctx map[string]interface{}) ([
|
||||||
return actionResults, errCount
|
return actionResults, errCount
|
||||||
}
|
}
|
||||||
|
|
||||||
func resolveMessage(messageTemplate string, ctx map[string]interface{}) ([]byte, error){
|
|
||||||
msg := messageTemplate
|
|
||||||
tmpl, err := template.New("alert-message").Funcs(funcs.GenericFuncMap()).Parse(msg)
|
|
||||||
if err !=nil {
|
|
||||||
return nil, fmt.Errorf("parse message temlate error: %w", err)
|
|
||||||
}
|
|
||||||
msgBuffer := &bytes.Buffer{}
|
|
||||||
err = tmpl.Execute(msgBuffer, ctx)
|
|
||||||
return msgBuffer.Bytes(), err
|
|
||||||
}
|
|
||||||
|
|
||||||
func performChannel(channel *alerting.Channel, ctx map[string]interface{}) ([]byte, error, []byte) {
|
|
||||||
var (
|
|
||||||
act action.Action
|
|
||||||
message []byte
|
|
||||||
err error
|
|
||||||
)
|
|
||||||
channel, err = RetrieveChannel(channel)
|
|
||||||
if err != nil {
|
|
||||||
return nil, err, nil
|
|
||||||
}
|
|
||||||
switch channel.Type {
|
|
||||||
|
|
||||||
case alerting.ChannelWebhook:
|
|
||||||
message, err = resolveMessage(channel.Webhook.Body, ctx)
|
|
||||||
if err != nil {
|
|
||||||
return nil, err, message
|
|
||||||
}
|
|
||||||
wh := *channel.Webhook
|
|
||||||
urlBytes, err := resolveMessage(wh.URL, ctx)
|
|
||||||
if err != nil {
|
|
||||||
return nil, err, message
|
|
||||||
}
|
|
||||||
wh.URL = string(urlBytes)
|
|
||||||
act = &action.WebhookAction{
|
|
||||||
Data: &wh,
|
|
||||||
Message: string(message),
|
|
||||||
}
|
|
||||||
case alerting.ChannelEmail:
|
|
||||||
message, err = resolveMessage(channel.Email.Body, ctx)
|
|
||||||
if err != nil {
|
|
||||||
return nil, err, message
|
|
||||||
}
|
|
||||||
subjectBytes, err := resolveMessage(channel.Email.Subject, ctx)
|
|
||||||
if err != nil {
|
|
||||||
return nil, err, nil
|
|
||||||
}
|
|
||||||
act = &action.EmailAction{
|
|
||||||
Data: channel.Email,
|
|
||||||
Subject: string(subjectBytes),
|
|
||||||
Body: string(message),
|
|
||||||
}
|
|
||||||
default:
|
|
||||||
return nil, fmt.Errorf("unsupported action type: %s", channel.Type), message
|
|
||||||
}
|
|
||||||
executeResult, err := act.Execute()
|
|
||||||
return executeResult, err, message
|
|
||||||
}
|
|
||||||
func (engine *Engine) GenerateTask(rule alerting.Rule) func(ctx context.Context) {
|
func (engine *Engine) GenerateTask(rule alerting.Rule) func(ctx context.Context) {
|
||||||
return func(ctx context.Context) {
|
return func(ctx context.Context) {
|
||||||
defer func() {
|
defer func() {
|
||||||
|
|
|
@ -1,24 +0,0 @@
|
||||||
/* Copyright © INFINI Ltd. All rights reserved.
|
|
||||||
* Web: https://infinilabs.com
|
|
||||||
* Email: hello#infini.ltd */
|
|
||||||
|
|
||||||
package elasticsearch
|
|
||||||
|
|
||||||
import (
|
|
||||||
"fmt"
|
|
||||||
"infini.sh/console/model/alerting"
|
|
||||||
"infini.sh/framework/core/orm"
|
|
||||||
)
|
|
||||||
|
|
||||||
func RetrieveChannel(ch *alerting.Channel) (*alerting.Channel, error) {
|
|
||||||
if ch == nil {
|
|
||||||
return nil, fmt.Errorf("empty channel")
|
|
||||||
}
|
|
||||||
if ch.ID != "" {
|
|
||||||
_, err := orm.Get(ch)
|
|
||||||
if err != nil {
|
|
||||||
return nil, err
|
|
||||||
}
|
|
||||||
}
|
|
||||||
return ch, nil
|
|
||||||
}
|
|
Loading…
Reference in New Issue