mirror of
https://github.com/yunionio/cloudpods.git
synced 2026-06-05 02:32:27 +08:00
257 lines
8.1 KiB
Go
257 lines
8.1 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
|
||
}
|
||
|
||
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, settings *monitor.NotificationSettingOneCloud, silentPeriod string) (*SNotification, error) {
|
||
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
|
||
}
|
||
return man.createNotification(ctx, userCred, input)
|
||
}
|
||
|
||
func (man *SNotificationManager) CreateAutoMigrationNotification(ctx context.Context, userCred mcclient.TokenCredential, alert *SMigrationAlert) (*SNotification, error) {
|
||
alertName := alert.GetName()
|
||
newName, err := db.GenerateName(ctx, man, userCred, alertName)
|
||
if err != nil {
|
||
return nil, errors.Wrapf(err, "generate name: %s", alertName)
|
||
}
|
||
settings := monitor.NotificationSettingAutoMigration{
|
||
AlertId: alert.GetId(),
|
||
}
|
||
input := &monitor.NotificationCreateInput{
|
||
Name: newName,
|
||
Type: monitor.AlertNotificationTypeAutoMigration,
|
||
Settings: jsonutils.Marshal(settings),
|
||
}
|
||
return man.createNotification(ctx, userCred, input)
|
||
}
|
||
|
||
func (man *SNotificationManager) createNotification(ctx context.Context, userCred mcclient.TokenCredential, input *monitor.NotificationCreateInput) (*SNotification, error) {
|
||
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
|
||
}
|
||
// 如果从未发送过通知(LastSendNotification 为零值),允许第一次发送
|
||
if n.LastSendNotification.IsZero() {
|
||
return true
|
||
}
|
||
if int64(time.Since(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
|
||
}
|