notification.go 8.1 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256
  1. // Copyright 2019 Yunion
  2. //
  3. // Licensed under the Apache License, Version 2.0 (the "License");
  4. // you may not use this file except in compliance with the License.
  5. // You may obtain a copy of the License at
  6. //
  7. // http://www.apache.org/licenses/LICENSE-2.0
  8. //
  9. // Unless required by applicable law or agreed to in writing, software
  10. // distributed under the License is distributed on an "AS IS" BASIS,
  11. // WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
  12. // See the License for the specific language governing permissions and
  13. // limitations under the License.
  14. package models
  15. import (
  16. "context"
  17. "database/sql"
  18. "time"
  19. "yunion.io/x/jsonutils"
  20. "yunion.io/x/pkg/errors"
  21. "yunion.io/x/sqlchemy"
  22. "yunion.io/x/onecloud/pkg/apis/monitor"
  23. "yunion.io/x/onecloud/pkg/cloudcommon/db"
  24. "yunion.io/x/onecloud/pkg/httperrors"
  25. "yunion.io/x/onecloud/pkg/mcclient"
  26. merrors "yunion.io/x/onecloud/pkg/monitor/errors"
  27. "yunion.io/x/onecloud/pkg/monitor/notifydrivers"
  28. )
  29. var (
  30. NotificationManager *SNotificationManager
  31. )
  32. func init() {
  33. NotificationManager = NewNotificationManager()
  34. }
  35. // +onecloud:swagger-gen-model-singular=alert_notification
  36. // +onecloud:swagger-gen-model-plural=alert_notifications
  37. type SNotificationManager struct {
  38. db.SVirtualResourceBaseManager
  39. }
  40. func NewNotificationManager() *SNotificationManager {
  41. man := &SNotificationManager{
  42. SVirtualResourceBaseManager: db.NewVirtualResourceBaseManager(
  43. SNotification{},
  44. "notifications_tbl",
  45. "alert_notification",
  46. "alert_notifications",
  47. ),
  48. }
  49. man.SetAlias("notification", "notifications")
  50. man.SetVirtualObject(man)
  51. return man
  52. }
  53. type SNotification struct {
  54. db.SVirtualResourceBase
  55. Type string `nullable:"false" list:"user" create:"required"`
  56. IsDefault bool `nullable:"false" default:"false" list:"user" create:"optional" update:"user"`
  57. SendReminder bool `nullable:"false" default:"false" list:"user" create:"optional" update:"user"`
  58. DisableResolveMessage bool `nullable:"false" default:"false" list:"user" create:"optional" update:"user"`
  59. // unit is second
  60. Frequency int64 `nullable:"false" default:"0" list:"user" create:"optional" update:"user"`
  61. Settings jsonutils.JSONObject `nullable:"false" list:"user" create:"required" update:"user"`
  62. LastSendNotification time.Time `list:"user" create:"optional" update:"user"`
  63. }
  64. func (man *SNotificationManager) GetPlugin(typ string) (*notifydrivers.NotifierPlugin, error) {
  65. drv, err := notifydrivers.GetPlugin(typ)
  66. if err != nil {
  67. if errors.Cause(err) == notifydrivers.ErrUnsupportedNotificationType {
  68. return nil, httperrors.NewInputParameterError("unsupported notification type %s", typ)
  69. } else {
  70. return nil, err
  71. }
  72. }
  73. return drv, nil
  74. }
  75. func (man *SNotificationManager) GetNotification(id string) (*SNotification, error) {
  76. obj, err := man.FetchById(id)
  77. if err != nil {
  78. if errors.Cause(err) == sql.ErrNoRows {
  79. return nil, nil
  80. }
  81. return nil, err
  82. }
  83. return obj.(*SNotification), nil
  84. }
  85. func (man *SNotificationManager) GetNotifications(ids []string) ([]SNotification, error) {
  86. objs := make([]SNotification, 0)
  87. notis := man.Query().SubQuery()
  88. q := notis.Query().Filter(sqlchemy.In(notis.Field("id"), ids))
  89. if err := db.FetchModelObjects(man, q, &objs); err != nil {
  90. if err == sql.ErrNoRows {
  91. return nil, nil
  92. }
  93. return nil, err
  94. }
  95. return objs, nil
  96. }
  97. func (man *SNotificationManager) GetNotificationsWithDefault(ids []string) ([]SNotification, error) {
  98. objs := make([]SNotification, 0)
  99. notis := man.Query().SubQuery()
  100. q := notis.Query().Filter(sqlchemy.In(notis.Field("id"), ids))
  101. //sqlchemy.OR(
  102. // sqlchemy.IsTrue(notis.Field("is_default")),
  103. // sqlchemy.In(notis.Field("id"), ids)))
  104. if err := db.FetchModelObjects(man, q, &objs); err != nil {
  105. if err == sql.ErrNoRows {
  106. return nil, nil
  107. }
  108. return nil, err
  109. }
  110. return objs, nil
  111. }
  112. func (man *SNotificationManager) ValidateCreateData(ctx context.Context, userCred mcclient.TokenCredential, ownerId mcclient.IIdentityProvider, _ jsonutils.JSONObject, input monitor.NotificationCreateInput) (monitor.NotificationCreateInput, error) {
  113. if input.Type == "" {
  114. return input, merrors.NewArgIsEmptyErr("type")
  115. }
  116. if input.SendReminder == nil {
  117. sendReminder := true
  118. input.SendReminder = &sendReminder
  119. }
  120. if input.DisableResolveMessage == nil {
  121. dr := false
  122. input.DisableResolveMessage = &dr
  123. }
  124. plug, err := man.GetPlugin(input.Type)
  125. if err != nil {
  126. return input, err
  127. }
  128. return plug.ValidateCreateData(userCred, input)
  129. }
  130. func (man *SNotificationManager) ListItemFilter(ctx context.Context, q *sqlchemy.SQuery,
  131. userCred mcclient.TokenCredential, input monitor.NotificationListInput) (*sqlchemy.SQuery, error) {
  132. q, err := man.SVirtualResourceBaseManager.ListItemFilter(ctx, q, userCred, input.VirtualResourceListInput)
  133. if err != nil {
  134. return nil, err
  135. }
  136. if len(input.Type) > 0 {
  137. q = q.Equals("type", input.Type)
  138. }
  139. return q, err
  140. }
  141. func (man *SNotificationManager) CreateOneCloudNotification(ctx context.Context, userCred mcclient.TokenCredential, alertName string, settings *monitor.NotificationSettingOneCloud, silentPeriod string) (*SNotification, error) {
  142. newName, err := db.GenerateName(ctx, man, userCred, alertName)
  143. if err != nil {
  144. return nil, errors.Wrapf(err, "generate name: %s", alertName)
  145. }
  146. input := &monitor.NotificationCreateInput{
  147. Name: newName,
  148. Type: monitor.AlertNotificationTypeOneCloud,
  149. Settings: jsonutils.Marshal(settings),
  150. }
  151. if silentPeriod != "" {
  152. duration, _ := time.ParseDuration(silentPeriod)
  153. input.Frequency = duration / time.Second
  154. }
  155. return man.createNotification(ctx, userCred, input)
  156. }
  157. func (man *SNotificationManager) CreateAutoMigrationNotification(ctx context.Context, userCred mcclient.TokenCredential, alert *SMigrationAlert) (*SNotification, error) {
  158. alertName := alert.GetName()
  159. newName, err := db.GenerateName(ctx, man, userCred, alertName)
  160. if err != nil {
  161. return nil, errors.Wrapf(err, "generate name: %s", alertName)
  162. }
  163. settings := monitor.NotificationSettingAutoMigration{
  164. AlertId: alert.GetId(),
  165. }
  166. input := &monitor.NotificationCreateInput{
  167. Name: newName,
  168. Type: monitor.AlertNotificationTypeAutoMigration,
  169. Settings: jsonutils.Marshal(settings),
  170. }
  171. return man.createNotification(ctx, userCred, input)
  172. }
  173. func (man *SNotificationManager) createNotification(ctx context.Context, userCred mcclient.TokenCredential, input *monitor.NotificationCreateInput) (*SNotification, error) {
  174. obj, err := db.DoCreate(man, ctx, userCred, nil, input.JSON(input), userCred)
  175. if err != nil {
  176. return nil, errors.Wrapf(err, "create notification input: %s", input.JSON(input))
  177. }
  178. return obj.(*SNotification), nil
  179. }
  180. func (n *SNotification) AttachToAlert(
  181. ctx context.Context,
  182. userCred mcclient.TokenCredential,
  183. alertId string) (*SAlertnotification, error) {
  184. alert, err := AlertManager.GetAlert(alertId)
  185. if err != nil {
  186. return nil, err
  187. }
  188. return alert.AttachNotification(ctx, userCred, n, monitor.AlertNotificationStateUnknown, "")
  189. }
  190. func (n *SNotification) GetAlertNotificationCount() (int, error) {
  191. alertNotis := AlertNotificationManager.Query()
  192. return alertNotis.Equals("notification_id", n.Id).CountWithError()
  193. }
  194. func (n *SNotification) IsAttached() (bool, error) {
  195. cnt, err := n.GetAlertNotificationCount()
  196. if err != nil {
  197. return false, err
  198. }
  199. return cnt > 0, nil
  200. }
  201. func (n *SNotification) ValidateDeleteCondition(ctx context.Context, info jsonutils.JSONObject) error {
  202. cnt, err := n.GetAlertNotificationCount()
  203. if err != nil {
  204. return err
  205. }
  206. if cnt > 0 {
  207. return httperrors.NewNotEmptyError("Alert notification used by %d alert", cnt)
  208. }
  209. return n.SVirtualResourceBase.ValidateDeleteCondition(ctx, nil)
  210. }
  211. func (n *SNotification) ShouldSendNotification() bool {
  212. if n.Frequency == 0 {
  213. return true
  214. }
  215. // 如果从未发送过通知(LastSendNotification 为零值),允许第一次发送
  216. if n.LastSendNotification.IsZero() {
  217. return true
  218. }
  219. if int64(time.Since(n.LastSendNotification)/time.Second)+int64(60) >= n.Frequency {
  220. return true
  221. }
  222. return false
  223. }
  224. func (n *SNotification) UpdateSendTime() error {
  225. _, err := db.Update(n, func() error {
  226. n.LastSendNotification = time.Now()
  227. return nil
  228. })
  229. return err
  230. }