-
Notifications
You must be signed in to change notification settings - Fork 1
/
dashboard.go
144 lines (131 loc) · 3.44 KB
/
dashboard.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
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
// Package dashboard implements a web dashboard for monitoring.
package dashboard // import "hkjn.me/dashboard"
import (
"errors"
"io/ioutil"
"log"
"net/http"
"sync"
"github.com/gorilla/mux"
"hkjn.me/config"
"hkjn.me/prober"
"hkjn.me/probes"
"hkjn.me/dashboard/gen"
)
var (
emailTemplate = `{{define "email"}}
The probe <a href="http://j.mp/hkjndash#{{.Name}}">{{.Name}}</a> failed enough that this alert fired, as the arbitrary metric of 'badness' is {{.Badness}}, which we can all agree is a big number.<br/>
The description of the probe is: “{{.Desc}}”<br/>
Failure details follow:<br/>
{{range $r := .Records.RecentFailures}}
<h2>{{$r.Timestamp}} ({{$r.Ago}})</h2>
<p>{{$r.Result.Info}}</p>
{{end}}
{{end}}`
probecfg = struct {
WebProbes []struct {
Target, Want, Name string
WantStatus int
}
VarsProbes []struct {
Target, Name, Key, WantValue string
}
DnsProbes []struct {
Target string
Records struct {
Cname string
A []string
Mx []struct {
Host string
Pref uint16
}
Ns []string
Txt []string
}
}
}{}
loadConfigOnce = sync.Once{}
)
type Config struct {
Debug bool `default:"true"`
BindAddr string
AllowedGoogleIds []string
SendgridToken string
EmailSender string
EmailRecipient string
}
// setProbeCfg sets the config values.
func setProbesCfg(conf Config, emailTemplate string) error {
if conf.Debug {
log.Printf("Starting in debug mode..")
return nil
}
// TODO(hkjn): Unify probes.Config vs dashboard.Config.
probes.Config.SendgridToken = conf.SendgridToken
if conf.SendgridToken == "" {
return errors.New("no DASHBOARD_SENDGRIDTOKEN specified")
}
if conf.EmailSender == "" {
return errors.New("no DASHBOARD_EMAILSENDER specified")
}
if conf.Debug {
log.Printf(
"Sending any alert emails from %q to %q\n",
conf.EmailSender,
conf.EmailRecipient,
)
}
probes.Config.Alert.Sender = conf.EmailSender
if conf.EmailRecipient == "" {
return errors.New("no DASHBOARD_EMAILRECIPIENT specified")
}
probes.Config.Alert.Recipient = conf.EmailRecipient
if emailTemplate == "" {
return errors.New("no email template")
}
probes.Config.Template = emailTemplate
if conf.Debug {
log.Printf("These Google+ IDs are allowed access: %q\n", conf.AllowedGoogleIds)
}
return nil
}
// getIndexData returns the data for the index page.
//
// TODO: offer alternative auth other than defunct Google+ login
// TODO: improve style of web page, add details like DNS records probed
// when clicking probe heading
func getIndexData(w http.ResponseWriter, r *http.Request) (interface{}, error) {
data := struct {
Version string
Links []struct {
Name, URL string
}
Probes []*prober.Probe
ProberDisabled bool
}{}
data.Version = gen.Version
data.Probes = getProbes()
data.ProberDisabled = *proberDisabled
return data, nil
}
// Start returns the HTTP routes for the dashboard.
func Start(conf Config) *mux.Router {
r := func(filename string) ([]byte, error) {
return ioutil.ReadFile(filename)
}
if !conf.Debug {
r = func(filename string) ([]byte, error) {
return gen.Asset(filename)
}
}
config.MustLoadNameFrom("probes.yaml", &probecfg, r)
ps := getProbes()
log.Printf("Starting %d probes..\n", len(ps))
for _, p := range ps {
go p.Run()
}
if err := setProbesCfg(conf, emailTemplate); err != nil {
log.Fatalf("FATAL: Couldn't set probes config: %v\n", err)
}
return newRouter(conf.Debug)
}