notify_new_incident.go 3.9 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143
  1. package cluster
  2. import (
  3. "errors"
  4. "fmt"
  5. "net/http"
  6. "strings"
  7. "github.com/porter-dev/porter/api/server/authz"
  8. "github.com/porter-dev/porter/api/server/handlers"
  9. "github.com/porter-dev/porter/api/server/shared"
  10. "github.com/porter-dev/porter/api/server/shared/apierrors"
  11. "github.com/porter-dev/porter/api/server/shared/config"
  12. "github.com/porter-dev/porter/api/types"
  13. "github.com/porter-dev/porter/internal/models"
  14. "github.com/porter-dev/porter/internal/notifier"
  15. "github.com/porter-dev/porter/internal/notifier/sendgrid"
  16. "github.com/porter-dev/porter/internal/notifier/slack"
  17. "github.com/porter-dev/porter/internal/repository"
  18. "gorm.io/gorm"
  19. )
  20. type NotifyNewIncidentHandler struct {
  21. handlers.PorterHandlerReadWriter
  22. authz.KubernetesAgentGetter
  23. }
  24. func NewNotifyNewIncidentHandler(
  25. config *config.Config,
  26. decoderValidator shared.RequestDecoderValidator,
  27. writer shared.ResultWriter,
  28. ) *NotifyNewIncidentHandler {
  29. return &NotifyNewIncidentHandler{
  30. PorterHandlerReadWriter: handlers.NewDefaultPorterHandler(config, decoderValidator, writer),
  31. KubernetesAgentGetter: authz.NewOutOfClusterAgentGetter(config),
  32. }
  33. }
  34. func (c *NotifyNewIncidentHandler) ServeHTTP(w http.ResponseWriter, r *http.Request) {
  35. cluster, _ := r.Context().Value(types.ClusterScope).(*models.Cluster)
  36. request := &types.Incident{}
  37. if ok := c.DecodeAndValidate(w, r, request); !ok {
  38. return
  39. }
  40. slackInts, _ := c.Repo().SlackIntegration().ListSlackIntegrationsByProjectID(cluster.ProjectID)
  41. rel, err := c.Repo().Release().ReadRelease(cluster.ID, request.ReleaseName, request.ReleaseNamespace)
  42. if err != nil && !errors.Is(err, gorm.ErrRecordNotFound) {
  43. c.HandleAPIError(w, r, apierrors.NewErrInternal(err))
  44. return
  45. }
  46. var notifConf *types.NotificationConfig
  47. if rel != nil && rel.NotificationConfig != 0 {
  48. conf, err := c.Repo().NotificationConfig().ReadNotificationConfig(rel.NotificationConfig)
  49. if err != nil {
  50. c.HandleAPIError(w, r, apierrors.NewErrInternal(err))
  51. return
  52. }
  53. notifConf = conf.ToNotificationConfigType()
  54. }
  55. users, err := getUsersByProjectID(c.Repo(), cluster.ProjectID)
  56. if err != nil {
  57. c.HandleAPIError(w, r, apierrors.NewErrInternal(err))
  58. return
  59. }
  60. notifiers := make([]notifier.IncidentNotifier, 0)
  61. if c.Config().SlackConf != nil {
  62. notifiers = append(notifiers, slack.NewIncidentNotifier(slackInts...))
  63. }
  64. if sc := c.Config().ServerConf; sc.SendgridAPIKey != "" && sc.SendgridSenderEmail != "" && sc.SendgridIncidentAlertTemplateID != "" {
  65. notifiers = append(notifiers, sendgrid.NewIncidentNotifier(&sendgrid.IncidentNotifierOpts{
  66. SharedOpts: &sendgrid.SharedOpts{
  67. APIKey: c.Config().ServerConf.SendgridAPIKey,
  68. SenderEmail: c.Config().ServerConf.SendgridSenderEmail,
  69. },
  70. IncidentAlertTemplateID: sc.SendgridIncidentAlertTemplateID,
  71. Users: users,
  72. }))
  73. }
  74. multi := notifier.NewMultiIncidentNotifier(
  75. notifConf,
  76. notifiers...,
  77. )
  78. if !cluster.NotificationsDisabled {
  79. url := fmt.Sprintf(
  80. "%s/applications/%s/%s/%s?project_id=%d",
  81. c.Config().ServerConf.ServerURL,
  82. cluster.Name,
  83. request.ReleaseNamespace,
  84. request.ReleaseName,
  85. cluster.ProjectID,
  86. )
  87. if strings.ToLower(string(request.InvolvedObjectKind)) == "job" {
  88. url = fmt.Sprintf(
  89. "%s/jobs/%s/%s/%s?project_id=%d&job=%s",
  90. c.Config().ServerConf.ServerURL,
  91. cluster.Name,
  92. request.ReleaseNamespace,
  93. request.ReleaseName,
  94. cluster.ProjectID,
  95. request.InvolvedObjectName,
  96. )
  97. }
  98. err := multi.NotifyNew(request, url)
  99. if err != nil {
  100. c.HandleAPIError(w, r, apierrors.NewErrInternal(err))
  101. return
  102. }
  103. }
  104. }
  105. func getUsersByProjectID(repo repository.Repository, projectID uint) ([]*models.User, error) {
  106. roles, err := repo.Project().ListProjectRoles(projectID)
  107. if err != nil {
  108. return nil, err
  109. }
  110. roleMap := make(map[uint]*models.Role)
  111. idArr := make([]uint, 0)
  112. for _, role := range roles {
  113. roleCp := role
  114. roleMap[role.UserID] = &roleCp
  115. idArr = append(idArr, role.UserID)
  116. }
  117. return repo.User().ListUsersByIDs(idArr)
  118. }