Files
cloudpods/pkg/monitor/models/notification.go

257 lines
8.1 KiB
Go
Raw Permalink Blame History

This file contains ambiguous Unicode characters
This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.
// 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
}