onecloud.go 18 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587588589590591592593594595596597598599600601602603604605606607608609610611612613614615616617618619
  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 notifiers
  15. import (
  16. "context"
  17. "fmt"
  18. "html/template"
  19. "strings"
  20. "golang.org/x/sync/errgroup"
  21. "golang.org/x/text/language"
  22. "yunion.io/x/jsonutils"
  23. "yunion.io/x/log"
  24. "yunion.io/x/pkg/appctx"
  25. "yunion.io/x/pkg/errors"
  26. "yunion.io/x/pkg/util/rbacscope"
  27. "yunion.io/x/pkg/util/sets"
  28. "yunion.io/x/onecloud/pkg/apis/monitor"
  29. "yunion.io/x/onecloud/pkg/cloudcommon/db"
  30. "yunion.io/x/onecloud/pkg/cloudcommon/notifyclient"
  31. "yunion.io/x/onecloud/pkg/hostman/hostinfo/hostconsts"
  32. "yunion.io/x/onecloud/pkg/httperrors"
  33. "yunion.io/x/onecloud/pkg/i18n"
  34. "yunion.io/x/onecloud/pkg/mcclient"
  35. "yunion.io/x/onecloud/pkg/mcclient/auth"
  36. modules "yunion.io/x/onecloud/pkg/mcclient/modules/identity"
  37. "yunion.io/x/onecloud/pkg/mcclient/modules/notify"
  38. "yunion.io/x/onecloud/pkg/monitor/alerting"
  39. "yunion.io/x/onecloud/pkg/monitor/alerting/notifiers/templates"
  40. "yunion.io/x/onecloud/pkg/monitor/models"
  41. "yunion.io/x/onecloud/pkg/monitor/options"
  42. )
  43. // generateMonitorTitle 生成监控告警的标题
  44. func generateMonitorTitle(suffix string, data interface{}) string {
  45. // 将 interface{} 转换为 map 以便访问字段
  46. dataMap, ok := data.(map[string]interface{})
  47. if !ok {
  48. return ""
  49. }
  50. // 获取字段值
  51. priority, _ := dataMap["priority"].(string)
  52. name, _ := dataMap["name"].(string)
  53. isRecovery, _ := dataMap["is_recovery"].(bool)
  54. noData, _ := dataMap["no_data"].(bool)
  55. // 根据语言设置级别文本
  56. var level string
  57. if suffix == "cn" {
  58. level = "普通"
  59. if priority == string(notify.NotifyPriorityImportant) {
  60. level = "重要"
  61. } else if priority == string(notify.NotifyPriorityCritical) {
  62. level = "致命"
  63. }
  64. } else {
  65. level = "Normal"
  66. if priority == string(notify.NotifyPriorityImportant) {
  67. level = "Important"
  68. } else if priority == string(notify.NotifyPriorityCritical) {
  69. level = "Critical"
  70. }
  71. }
  72. // 根据语言和状态设置提示消息
  73. var hintMsg string
  74. if suffix == "cn" {
  75. hintMsg = "发生告警"
  76. if isRecovery {
  77. hintMsg = "告警已恢复"
  78. } else if noData {
  79. hintMsg = "暂无数据"
  80. }
  81. } else {
  82. hintMsg = "Alerting"
  83. if isRecovery {
  84. hintMsg = "Alarm recovered"
  85. } else if noData {
  86. hintMsg = "No data available"
  87. }
  88. }
  89. return fmt.Sprintf("[%s] [%s] %s", level, hintMsg, name)
  90. }
  91. // monitorTitleLangFunc 实现 LangSuffixFunc 接口,用于生成监控标题
  92. type monitorTitleLangFunc struct{}
  93. func (f *monitorTitleLangFunc) Call(langSuffix string, data interface{}) string {
  94. return generateMonitorTitle(langSuffix, data)
  95. }
  96. // getMonitorTemplateFuncs 根据语言后缀创建监控模板函数映射
  97. // 注意:这里返回的函数实现了 LangSuffixFunc 接口,langSuffix 会在 getTemplate 中动态传入
  98. func getMonitorTemplateFuncs() template.FuncMap {
  99. return template.FuncMap{
  100. "monitorTitle": &monitorTitleLangFunc{},
  101. }
  102. }
  103. const (
  104. SUFFIX = "onecloudNotifier"
  105. MOBILE_DEFAULT_TOPIC_CN = "monitor-cn"
  106. MOBILE_DEFAULT_TOPIC_EN = "monitor-en"
  107. MOBILE_METER_TOPIC_CN = "meter-cn"
  108. MOBILE_METER_TOPIC_EN = "meter-en"
  109. )
  110. var (
  111. i18nTable = i18n.Table{}
  112. i18nEnTry = i18n.NewTableEntry().EN("en").CN("cn")
  113. )
  114. func init() {
  115. i18nTable.Set(SUFFIX, i18nEnTry)
  116. alerting.RegisterNotifier(&alerting.NotifierPlugin{
  117. Type: monitor.AlertNotificationTypeOneCloud,
  118. Factory: newOneCloudNotifier,
  119. ValidateCreateData: func(cred mcclient.IIdentityProvider, input monitor.NotificationCreateInput) (monitor.NotificationCreateInput, error) {
  120. settings := new(monitor.NotificationSettingOneCloud)
  121. if err := input.Settings.Unmarshal(settings); err != nil {
  122. return input, errors.Wrap(err, "unmarshal setting")
  123. }
  124. if settings.Channel == "" && len(settings.RobotIds) == 0 && len(settings.RoleIds) == 0 {
  125. return input, httperrors.NewInputParameterError("channel, robot_ids or role_ids is empty")
  126. }
  127. ids := make([]string, 0)
  128. for _, uid := range settings.UserIds {
  129. ctx := context.Background()
  130. ctx = context.WithValue(ctx, "alerting", uid)
  131. obj, err := db.UserCacheManager.FetchUserByIdOrName(ctx, uid)
  132. if err != nil {
  133. return input, errors.Wrapf(err, "fetch setting uid %s", uid)
  134. }
  135. ids = append(ids, obj.GetId())
  136. }
  137. settings.UserIds = ids
  138. input.Settings = jsonutils.Marshal(settings)
  139. return input, nil
  140. },
  141. })
  142. }
  143. // OneCloudNotifier is responsible for sending
  144. // alert notifications over onecloud notify service.
  145. type OneCloudNotifier struct {
  146. NotifierBase
  147. Setting *monitor.NotificationSettingOneCloud
  148. session *mcclient.ClientSession
  149. }
  150. func newOneCloudNotifier(config alerting.NotificationConfig) (alerting.Notifier, error) {
  151. setting := new(monitor.NotificationSettingOneCloud)
  152. if err := config.Settings.Unmarshal(setting); err != nil {
  153. return nil, errors.Wrapf(err, "unmarshal onecloud setting %s", config.Settings)
  154. }
  155. return &OneCloudNotifier{
  156. NotifierBase: NewNotifierBase(config),
  157. Setting: setting,
  158. session: getAdminSession(),
  159. }, nil
  160. }
  161. func getAdminSession() *mcclient.ClientSession {
  162. return auth.GetAdminSession(context.Background(), options.Options.Region)
  163. }
  164. func GetNotifyTemplateConfig(ctx *alerting.EvalContext, isRecoverd bool, matches []*monitor.EvalMatch) monitor.NotificationTemplateConfig {
  165. return getNotifyTemplateConfigOfLang(ctx, matches, isRecoverd, language.Chinese)
  166. }
  167. func getNotifyTemplateConfigOfLang(ctx *alerting.EvalContext,
  168. matches []*monitor.EvalMatch, isRecovered bool, lang language.Tag) monitor.NotificationTemplateConfig {
  169. priority := notify.NotifyPriorityNormal
  170. levelNormal := "普通"
  171. levelImportant := "重要"
  172. levelCritial := "致命"
  173. msgRecovered := "告警已恢复"
  174. msgNoData := "暂无数据"
  175. msgAlerting := "发生告警"
  176. transMap := map[string]string{
  177. levelNormal: "Normal",
  178. levelImportant: "Important",
  179. levelCritial: "Critical",
  180. msgRecovered: "Alarm recovered",
  181. msgNoData: "No data available",
  182. msgAlerting: "Alerting",
  183. }
  184. trans := func(input string) string {
  185. if lang == language.English {
  186. return transMap[input]
  187. }
  188. return input
  189. }
  190. level := levelNormal
  191. switch ctx.Rule.Level {
  192. case "", "normal":
  193. priority = notify.NotifyPriorityNormal
  194. case "important":
  195. priority = notify.NotifyPriorityImportant
  196. level = levelImportant
  197. case "fatal", "critical":
  198. priority = notify.NotifyPriorityCritical
  199. level = levelCritial
  200. }
  201. topic := fmt.Sprintf("[%s]", trans(level))
  202. isRecovery := false
  203. var hintMsg string
  204. if ctx.Rule.State == monitor.AlertStateOK || isRecovered {
  205. isRecovery = true
  206. hintMsg = msgRecovered
  207. } else if ctx.NoDataFound {
  208. hintMsg = msgNoData
  209. } else {
  210. hintMsg = msgAlerting
  211. }
  212. topic = fmt.Sprintf("%s [%s] %s", topic, trans(hintMsg), ctx.GetRuleTitle())
  213. config := ctx.GetNotificationTemplateConfig(matches)
  214. config.Title = topic
  215. config.Level = level
  216. config.Priority = string(priority)
  217. config.IsRecovery = isRecovery
  218. return config
  219. }
  220. // Notify sends the alert notification.
  221. func (oc *OneCloudNotifier) Notify(ctx *alerting.EvalContext, _ jsonutils.JSONObject) error {
  222. log.Infof("Sending alert notification %s to onecloud", ctx.GetRuleTitle())
  223. userIds := oc.Setting.UserIds
  224. if len(oc.Setting.RoleIds) != 0 {
  225. alert, err := models.CommonAlertManager.GetAlert(ctx.Rule.Id)
  226. if err != nil {
  227. return errors.Wrapf(err, "Get alert by %s", ctx.Rule.Id)
  228. }
  229. scope := alert.GetResourceScope()
  230. scopeId := ""
  231. switch scope {
  232. case rbacscope.ScopeDomain:
  233. scopeId = alert.GetDomainId()
  234. case rbacscope.ScopeProject:
  235. scopeId = alert.GetProjectId()
  236. }
  237. roleUserIds, err := getUsersByRoles(oc.Setting.RoleIds, string(scope), scopeId)
  238. if err != nil {
  239. return errors.Wrapf(err, "getUsersByRoles with %v:%s:%s", oc.Setting.RoleIds, scope, scopeId)
  240. }
  241. userIds = append(userIds, roleUserIds...)
  242. userIds = sets.NewString(userIds...).List()
  243. }
  244. langNotifyGroup, _ := errgroup.WithContext(ctx.Ctx)
  245. if err := oc.notifyByUserIds(ctx, userIds, langNotifyGroup); err != nil {
  246. return errors.Wrapf(err, "notifyByUserIds with %v", userIds)
  247. }
  248. if len(oc.Setting.RobotIds) != 0 {
  249. withLangTag := appctx.WithLangTag(ctx.Ctx, language.English)
  250. langNotifyGroup.Go(func() error {
  251. return oc.notifyByContextLang(withLangTag, ctx, []string{})
  252. })
  253. }
  254. return langNotifyGroup.Wait()
  255. }
  256. func (oc *OneCloudNotifier) notifyByUserIds(ctx *alerting.EvalContext, userIds []string, errGrp *errgroup.Group) error {
  257. langIdsMap, err := GetUserLangIdsMap(userIds)
  258. if err != nil {
  259. return errors.Wrapf(err, "GetUserLangIdsMap: %v", userIds)
  260. }
  261. for lang, _ := range langIdsMap {
  262. ids := langIdsMap[lang]
  263. langTag, _ := language.Parse(lang)
  264. langStr := i18nTable.LookupByLang(langTag, SUFFIX)
  265. langContext := appctx.WithLangTag(ctx.Ctx, getLangBystr(langStr))
  266. errGrp.Go(func() error {
  267. return oc.notifyByContextLang(langContext, ctx, ids)
  268. })
  269. }
  270. return nil
  271. }
  272. func getUsersByRoles(roleIds []string, roleScope string, scopeId string) ([]string, error) {
  273. s := getAdminSession()
  274. return modules.RoleAssignments.GetUserIdsByRolesInScope(s, roleIds, rbacscope.String2Scope(roleScope), scopeId)
  275. }
  276. func getLangBystr(str string) language.Tag {
  277. for lang, val := range i18nEnTry {
  278. if val == str {
  279. return lang
  280. }
  281. }
  282. return language.English
  283. }
  284. func (oc *OneCloudNotifier) notifyByContextLang(ctx context.Context, evalCtx *alerting.EvalContext, uids []string) error {
  285. errs := []error{}
  286. if evalCtx.Rule.State == monitor.AlertStatePending {
  287. log.Warningf("skip notify rule because state is pending: %s", jsonutils.Marshal(evalCtx.Rule))
  288. return nil
  289. }
  290. if len(evalCtx.GetEvalMatches()) > 0 {
  291. if err := oc.notifyMatchesByContextLang(ctx, evalCtx, evalCtx.GetEvalMatches(), uids, false); err != nil {
  292. errs = append(errs, errors.Wrapf(err, "notify alerting matches"))
  293. }
  294. }
  295. if evalCtx.HasRecoveredMatches() && !evalCtx.Rule.DisableNotifyRecovery {
  296. if err := oc.notifyMatchesByContextLang(ctx, evalCtx, evalCtx.GetRecoveredMatches(), uids, true); err != nil {
  297. errs = append(errs, errors.Wrapf(err, "notify recovered matches"))
  298. }
  299. }
  300. return errors.NewAggregate(errs)
  301. }
  302. func (oc *OneCloudNotifier) notifyMatchesByContextLang(
  303. ctx context.Context,
  304. evalCtx *alerting.EvalContext,
  305. matches []*monitor.EvalMatch,
  306. uids []string,
  307. isRecoverd bool) error {
  308. lang := appctx.Lang(ctx)
  309. config := getNotifyTemplateConfigOfLang(evalCtx, matches, isRecoverd, lang)
  310. oc.filterMatchTagsForConfig(&config, ctx)
  311. templateFuncs := getMonitorTemplateFuncs()
  312. // 对于 Mobile 渠道,需要构建 content,因为 sendMobileImpl 会直接使用 msg.Msg
  313. // 对于其他渠道,content 会通过 DEFAULT 模板文件根据语言环境构建,这里不需要构建
  314. var content string
  315. if oc.Setting.Channel == string(notify.NotifyByMobile) {
  316. content = oc.newRemoteMobileContent(&config, evalCtx, lang)
  317. }
  318. msg := notify.SNotifyMessage{
  319. Uid: uids,
  320. Robots: oc.Setting.RobotIds,
  321. ContactType: notify.TNotifyChannel(oc.Setting.Channel),
  322. Topic: config.Title,
  323. Priority: notify.TNotifyPriority(config.Priority),
  324. Msg: content,
  325. }
  326. factory := new(sendBodyFactory)
  327. sendImp := factory.newSendnotify(evalCtx, oc, msg, config, templateFuncs)
  328. return sendImp.send()
  329. }
  330. func (oc *OneCloudNotifier) newRemoteMobileContent(config *monitor.NotificationTemplateConfig,
  331. evalCtx *alerting.EvalContext, lang language.Tag) string {
  332. db := monitor.METRIC_DATABASE_TELE
  333. if len(evalCtx.Rule.RuleDescription) != 0 {
  334. db = evalCtx.Rule.RuleDescription[0].Database
  335. }
  336. switch db {
  337. case monitor.METRIC_DATABASE_METER:
  338. return oc.newMeterRemoteMobileContent(config, evalCtx, lang)
  339. default:
  340. return oc.newDefaultRemoteMobileContent(config, evalCtx, lang)
  341. }
  342. }
  343. func mobileContent(alertName string, typeStr string) string {
  344. content := make([][]string, 2)
  345. content[0] = []string{"alert_name", alertName}
  346. content[1] = []string{"type", typeStr}
  347. return jsonutils.Marshal(content).String()
  348. }
  349. func (oc *OneCloudNotifier) newDefaultRemoteMobileContent(config *monitor.NotificationTemplateConfig,
  350. evalCtx *alerting.EvalContext, lang language.Tag) string {
  351. typ := ""
  352. switch lang {
  353. case language.English:
  354. typ = "policy"
  355. config.Title = MOBILE_DEFAULT_TOPIC_EN
  356. default:
  357. typ = "告警策略"
  358. config.Title = MOBILE_DEFAULT_TOPIC_CN
  359. }
  360. return mobileContent(evalCtx.Rule.Name, typ)
  361. }
  362. func (oc *OneCloudNotifier) newMeterRemoteMobileContent(config *monitor.NotificationTemplateConfig,
  363. evalCtx *alerting.EvalContext, lang language.Tag) string {
  364. typ := ""
  365. switch lang {
  366. case language.English:
  367. config.Title = MOBILE_DEFAULT_TOPIC_EN
  368. typ = "budget"
  369. default:
  370. typ = "预算"
  371. config.Title = MOBILE_DEFAULT_TOPIC_CN
  372. }
  373. var name string
  374. if evalCtx.Rule.CustomizeConfig != nil {
  375. customizeConfig := new(monitor.MeterCustomizeConfig)
  376. if err := evalCtx.Rule.CustomizeConfig.Unmarshal(customizeConfig); err == nil {
  377. name = customizeConfig.Name
  378. }
  379. }
  380. // 兼容旧数据:如果 CustomizeConfig 为 nil 或解析失败,使用 Rule.Name 作为后备值
  381. if name == "" {
  382. name = evalCtx.Rule.Name
  383. }
  384. return mobileContent(name, typ)
  385. }
  386. func GetUserLangIdsMap(ids []string) (map[string][]string, error) {
  387. if len(ids) == 0 {
  388. return map[string][]string{}, nil
  389. }
  390. session := getAdminSession()
  391. langIdsMap := make(map[string][]string)
  392. params := jsonutils.NewDict()
  393. params.Set("filter", jsonutils.NewString(fmt.Sprintf("id.in(%s)", strings.Join(ids, ","))))
  394. params.Set("details", jsonutils.JSONFalse)
  395. params.Set("scope", jsonutils.NewString("system"))
  396. params.Set("system", jsonutils.JSONTrue)
  397. ret, err := modules.UsersV3.List(session, params)
  398. if err != nil {
  399. return nil, err
  400. }
  401. for i := range ret.Data {
  402. id, _ := ret.Data[i].GetString("id")
  403. langStr, _ := ret.Data[i].GetString("lang")
  404. if _, ok := langIdsMap[langStr]; ok {
  405. langIdsMap[langStr] = append(langIdsMap[langStr], id)
  406. continue
  407. }
  408. langIdsMap[langStr] = []string{id}
  409. }
  410. return langIdsMap, nil
  411. }
  412. var (
  413. companyInfo models.SCompanyInfo
  414. )
  415. func (oc *OneCloudNotifier) filterMatchTagsForConfig(config *monitor.NotificationTemplateConfig, ctx context.Context) {
  416. sCompanyInfo, err := models.GetCompanyInfo(ctx)
  417. if err != nil {
  418. log.Errorf("GetCompanyInfo error:%#v", err)
  419. return
  420. }
  421. for i, _ := range config.Matches {
  422. if val, ok := config.Matches[i].Tags[hostconsts.TELEGRAF_TAG_KEY_BRAND]; ok {
  423. if val == hostconsts.TELEGRAF_TAG_ONECLOUD_BRAND {
  424. config.Matches[i].Tags[hostconsts.TELEGRAF_TAG_KEY_BRAND] = sCompanyInfo.Name
  425. }
  426. }
  427. }
  428. }
  429. func (oc *OneCloudNotifier) buildContent(config monitor.NotificationTemplateConfig) *templates.TemplateConfig {
  430. return templates.NewTemplateConfig(config)
  431. }
  432. type sendBodyFactory struct {
  433. }
  434. func (f *sendBodyFactory) newSendnotify(evalCtx *alerting.EvalContext, notifier *OneCloudNotifier,
  435. message notify.SNotifyMessage,
  436. config monitor.NotificationTemplateConfig, templateFuncs template.FuncMap) iSendnotify {
  437. def := new(sendnotifyBase)
  438. def.OneCloudNotifier = notifier
  439. def.evalCtx = *evalCtx
  440. def.msg = message
  441. def.config = config
  442. def.templateFuncs = templateFuncs
  443. // 系统内置报警处理
  444. if len(notifier.Setting.UserIds) == 0 && len(notifier.Setting.RobotIds) == 0 {
  445. sys := new(sendSysImpl)
  446. sys.sendnotifyBase = def
  447. return sys
  448. }
  449. switch notifier.Setting.Channel {
  450. case monitor.DEFAULT_SEND_NOTIFY_CHANNEL:
  451. user := new(sendUserImpl)
  452. user.sendnotifyBase = def
  453. return user
  454. case string(notify.NotifyByMobile):
  455. mobile := new(sendMobileImpl)
  456. mobile.sendnotifyBase = def
  457. return mobile
  458. case string(notify.NotifyByRobot):
  459. robot := new(sendRobotImpl)
  460. robot.sendnotifyBase = def
  461. return robot
  462. default:
  463. return def
  464. }
  465. }
  466. type iSendnotify interface {
  467. send() error
  468. execNotifyFunc() error
  469. }
  470. type sendnotifyBase struct {
  471. *OneCloudNotifier
  472. evalCtx alerting.EvalContext
  473. msg notify.SNotifyMessage
  474. config monitor.NotificationTemplateConfig
  475. templateFuncs template.FuncMap
  476. }
  477. func (s *sendnotifyBase) send() error {
  478. return SendNotifyInfo(s, s)
  479. //return notify.Notifications.Send(s.session, s.msg)
  480. }
  481. func (s *sendnotifyBase) execNotifyFunc() error {
  482. notifyclient.RawNotifyWithCtxAndTemplateFuncs(s.Ctx, s.msg.Uid, false, notify.TNotifyChannel(s.Setting.Channel),
  483. notify.TNotifyPriority(s.msg.Priority),
  484. "DEFAULT",
  485. jsonutils.Marshal(&s.config), s.templateFuncs)
  486. return nil
  487. }
  488. type sendUserImpl struct {
  489. *sendnotifyBase
  490. }
  491. func (s *sendUserImpl) send() error {
  492. return SendNotifyInfo(s.sendnotifyBase, s)
  493. }
  494. func (s *sendUserImpl) execNotifyFunc() error {
  495. return notifyclient.NotifyAllWithoutRobotWithCtxAndTemplateFuncs(
  496. s.Ctx, s.msg.Uid, false, s.msg.Priority,
  497. "DEFAULT", jsonutils.Marshal(&s.config), s.templateFuncs)
  498. }
  499. type sendSysImpl struct {
  500. *sendnotifyBase
  501. }
  502. func (s *sendSysImpl) send() error {
  503. return SendNotifyInfo(s.sendnotifyBase, s)
  504. }
  505. func (s *sendSysImpl) execNotifyFunc() error {
  506. notifyclient.SystemNotifyWithCtxAndTemplateFuncs(s.Ctx, s.msg.Priority, "DEFAULT",
  507. jsonutils.Marshal(&s.config), s.templateFuncs)
  508. return nil
  509. }
  510. type sendMobileImpl struct {
  511. *sendnotifyBase
  512. }
  513. func (s *sendMobileImpl) send() error {
  514. msgObj, err := jsonutils.ParseString(s.msg.Msg)
  515. if err != nil {
  516. return err
  517. }
  518. notifyclient.RawNotifyWithCtxAndTemplateFuncs(s.Ctx, s.msg.Uid, false, notify.TNotifyChannel(s.Setting.Channel),
  519. s.msg.Priority,
  520. s.msg.Topic,
  521. msgObj,
  522. s.templateFuncs)
  523. return nil
  524. }
  525. type sendRobotImpl struct {
  526. *sendnotifyBase
  527. }
  528. func (s *sendRobotImpl) send() error {
  529. return SendNotifyInfo(s.sendnotifyBase, s)
  530. }
  531. func (s *sendRobotImpl) execNotifyFunc() error {
  532. return notifyclient.NotifyRobotWithCtxAndTemplateFuncs(s.Ctx, s.msg.Robots, s.msg.Priority,
  533. "DEFAULT", jsonutils.Marshal(&s.config), s.templateFuncs)
  534. }
  535. func SendNotifyInfo(base *sendnotifyBase, imp iSendnotify) error {
  536. /*tmpMatches := base.config.Matches
  537. batch := 100
  538. for i := 0; i < len(tmpMatches); i += batch {
  539. split := i + batch
  540. if split > len(tmpMatches) {
  541. split = len(tmpMatches)
  542. }
  543. base.config.Matches = tmpMatches[i:split]
  544. base.config.ResourceName = base.evalCtx.GetResourceNameOfMatches(base.config.Matches)
  545. err := imp.execNotifyFunc()
  546. if err != nil {
  547. return err
  548. }
  549. }
  550. return nil*/
  551. base.config.ResourceName = base.evalCtx.GetResourceNameOfMatches(base.config.Matches)
  552. return imp.execNotifyFunc()
  553. }