incident_notifier.go 3.1 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135
  1. package slack
  2. import (
  3. "bytes"
  4. "encoding/json"
  5. "fmt"
  6. "net/http"
  7. "strings"
  8. "time"
  9. "github.com/porter-dev/porter/api/types"
  10. "github.com/porter-dev/porter/internal/models/integrations"
  11. )
  12. type IncidentNotifier struct {
  13. slackInts []*integrations.SlackIntegration
  14. }
  15. func NewIncidentNotifier(slackInts ...*integrations.SlackIntegration) *IncidentNotifier {
  16. return &IncidentNotifier{
  17. slackInts: slackInts,
  18. }
  19. }
  20. func (s *IncidentNotifier) NotifyNew(incident *types.Incident, url string) error {
  21. res := []*SlackBlock{}
  22. resourceKind := "application"
  23. if strings.ToLower(string(incident.InvolvedObjectKind)) == "job" {
  24. resourceKind = "job"
  25. }
  26. topSectionMarkdwn := fmt.Sprintf(
  27. ":warning: Your %s %s crashed on Porter. <%s|View the incident.>",
  28. resourceKind,
  29. "`"+incident.ReleaseName+"`",
  30. url,
  31. )
  32. createdAt := incident.CreatedAt
  33. res = append(
  34. res,
  35. getMarkdownBlock(topSectionMarkdwn),
  36. getDividerBlock(),
  37. getMarkdownBlock(fmt.Sprintf("*Namespace:* %s", "`"+incident.ReleaseNamespace+"`")),
  38. getMarkdownBlock(fmt.Sprintf("*Name:* %s", "`"+incident.ReleaseName+"`")),
  39. getMarkdownBlock(fmt.Sprintf(
  40. "*Created at:* <!date^%d^ {date_num} {time_secs}| %s>",
  41. createdAt.Unix(),
  42. createdAt.Format("2006-01-02 15:04:05 UTC"),
  43. )),
  44. getMarkdownBlock(fmt.Sprintf("```\n%s\n```", incident.Summary)),
  45. )
  46. slackPayload := &SlackPayload{
  47. Blocks: res,
  48. }
  49. payload, err := json.Marshal(slackPayload)
  50. if err != nil {
  51. return err
  52. }
  53. reqBody := bytes.NewReader(payload)
  54. client := &http.Client{
  55. Timeout: time.Second * 5,
  56. }
  57. for _, slackInt := range s.slackInts {
  58. _, err := client.Post(string(slackInt.Webhook), "application/json", reqBody)
  59. if err != nil {
  60. return err
  61. }
  62. }
  63. return nil
  64. }
  65. func (s *IncidentNotifier) NotifyResolved(incident *types.Incident, url string) error {
  66. res := []*SlackBlock{}
  67. createdAt := incident.CreatedAt
  68. resolvedAt := incident.UpdatedAt
  69. topSectionMarkdwn := fmt.Sprintf(
  70. ":white_check_mark: The incident for application %s has been resolved. <%s|View the incident.>",
  71. "`"+incident.ReleaseName+"`",
  72. url,
  73. )
  74. res = append(
  75. res,
  76. getMarkdownBlock(topSectionMarkdwn),
  77. getDividerBlock(),
  78. getMarkdownBlock(fmt.Sprintf("*Namespace:* %s", "`"+incident.ReleaseNamespace+"`")),
  79. getMarkdownBlock(fmt.Sprintf("*Name:* %s", "`"+incident.ReleaseName+"`")),
  80. getMarkdownBlock(fmt.Sprintf(
  81. "*Created at:* <!date^%d^ {date_num} {time_secs}| %s>",
  82. createdAt.Unix(),
  83. createdAt.Format("2006-01-02 15:04:05 UTC"),
  84. )),
  85. getMarkdownBlock(fmt.Sprintf(
  86. "*Resolved at:* <!date^%d^ {date_num} {time_secs}| %s>",
  87. resolvedAt.Unix(),
  88. resolvedAt.Format("2006-01-02 15:04:05 UTC"),
  89. )),
  90. getMarkdownBlock(fmt.Sprintf("*Incident Summary:*")),
  91. getMarkdownBlock(fmt.Sprintf("```\n%s\n```", incident.Summary)),
  92. )
  93. slackPayload := &SlackPayload{
  94. Blocks: res,
  95. }
  96. payload, err := json.Marshal(slackPayload)
  97. if err != nil {
  98. return err
  99. }
  100. reqBody := bytes.NewReader(payload)
  101. client := &http.Client{
  102. Timeout: time.Second * 5,
  103. }
  104. for _, slackInt := range s.slackInts {
  105. _, err := client.Post(string(slackInt.Webhook), "application/json", reqBody)
  106. if err != nil {
  107. return err
  108. }
  109. }
  110. return nil
  111. }