diff --git a/alarm/alarm.go b/alarm/alarm.go index 4f288f5..e82911d 100644 --- a/alarm/alarm.go +++ b/alarm/alarm.go @@ -6,7 +6,7 @@ import ( type Alarm interface { Parse(string) (bool, error) - Alarm(string,string,string,error) error + Alarm(string, string, string, error) error } func NewAlarm(name string, typename string) (Alarm, error) { diff --git a/alarm/alarm_email.go b/alarm/alarm_email.go index 80df089..fe02c34 100644 --- a/alarm/alarm_email.go +++ b/alarm/alarm_email.go @@ -5,6 +5,8 @@ import ( "net/smtp" "os" "strings" + "text/template" + "time" ) const ( @@ -12,15 +14,33 @@ const ( TK_TO TK_SMTP TK_FROM + TK_USER + TK_PASS + TK_SUBJECT + TK_MESSAGE ) type AlarmEmail struct { - Type string - Name string - From string - SMTP string - To []string - state int + 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 { @@ -29,60 +49,38 @@ func NewAlarmEmail(name string) *AlarmEmail { host = "localhost" } - return &AlarmEmail{ - Type: "email", Name: name, - From: "alrm@" + host, SMTP: "localhost:25", + 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) Alarm(grp string, host string, chk string, cerr error) error { - 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() +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 +} - msg := fmt.Sprintf("From: %s\r\n", a.From) - msg += fmt.Sprintf("To: %s\r\n", strings.Join(a.To, ";")) - msg += fmt.Sprintf("Subject: %s\r\n\r\n", "test subject") - msg += fmt.Sprintf("%s", cerr.Error()) - - _, err = fmt.Fprintf(m, "%s", msg) - if err != nil { - return err - } - err = m.Close() - if err != nil { - return err - } - err = c.Quit() +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 } @@ -96,6 +94,14 @@ func (a *AlarmEmail) Parse(tk string) (bool, error) { 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") @@ -128,8 +134,108 @@ func (a *AlarmEmail) Parse(tk string) (bool, error) { 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 +} diff --git a/main.go b/main.go index 7a83ff3..64ee4cc 100644 --- a/main.go +++ b/main.go @@ -16,7 +16,6 @@ func main() { flag.Usage = printUsage flag.Parse() - if *cfgPath == "" { searchpaths := []string{"/etc/alrmrc", "./alrmrc"} for _, sp := range searchpaths { @@ -44,7 +43,6 @@ func main() { os.Exit(1) } - if *debuglvl > 0 { o, err := json.MarshalIndent(cfg, "", " ") if err != nil {