-
Notifications
You must be signed in to change notification settings - Fork 2
/
Copy pathalert.go
101 lines (88 loc) · 2.72 KB
/
alert.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
package main
import (
"fmt"
"os"
"os/exec"
"strings"
"time"
)
// HourRange hold a Start and an End in the form of int arrays ([0] = hours, [1] = minutes)
type HourRange struct {
Start [2]int
End [2]int
}
// Alert is the final form of alerts.d files
type Alert struct {
Name string
Disabled bool
Targets []string
Command string
Arguments []string
Hours []HourRange
Days []int
}
// Ring will send an AlertMessage using this Alert, executing the
// configured command
func (alert *Alert) Ring(msg *AlertMessage) {
Info.Println("ring: " + alert.Name + ", " + alert.Command /* + " " + strings.Join(alert.Arguments, " ") */)
varMap := make(map[string]interface{})
varMap["SUBJECT"] = msg.Subject
varMap["TYPE"] = msg.Type.String()
varMap["UNIQUEID"] = msg.UniqueID
varMap["HOST_NAME"] = msg.Hostname
varMap["CLASSES"] = strings.Join(msg.Classes, ",")
varMap["NOSEE_SRV"] = GlobalConfig.Name
varMap["DATETIME"] = msg.DateTime.Format(time.RFC3339)
// "Level" ? (Run, Task, Checks)
// Probe Name, Check Name, Alert Name ?
var args []string
for _, arg := range alert.Arguments {
expArg := StringExpandVariables(arg, varMap)
args = append(args, expArg)
}
go func() {
cmd := exec.Command(alert.Command, args...)
env := os.Environ()
for key, val := range varMap {
env = append(env, fmt.Sprintf("%s=%s", key, InterfaceValueToString(val)))
}
cmd.Env = env
// we also inject Details thru stdin:
cmd.Stdin = strings.NewReader(msg.Details)
if cmdOut, err := cmd.CombinedOutput(); err != nil {
if len(msg.Classes) == 1 && msg.Classes[0] == GeneralClass {
Error.Printf("unable to ring an alert to general class! error: %s (%s)\n", err, alert.Command)
return
}
Warning.Printf("error running alert '%s': %s", alert.Command, err)
msg.Subject = msg.Subject + " (Fwd)"
prepend := fmt.Sprintf("WARNING: This alert is re-routed to the 'general' class, because\noriginal alert failed with the following error: %s (%s)\nOutput: %s\n\n", err.Error(), alert.Command, string(cmdOut))
msg.Details = prepend + msg.Details
msg.Classes = []string{GeneralClass}
msg.RingAlerts()
}
}()
}
// Ringable will return true if this Alert is currently able to ring
// (no matching day or hour limit)
func (alert *Alert) Ringable() bool {
now := time.Now()
nowMins := now.Hour()*60 + now.Minute()
nowDay := int(now.Weekday())
hourOk := len(alert.Hours) == 0
for _, hourRange := range alert.Hours {
start := hourRange.Start[0]*60 + hourRange.Start[1]
end := hourRange.End[0]*60 + hourRange.End[1]
if nowMins >= start && nowMins <= end {
hourOk = true
break
}
}
dayOk := len(alert.Days) == 0
for _, day := range alert.Days {
if nowDay == day {
dayOk = true
}
}
return hourOk && dayOk
}