-
Notifications
You must be signed in to change notification settings - Fork 1
/
nsqadmin_actions.go
121 lines (110 loc) · 3.03 KB
/
nsqadmin_actions.go
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
package main
import (
"encoding/json"
"fmt"
"log"
"net/url"
"time"
"github.com/nsqio/nsqadmin_to_slack/internal/slack"
)
type AdminAction struct {
Action string `json:"action"`
Topic string `json:"topic"`
Channel string `json:"channel,omitempty"`
Node string `json:"node,omitempty"`
Timestamp int64 `json:"timestamp"`
User string `json:"user,omitempty"`
UserEmail string `json:"user_email,omitempty"` // from X-Forwarded-Email
RemoteIP string `json:"remote_ip"`
UserAgent string `json:"user_agent"`
URL string `json:"url"` // The URL of the HTTP request that triggered this action
Via string `json:"via"` // the Hostname of the nsqadmin performing this action
}
// SlackMsg formats an appropriate message for posting to Slack
func (msg AdminAction) SlackMsg() string {
var txt string
switch msg.Action {
case "create_topic":
txt = "Created Topic"
case "create_channel":
txt = "Created Channel"
case "delete_topic":
txt = "Deleted Topic"
case "delete_channel":
txt = "Deleted Channel"
case "empty_topic":
txt = "Emptied Topic"
case "empty_channel":
txt = "Emptied Channel"
case "pause_topic":
txt = "Paused Topic"
case "pause_channel":
txt = "Paused Channel"
case "unpause_topic":
txt = "Unpaused Topic"
case "unpause_channel":
txt = "Unpaused Channel"
case "tombstone_topic_producer":
txt = "Tombstoned Topic"
default:
txt = msg.Action
}
name := msg.Topic
if msg.Channel != "" {
name = fmt.Sprintf("%s/%s", name, msg.Channel)
}
u, err := url.Parse(msg.URL)
if err != nil {
log.Printf("failed parsing %q %s. using %s instead", msg.URL, err, msg.Via)
u = &url.URL{
Scheme: "http",
Host: msg.Via,
}
}
u.Path = ""
u.RawQuery = ""
switch msg.Action {
case "tombstone_topic_producer":
txt += fmt.Sprintf(" `%s` on %s", name, msg.Node)
case "delete_topic", "delete_channel":
txt += fmt.Sprintf(" `%s`", name)
default:
u.Path = fmt.Sprintf("/topics/%s", name)
txt += fmt.Sprintf(" <%s|%s>", u, name)
}
u.Path = ""
txt += fmt.Sprintf(" from <%s|%s>", u, u.Host)
// warn if we are retrying this message after a long period of time
if msg.Timestamp > 0 {
t := time.Unix(msg.Timestamp, 0)
duration := time.Since(t)
if duration > time.Minute*2 {
txt += fmt.Sprintf("\n\nWARNING: outdated notification from %s ago %s", duration, t.Format(time.RFC3339))
}
}
return txt
}
// nsqadmin sends notifications for nsqadmin actions to #ops
func (h *Handler) nsqadmin(b []byte) error {
var msg AdminAction
err := json.Unmarshal(b, &msg)
if err != nil {
return err
}
username := msg.User
// prefer an exact slack username match via email
if msg.UserEmail != "" {
if user, _ := h.Slack.UserByEmail(msg.UserEmail); user != nil {
username = user.Name
}
}
txt := msg.SlackMsg()
log.Printf("sending %s %s %q", username, h.SlackChannel, txt)
err = h.Slack.ChatPostMessage(&slack.Message{
Channel: h.SlackChannel,
Text: txt,
Username: username,
IconURL: "https://s3.amazonaws.com/static.bitly.com/graphics/eng/nsq_logo_small.png",
})
return err
}