Files
cloudpods/pkg/monitor/models/notification.go
zhaoxiangchun b281ab8543 fix(monitor): monitor alert support multi robot
1. 机器人下放到域后监控报警支持
2021-09-26 16:36:24 +08:00

242 lines
7.3 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 models
import (
"context"
"database/sql"
"time"
"yunion.io/x/jsonutils"
"yunion.io/x/pkg/errors"
"yunion.io/x/sqlchemy"
"yunion.io/x/onecloud/pkg/apis/monitor"
"yunion.io/x/onecloud/pkg/cloudcommon/db"
"yunion.io/x/onecloud/pkg/httperrors"
"yunion.io/x/onecloud/pkg/mcclient"
merrors "yunion.io/x/onecloud/pkg/monitor/errors"
"yunion.io/x/onecloud/pkg/monitor/notifydrivers"
)
var (
NotificationManager *SNotificationManager
)
func init() {
NotificationManager = NewNotificationManager()
}
// +onecloud:swagger-gen-model-singular=alert_notification
// +onecloud:swagger-gen-model-plural=alert_notifications
type SNotificationManager struct {
db.SVirtualResourceBaseManager
}
type SAlertNotificationStateManager struct {
db.SStandaloneResourceBaseManager
}
func NewNotificationManager() *SNotificationManager {
man := &SNotificationManager{
SVirtualResourceBaseManager: db.NewVirtualResourceBaseManager(
SNotification{},
"notifications_tbl",
"alert_notification",
"alert_notifications",
),
}
man.SetAlias("notification", "notifications")
man.SetVirtualObject(man)
return man
}
type SNotification struct {
db.SVirtualResourceBase
Type string `nullable:"false" list:"user" create:"required"`
IsDefault bool `nullable:"false" default:"false" list:"user" create:"optional" update:"user"`
SendReminder bool `nullable:"false" default:"false" list:"user" create:"optional" update:"user"`
DisableResolveMessage bool `nullable:"false" default:"false" list:"user" create:"optional" update:"user"`
// unit is second
Frequency int64 `nullable:"false" default:"0" list:"user" create:"optional" update:"user"`
Settings jsonutils.JSONObject `nullable:"false" list:"user" create:"required" update:"user"`
LastSendNotification time.Time `list:"user" create:"optional" update:"user"`
}
func (man *SNotificationManager) GetPlugin(typ string) (*notifydrivers.NotifierPlugin, error) {
drv, err := notifydrivers.GetPlugin(typ)
if err != nil {
if errors.Cause(err) == notifydrivers.ErrUnsupportedNotificationType {
return nil, httperrors.NewInputParameterError("unsupported notification type %s", typ)
} else {
return nil, err
}
}
return drv, nil
}
func (man *SNotificationManager) GetNotification(id string) (*SNotification, error) {
obj, err := man.FetchById(id)
if err != nil {
if errors.Cause(err) == sql.ErrNoRows {
return nil, nil
}
return nil, err
}
return obj.(*SNotification), nil
}
func (man *SNotificationManager) GetNotifications(ids []string) ([]SNotification, error) {
objs := make([]SNotification, 0)
notis := man.Query().SubQuery()
q := notis.Query().Filter(sqlchemy.In(notis.Field("id"), ids))
if err := db.FetchModelObjects(man, q, &objs); err != nil {
if err == sql.ErrNoRows {
return nil, nil
}
return nil, err
}
return objs, nil
}
func (man *SNotificationManager) GetNotificationsWithDefault(ids []string) ([]SNotification, error) {
objs := make([]SNotification, 0)
notis := man.Query().SubQuery()
q := notis.Query().Filter(sqlchemy.In(notis.Field("id"), ids))
//sqlchemy.OR(
// sqlchemy.IsTrue(notis.Field("is_default")),
// sqlchemy.In(notis.Field("id"), ids)))
if err := db.FetchModelObjects(man, q, &objs); err != nil {
if err == sql.ErrNoRows {
return nil, nil
}
return nil, err
}
return objs, nil
}
func (man *SNotificationManager) ValidateCreateData(ctx context.Context, userCred mcclient.TokenCredential, ownerId mcclient.IIdentityProvider, _ jsonutils.JSONObject, input monitor.NotificationCreateInput) (monitor.NotificationCreateInput, error) {
if input.Type == "" {
return input, merrors.NewArgIsEmptyErr("type")
}
if input.SendReminder == nil {
sendReminder := true
input.SendReminder = &sendReminder
}
if input.DisableResolveMessage == nil {
dr := false
input.DisableResolveMessage = &dr
}
plug, err := man.GetPlugin(input.Type)
if err != nil {
return input, err
}
return plug.ValidateCreateData(userCred, input)
}
func (man *SNotificationManager) ListItemFilter(ctx context.Context, q *sqlchemy.SQuery,
userCred mcclient.TokenCredential, input monitor.NotificationListInput) (*sqlchemy.SQuery, error) {
q, err := man.SVirtualResourceBaseManager.ListItemFilter(ctx, q, userCred, input.VirtualResourceListInput)
if err != nil {
return nil, err
}
if len(input.Type) > 0 {
q = q.Equals("type", input.Type)
}
return q, err
}
func (man *SNotificationManager) CreateOneCloudNotification(ctx context.Context, userCred mcclient.TokenCredential, alertName string, channel string, userIds []string, robotIds []string, silentPeriod string) (*SNotification, error) {
settings := &monitor.NotificationSettingOneCloud{
Channel: channel,
UserIds: userIds,
RobotIds: robotIds,
}
newName, err := db.GenerateName(ctx, man, userCred, alertName)
if err != nil {
return nil, errors.Wrapf(err, "generate name: %s", alertName)
}
input := &monitor.NotificationCreateInput{
Name: newName,
Type: monitor.AlertNotificationTypeOneCloud,
Settings: jsonutils.Marshal(settings),
}
if silentPeriod != "" {
duration, _ := time.ParseDuration(silentPeriod)
input.Frequency = duration / time.Second
}
obj, err := db.DoCreate(man, ctx, userCred, nil, input.JSON(input), userCred)
if err != nil {
return nil, errors.Wrapf(err, "create notification input: %s", input.JSON(input))
}
return obj.(*SNotification), nil
}
func (n *SNotification) AttachToAlert(
ctx context.Context,
userCred mcclient.TokenCredential,
alertId string) (*SAlertnotification, error) {
alert, err := AlertManager.GetAlert(alertId)
if err != nil {
return nil, err
}
return alert.AttachNotification(ctx, userCred, n, monitor.AlertNotificationStateUnknown, "")
}
func (n *SNotification) GetAlertNotificationCount() (int, error) {
alertNotis := AlertNotificationManager.Query()
return alertNotis.Equals("notification_id", n.Id).CountWithError()
}
func (n *SNotification) IsAttached() (bool, error) {
cnt, err := n.GetAlertNotificationCount()
if err != nil {
return false, err
}
return cnt > 0, nil
}
func (n *SNotification) ValidateDeleteCondition(ctx context.Context, info jsonutils.JSONObject) error {
cnt, err := n.GetAlertNotificationCount()
if err != nil {
return err
}
if cnt > 0 {
return httperrors.NewNotEmptyError("Alert notification used by %d alert", cnt)
}
return n.SVirtualResourceBase.ValidateDeleteCondition(ctx, nil)
}
func (n *SNotification) ShouldSendNotification() bool {
if n.Frequency == 0 {
return true
}
if int64(time.Now().Sub(n.LastSendNotification)/time.Second)+int64(60) >= n.Frequency {
return true
}
return false
}
func (n *SNotification) UpdateSendTime() error {
_, err := db.Update(n, func() error {
n.LastSendNotification = time.Now()
return nil
})
return err
}