Christopher Ramey
3 years ago
5 changed files with 254 additions and 242 deletions
-
3alarm/alarm.go
-
241alarm/alarm_email.go
-
72alarm/email/alarm.go
-
82alarm/email/email.go
-
98alarm/email/parse.go
@ -1,241 +0,0 @@ |
|||||
package alarm |
|
||||
|
|
||||
import ( |
|
||||
"fmt" |
|
||||
"net/smtp" |
|
||||
"os" |
|
||||
"strings" |
|
||||
"text/template" |
|
||||
"time" |
|
||||
) |
|
||||
|
|
||||
const ( |
|
||||
TK_NONE = iota |
|
||||
TK_TO |
|
||||
TK_SMTP |
|
||||
TK_FROM |
|
||||
TK_USER |
|
||||
TK_PASS |
|
||||
TK_SUBJECT |
|
||||
TK_MESSAGE |
|
||||
) |
|
||||
|
|
||||
type AlarmEmail struct { |
|
||||
Type string |
|
||||
Name string |
|
||||
To []string |
|
||||
From string |
|
||||
SMTP string |
|
||||
User string |
|
||||
Pass string |
|
||||
Subject string |
|
||||
subTemplate *template.Template |
|
||||
Message string |
|
||||
msgTemplate *template.Template |
|
||||
state int |
|
||||
} |
|
||||
|
|
||||
type EmailDetail struct { |
|
||||
Timestamp string |
|
||||
Group string |
|
||||
Host string |
|
||||
Check string |
|
||||
Error error |
|
||||
} |
|
||||
|
|
||||
func NewAlarmEmail(name string) *AlarmEmail { |
|
||||
host, _ := os.Hostname() |
|
||||
if host == "" { |
|
||||
host = "localhost" |
|
||||
} |
|
||||
|
|
||||
al := &AlarmEmail{ |
|
||||
Type: "email", |
|
||||
Name: name, |
|
||||
From: "alrm@" + host, |
|
||||
SMTP: "localhost:25", |
|
||||
Subject: "{{.Host}} failure", |
|
||||
Message: "Check {{.Check}} failed at {{.Timestamp}}: {{.Error}}", |
|
||||
} |
|
||||
al.updateSubject() |
|
||||
al.updateMessage() |
|
||||
return al |
|
||||
} |
|
||||
|
|
||||
func (a *AlarmEmail) updateSubject() error { |
|
||||
t := template.New("email subject") |
|
||||
_, err := t.Parse(a.Subject) |
|
||||
if err != nil { |
|
||||
fmt.Print(err) |
|
||||
return err |
|
||||
} |
|
||||
a.subTemplate = t |
|
||||
return nil |
|
||||
} |
|
||||
|
|
||||
func (a *AlarmEmail) updateMessage() error { |
|
||||
t := template.New("email message") |
|
||||
_, err := t.Parse(a.Message) |
|
||||
if err != nil { |
|
||||
fmt.Print(err) |
|
||||
return err |
|
||||
} |
|
||||
a.msgTemplate = t |
|
||||
return nil |
|
||||
} |
|
||||
|
|
||||
func (a *AlarmEmail) Parse(tk string) (bool, error) { |
|
||||
switch a.state { |
|
||||
case TK_NONE: |
|
||||
switch strings.ToLower(tk) { |
|
||||
case "to": |
|
||||
a.state = TK_TO |
|
||||
case "from": |
|
||||
a.state = TK_FROM |
|
||||
case "smtp": |
|
||||
a.state = TK_SMTP |
|
||||
case "user": |
|
||||
a.state = TK_USER |
|
||||
case "pass": |
|
||||
a.state = TK_PASS |
|
||||
case "subject": |
|
||||
a.state = TK_SUBJECT |
|
||||
case "message": |
|
||||
a.state = TK_MESSAGE |
|
||||
default: |
|
||||
if len(a.To) < 1 { |
|
||||
return false, fmt.Errorf("email alarm requires to address") |
|
||||
} |
|
||||
return false, nil |
|
||||
} |
|
||||
|
|
||||
case TK_FROM: |
|
||||
if strings.TrimSpace(tk) == "" { |
|
||||
return false, fmt.Errorf("from address cannot be empty") |
|
||||
} |
|
||||
a.From = tk |
|
||||
a.state = TK_NONE |
|
||||
|
|
||||
case TK_SMTP: |
|
||||
if strings.TrimSpace(tk) == "" { |
|
||||
return false, fmt.Errorf("smtp server cannot be empty") |
|
||||
} |
|
||||
// If the smtp host doesn't contain a port, add the default
|
|
||||
if !strings.Contains(tk, ":") { |
|
||||
tk += ":25" |
|
||||
} |
|
||||
a.SMTP = tk |
|
||||
a.state = TK_NONE |
|
||||
|
|
||||
case TK_TO: |
|
||||
if strings.TrimSpace(tk) == "" { |
|
||||
return false, fmt.Errorf("to address cannot be empty") |
|
||||
} |
|
||||
a.To = append(a.To, tk) |
|
||||
a.state = TK_NONE |
|
||||
|
|
||||
case TK_USER: |
|
||||
if strings.TrimSpace(tk) == "" { |
|
||||
return false, fmt.Errorf("user cannot be empty") |
|
||||
} |
|
||||
a.User = tk |
|
||||
a.state = TK_NONE |
|
||||
|
|
||||
case TK_PASS: |
|
||||
if strings.TrimSpace(tk) == "" { |
|
||||
return false, fmt.Errorf("pass cannot be empty") |
|
||||
} |
|
||||
a.Pass = tk |
|
||||
a.state = TK_NONE |
|
||||
|
|
||||
case TK_SUBJECT: |
|
||||
if strings.TrimSpace(tk) == "" { |
|
||||
return false, fmt.Errorf("subject cannot be empty") |
|
||||
} |
|
||||
a.Subject = tk |
|
||||
err := a.updateSubject() |
|
||||
if err != nil { |
|
||||
return false, err |
|
||||
} |
|
||||
a.state = TK_NONE |
|
||||
|
|
||||
case TK_MESSAGE: |
|
||||
if strings.TrimSpace(tk) == "" { |
|
||||
return false, fmt.Errorf("message cannot be empty") |
|
||||
} |
|
||||
a.Message = tk |
|
||||
err := a.updateMessage() |
|
||||
if err != nil { |
|
||||
return false, err |
|
||||
} |
|
||||
a.state = TK_NONE |
|
||||
|
|
||||
default: |
|
||||
return false, fmt.Errorf("invalid state in alarm_email") |
|
||||
} |
|
||||
return true, nil |
|
||||
} |
|
||||
|
|
||||
func (a *AlarmEmail) Alarm(grp string, hst string, chk string, alerr error) error { |
|
||||
dt := EmailDetail{ |
|
||||
Timestamp: time.Now().Format(time.RFC1123), |
|
||||
Group: grp, |
|
||||
Host: hst, |
|
||||
Check: chk, |
|
||||
Error: alerr, |
|
||||
} |
|
||||
|
|
||||
c, err := smtp.Dial(a.SMTP) |
|
||||
if err != nil { |
|
||||
return err |
|
||||
} |
|
||||
|
|
||||
helo := "localhost" |
|
||||
tspl := strings.Split(a.From, "@") |
|
||||
if len(tspl) > 1 { |
|
||||
helo = tspl[1] |
|
||||
} |
|
||||
|
|
||||
err = c.Hello(helo) |
|
||||
if err != nil { |
|
||||
return err |
|
||||
} |
|
||||
err = c.Mail(a.From) |
|
||||
if err != nil { |
|
||||
return err |
|
||||
} |
|
||||
for _, to := range a.To { |
|
||||
err = c.Rcpt(to) |
|
||||
if err != nil { |
|
||||
return err |
|
||||
} |
|
||||
} |
|
||||
m, err := c.Data() |
|
||||
if err != nil { |
|
||||
return err |
|
||||
} |
|
||||
|
|
||||
fmt.Fprintf(m, "From: %s\r\n", a.From) |
|
||||
fmt.Fprintf(m, "To: %s\r\n", strings.Join(a.To, ";")) |
|
||||
|
|
||||
fmt.Fprintf(m, "Subject: ") |
|
||||
err = a.subTemplate.Execute(m, dt) |
|
||||
if err != nil { |
|
||||
return err |
|
||||
} |
|
||||
fmt.Fprintf(m, "\r\n\r\n") |
|
||||
|
|
||||
err = a.msgTemplate.Execute(m, dt) |
|
||||
if err != nil { |
|
||||
return err |
|
||||
} |
|
||||
err = m.Close() |
|
||||
if err != nil { |
|
||||
return err |
|
||||
} |
|
||||
err = c.Quit() |
|
||||
if err != nil { |
|
||||
return err |
|
||||
} |
|
||||
return nil |
|
||||
} |
|
@ -0,0 +1,72 @@ |
|||||
|
package email |
||||
|
|
||||
|
import ( |
||||
|
"fmt" |
||||
|
"net/smtp" |
||||
|
"strings" |
||||
|
"time" |
||||
|
) |
||||
|
|
||||
|
func (a *AlarmEmail) Alarm(grp string, hst string, chk string, alerr error) error { |
||||
|
dt := EmailDetail{ |
||||
|
Timestamp: time.Now().Format(time.RFC1123), |
||||
|
Group: grp, |
||||
|
Host: hst, |
||||
|
Check: chk, |
||||
|
Error: alerr, |
||||
|
} |
||||
|
|
||||
|
c, err := smtp.Dial(a.SMTP) |
||||
|
if err != nil { |
||||
|
return err |
||||
|
} |
||||
|
|
||||
|
helo := "localhost" |
||||
|
tspl := strings.Split(a.From, "@") |
||||
|
if len(tspl) > 1 { |
||||
|
helo = tspl[1] |
||||
|
} |
||||
|
|
||||
|
err = c.Hello(helo) |
||||
|
if err != nil { |
||||
|
return err |
||||
|
} |
||||
|
err = c.Mail(a.From) |
||||
|
if err != nil { |
||||
|
return err |
||||
|
} |
||||
|
for _, to := range a.To { |
||||
|
err = c.Rcpt(to) |
||||
|
if err != nil { |
||||
|
return err |
||||
|
} |
||||
|
} |
||||
|
m, err := c.Data() |
||||
|
if err != nil { |
||||
|
return err |
||||
|
} |
||||
|
|
||||
|
fmt.Fprintf(m, "From: %s\r\n", a.From) |
||||
|
fmt.Fprintf(m, "To: %s\r\n", strings.Join(a.To, ";")) |
||||
|
|
||||
|
fmt.Fprintf(m, "Subject: ") |
||||
|
err = a.subTemplate.Execute(m, dt) |
||||
|
if err != nil { |
||||
|
return err |
||||
|
} |
||||
|
fmt.Fprintf(m, "\r\n\r\n") |
||||
|
|
||||
|
err = a.msgTemplate.Execute(m, dt) |
||||
|
if err != nil { |
||||
|
return err |
||||
|
} |
||||
|
err = m.Close() |
||||
|
if err != nil { |
||||
|
return err |
||||
|
} |
||||
|
err = c.Quit() |
||||
|
if err != nil { |
||||
|
return err |
||||
|
} |
||||
|
return nil |
||||
|
} |
@ -0,0 +1,82 @@ |
|||||
|
package email |
||||
|
|
||||
|
import ( |
||||
|
"fmt" |
||||
|
"os" |
||||
|
"text/template" |
||||
|
) |
||||
|
|
||||
|
const ( |
||||
|
TK_NONE = iota |
||||
|
TK_TO |
||||
|
TK_SMTP |
||||
|
TK_FROM |
||||
|
TK_USER |
||||
|
TK_PASS |
||||
|
TK_SUBJECT |
||||
|
TK_MESSAGE |
||||
|
) |
||||
|
|
||||
|
type AlarmEmail struct { |
||||
|
Type string |
||||
|
Name string |
||||
|
To []string |
||||
|
From string |
||||
|
SMTP string |
||||
|
User string |
||||
|
Pass string |
||||
|
Subject string |
||||
|
subTemplate *template.Template |
||||
|
Message string |
||||
|
msgTemplate *template.Template |
||||
|
state int |
||||
|
} |
||||
|
|
||||
|
type EmailDetail struct { |
||||
|
Timestamp string |
||||
|
Group string |
||||
|
Host string |
||||
|
Check string |
||||
|
Error error |
||||
|
} |
||||
|
|
||||
|
func NewAlarmEmail(name string) *AlarmEmail { |
||||
|
host, _ := os.Hostname() |
||||
|
if host == "" { |
||||
|
host = "localhost" |
||||
|
} |
||||
|
|
||||
|
al := &AlarmEmail{ |
||||
|
Type: "email", |
||||
|
Name: name, |
||||
|
From: "alrm@" + host, |
||||
|
SMTP: "localhost:25", |
||||
|
Subject: "{{.Host}} failure", |
||||
|
Message: "Check {{.Check}} failed at {{.Timestamp}}: {{.Error}}", |
||||
|
} |
||||
|
al.updateSubject() |
||||
|
al.updateMessage() |
||||
|
return al |
||||
|
} |
||||
|
|
||||
|
func (a *AlarmEmail) updateSubject() error { |
||||
|
t := template.New("email subject") |
||||
|
_, err := t.Parse(a.Subject) |
||||
|
if err != nil { |
||||
|
fmt.Print(err) |
||||
|
return err |
||||
|
} |
||||
|
a.subTemplate = t |
||||
|
return nil |
||||
|
} |
||||
|
|
||||
|
func (a *AlarmEmail) updateMessage() error { |
||||
|
t := template.New("email message") |
||||
|
_, err := t.Parse(a.Message) |
||||
|
if err != nil { |
||||
|
fmt.Print(err) |
||||
|
return err |
||||
|
} |
||||
|
a.msgTemplate = t |
||||
|
return nil |
||||
|
} |
@ -0,0 +1,98 @@ |
|||||
|
package email |
||||
|
|
||||
|
import ( |
||||
|
"fmt" |
||||
|
"strings" |
||||
|
) |
||||
|
|
||||
|
func (a *AlarmEmail) Parse(tk string) (bool, error) { |
||||
|
switch a.state { |
||||
|
case TK_NONE: |
||||
|
switch strings.ToLower(tk) { |
||||
|
case "to": |
||||
|
a.state = TK_TO |
||||
|
case "from": |
||||
|
a.state = TK_FROM |
||||
|
case "smtp": |
||||
|
a.state = TK_SMTP |
||||
|
case "user": |
||||
|
a.state = TK_USER |
||||
|
case "pass": |
||||
|
a.state = TK_PASS |
||||
|
case "subject": |
||||
|
a.state = TK_SUBJECT |
||||
|
case "message": |
||||
|
a.state = TK_MESSAGE |
||||
|
default: |
||||
|
if len(a.To) < 1 { |
||||
|
return false, fmt.Errorf("email alarm requires to address") |
||||
|
} |
||||
|
return false, nil |
||||
|
} |
||||
|
|
||||
|
case TK_FROM: |
||||
|
if strings.TrimSpace(tk) == "" { |
||||
|
return false, fmt.Errorf("from address cannot be empty") |
||||
|
} |
||||
|
a.From = tk |
||||
|
a.state = TK_NONE |
||||
|
|
||||
|
case TK_SMTP: |
||||
|
if strings.TrimSpace(tk) == "" { |
||||
|
return false, fmt.Errorf("smtp server cannot be empty") |
||||
|
} |
||||
|
// If the smtp host doesn't contain a port, add the default
|
||||
|
if !strings.Contains(tk, ":") { |
||||
|
tk += ":25" |
||||
|
} |
||||
|
a.SMTP = tk |
||||
|
a.state = TK_NONE |
||||
|
|
||||
|
case TK_TO: |
||||
|
if strings.TrimSpace(tk) == "" { |
||||
|
return false, fmt.Errorf("to address cannot be empty") |
||||
|
} |
||||
|
a.To = append(a.To, tk) |
||||
|
a.state = TK_NONE |
||||
|
|
||||
|
case TK_USER: |
||||
|
if strings.TrimSpace(tk) == "" { |
||||
|
return false, fmt.Errorf("user cannot be empty") |
||||
|
} |
||||
|
a.User = tk |
||||
|
a.state = TK_NONE |
||||
|
|
||||
|
case TK_PASS: |
||||
|
if strings.TrimSpace(tk) == "" { |
||||
|
return false, fmt.Errorf("pass cannot be empty") |
||||
|
} |
||||
|
a.Pass = tk |
||||
|
a.state = TK_NONE |
||||
|
|
||||
|
case TK_SUBJECT: |
||||
|
if strings.TrimSpace(tk) == "" { |
||||
|
return false, fmt.Errorf("subject cannot be empty") |
||||
|
} |
||||
|
a.Subject = tk |
||||
|
err := a.updateSubject() |
||||
|
if err != nil { |
||||
|
return false, err |
||||
|
} |
||||
|
a.state = TK_NONE |
||||
|
|
||||
|
case TK_MESSAGE: |
||||
|
if strings.TrimSpace(tk) == "" { |
||||
|
return false, fmt.Errorf("message cannot be empty") |
||||
|
} |
||||
|
a.Message = tk |
||||
|
err := a.updateMessage() |
||||
|
if err != nil { |
||||
|
return false, err |
||||
|
} |
||||
|
a.state = TK_NONE |
||||
|
|
||||
|
default: |
||||
|
return false, fmt.Errorf("invalid state in alarm_email") |
||||
|
} |
||||
|
return true, nil |
||||
|
} |
Write
Preview
Loading…
Cancel
Save
Reference in new issue