Files
cloudpods/pkg/monitor/alerting/notifiers/dingding.go

155 lines
4.5 KiB
Go

// Copyright 2019 Yunion
//
// Licensed under the Apache License, Version 2.0 (the "License");
// you may not use this file except in compliance with the License.
// You may obtain a copy of the License at
//
// http://www.apache.org/licenses/LICENSE-2.0
//
// Unless required by applicable law or agreed to in writing, software
// distributed under the License is distributed on an "AS IS" BASIS,
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
// See the License for the specific language governing permissions and
// limitations under the License.
package notifiers
import (
"encoding/json"
"net/url"
"yunion.io/x/jsonutils"
"yunion.io/x/log"
"yunion.io/x/pkg/errors"
"yunion.io/x/pkg/utils"
"yunion.io/x/onecloud/pkg/apis/monitor"
"yunion.io/x/onecloud/pkg/httperrors"
"yunion.io/x/onecloud/pkg/mcclient"
"yunion.io/x/onecloud/pkg/monitor/alerting"
"yunion.io/x/onecloud/pkg/monitor/alerting/notifiers/templates"
)
const (
defaultDingdingMsgType = DingdingMsgTypeMarkdown
DingdingMsgTypeLink = "link"
DingdingMsgTypeMarkdown = "markdown"
DingdingMsgTypeActionCard = "actionCard"
)
func init() {
alerting.RegisterNotifier(&alerting.NotifierPlugin{
Type: monitor.AlertNotificationTypeDingding,
Factory: newDingdingNotifier,
ValidateCreateData: func(cred mcclient.IIdentityProvider, input monitor.NotificationCreateInput) (monitor.NotificationCreateInput, error) {
settings := new(monitor.NotificationSettingDingding)
if err := input.Settings.Unmarshal(settings); err != nil {
return input, errors.Wrap(err, "unmarshal setting")
}
if settings.Url == "" {
return input, httperrors.NewInputParameterError("url is empty")
}
if _, err := url.Parse(settings.Url); err != nil {
return input, httperrors.NewInputParameterError("invalid url: %v", err)
}
if settings.MessageType == "" {
settings.MessageType = defaultDingdingMsgType
}
if !utils.IsInStringArray(settings.MessageType, []string{
DingdingMsgTypeMarkdown,
DingdingMsgTypeLink,
DingdingMsgTypeActionCard,
}) {
return input, httperrors.NewInputParameterError("unsupport type: %s", settings.MessageType)
}
input.Settings = jsonutils.Marshal(settings)
return input, nil
},
})
}
type DingDingNotifier struct {
NotifierBase
MsgType string
Url string
}
func newDingdingNotifier(config alerting.NotificationConfig) (alerting.Notifier, error) {
settings := new(monitor.NotificationSettingDingding)
if err := config.Settings.Unmarshal(settings); err != nil {
return nil, errors.Wrap(err, "unmarshal setting")
}
return &DingDingNotifier{
NotifierBase: NewNotifierBase(config),
Url: settings.Url,
MsgType: settings.MessageType,
}, nil
}
func (dd *DingDingNotifier) Notify(ctx *alerting.EvalContext, _ jsonutils.JSONObject) error {
log.Infof("Sending alert notification to dingding")
// msgUrl, err := ctx.GetRuleURL()
body, err := dd.genBody(ctx)
if err != nil {
return err
}
input := &monitor.SendWebhookSync{
Url: dd.Url,
Body: string(body),
}
return SendWebRequestSync(ctx.Ctx, input)
}
func (dd *DingDingNotifier) genBody(ctx *alerting.EvalContext) ([]byte, error) {
q := url.Values{
"pc_slide": {"false"},
// "url": {messageURL},
}
// Use special link to auto open the message url outside of Dingding
// Refer: https://open-doc.dingtalk.com/docs/doc.htm?treeId=385&articleId=104972&docType=1#s9
messageURL := "dingtalk://dingtalkclient/page/link?" + q.Encode()
log.Infof("messageUrl: " + messageURL)
config := GetNotifyTemplateConfig(ctx)
contentConfig := templates.NewTemplateConfig(config)
content, err := contentConfig.GenerateMarkdown()
if err != nil {
return nil, errors.Wrap(err, "build content")
}
var bodyMsg map[string]interface{}
switch dd.MsgType {
case DingdingMsgTypeMarkdown:
bodyMsg = map[string]interface{}{
"msgtype": DingdingMsgTypeMarkdown,
DingdingMsgTypeMarkdown: map[string]string{
"title": config.Title,
"text": content,
},
}
case DingdingMsgTypeActionCard:
bodyMsg = map[string]interface{}{
"msgtype": DingdingMsgTypeActionCard,
DingdingMsgTypeActionCard: map[string]string{
"text": content,
"title": config.Title,
// "singleTitle": "More",
// "singleURL": messageURL,
},
}
case DingdingMsgTypeLink:
bodyMsg = map[string]interface{}{
"msgtype": DingdingMsgTypeLink,
"link": map[string]string{
"text": content,
"title": config.Title,
// "messageUrl": messageURL,
},
}
}
return json.Marshal(bodyMsg)
}