add test api to send channel message

This commit is contained in:
liugq 2023-07-26 17:54:42 +08:00
parent 5f2569d999
commit d6d1013e0a
6 changed files with 141 additions and 117 deletions

View File

@ -33,6 +33,7 @@ func (alert *AlertAPI) Init() {
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.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/:alert_id", alert.RequirePermission(alert.getAlert, enum.PermissionAlertHistoryRead))

View File

@ -6,9 +6,11 @@ package alerting
import (
"fmt"
"infini.sh/console/service/alerting/common"
"net/http"
"strconv"
"strings"
"time"
log "github.com/cihub/seelog"
"infini.sh/console/model/alerting"
@ -33,10 +35,7 @@ func (h *AlertAPI) createChannel(w http.ResponseWriter, req *http.Request, ps ht
return
}
h.WriteJSON(w, util.MapStr{
"_id": obj.ID,
"result": "created",
}, 200)
h.WriteCreatedOKJSON(w, obj.ID)
}
@ -60,11 +59,7 @@ func (h *AlertAPI) getChannel(w http.ResponseWriter, req *http.Request, ps httpr
return
}
h.WriteJSON(w, util.MapStr{
"found": true,
"_id": id,
"_source": obj,
}, 200)
h.WriteGetOKJSON(w, id, obj)
}
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
}
h.WriteJSON(w, util.MapStr{
"_id": obj.ID,
"result": "updated",
}, 200)
h.WriteUpdatedOKJSON(w, id)
}
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)
}
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)
}

View File

@ -80,10 +80,7 @@ func (h *EmailAPI) createEmailServer(w http.ResponseWriter, req *http.Request, p
}
}
h.WriteJSON(w, util.MapStr{
"_id": obj.ID,
"result": "created",
}, 200)
h.WriteCreatedOKJSON(w, obj.ID)
}
@ -107,11 +104,7 @@ func (h *EmailAPI) getEmailServer(w http.ResponseWriter, req *http.Request, ps h
return
}
h.WriteJSON(w, util.MapStr{
"found": true,
"_id": id,
"_source": obj,
}, 200)
h.WriteGetOKJSON(w, id, obj)
}
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)
}
h.WriteJSON(w, util.MapStr{
"_id": obj.ID,
"result": "updated",
}, 200)
h.WriteUpdatedOKJSON(w, obj.ID)
}
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{
"_id": obj.ID,
"result": "deleted",
}, 200)
h.WriteDeletedOKJSON(w, obj.ID)
}
func checkEmailServerReferenced(srv *model.EmailServer) error {

View File

@ -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
}

View File

@ -5,7 +5,6 @@
package elasticsearch
import (
"bytes"
"context"
"fmt"
"github.com/Knetic/govaluate"
@ -13,8 +12,7 @@ import (
"infini.sh/console/model"
"infini.sh/console/model/alerting"
alerting2 "infini.sh/console/service/alerting"
"infini.sh/console/service/alerting/action"
"infini.sh/console/service/alerting/funcs"
"infini.sh/console/service/alerting/common"
"infini.sh/framework/core/elastic"
"infini.sh/console/model/insight"
"infini.sh/framework/core/kv"
@ -25,7 +23,6 @@ import (
"sort"
"strconv"
"strings"
"text/template"
"time"
)
@ -857,12 +854,12 @@ func attachTitleMessageToCtx(title, message string, paramsCtx map[string]interfa
tplBytes []byte
err error
)
tplBytes, err = resolveMessage(message, paramsCtx)
tplBytes, err = common.ResolveMessage(message, paramsCtx)
if err != nil {
return fmt.Errorf("resolve message template error: %w", err)
}
paramsCtx[alerting2.ParamMessage] = string(tplBytes)
tplBytes, err = resolveMessage(title, paramsCtx)
tplBytes, err = common.ResolveMessage(title, paramsCtx)
if err != nil {
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 actionResults []alerting.ActionExecutionResult
for _, channel := range channels {
resBytes, err, messageBytes := performChannel(&channel, ctx)
resBytes, err, messageBytes := common.PerformChannel(&channel, ctx)
var errStr string
if err != nil {
errCount++
@ -980,64 +977,8 @@ func performChannels(channels []alerting.Channel, ctx map[string]interface{}) ([
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) {
return func(ctx context.Context) {
defer func() {

View File

@ -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
}