|
|
|
package core
|
|
|
|
|
|
|
|
import (
|
|
|
|
"fmt"
|
|
|
|
"strings"
|
|
|
|
"time"
|
|
|
|
|
|
|
|
log "github.com/sirupsen/logrus"
|
|
|
|
"github.com/spf13/viper"
|
|
|
|
)
|
|
|
|
|
|
|
|
var Notifiers = map[string]AbstractNotifier{
|
|
|
|
"email": EmailNotifier{},
|
|
|
|
}
|
|
|
|
|
|
|
|
type AbstractNotifier interface {
|
|
|
|
New(config interface{}) (AbstractNotifier, error)
|
|
|
|
ComposeNotification(box *Box, checks []CheckResult) Notification
|
|
|
|
Submit(notification Notification) error
|
|
|
|
}
|
|
|
|
|
|
|
|
type Notification struct {
|
|
|
|
Body string
|
|
|
|
Subject string
|
|
|
|
}
|
|
|
|
|
|
|
|
//////
|
|
|
|
|
|
|
|
func (box Box) GetNotifier() (AbstractNotifier, error) {
|
|
|
|
transport := box.NotifyConf.Notifications.Transport
|
|
|
|
if transport == "" {
|
|
|
|
return nil, fmt.Errorf("No notification transport provided")
|
|
|
|
}
|
|
|
|
|
|
|
|
notifier := Notifiers[transport]
|
|
|
|
if notifier == nil {
|
|
|
|
return nil, fmt.Errorf("%s is not a supported notification transport", transport)
|
|
|
|
}
|
|
|
|
|
|
|
|
return notifier.New(box.NotifyConf.Notifications.Options)
|
|
|
|
}
|
|
|
|
|
|
|
|
func (results BoxCheckResults) SendNotifications() error {
|
|
|
|
results = results.FilterChangedFromCache(false)
|
|
|
|
errs := []string{}
|
|
|
|
|
|
|
|
n := results.Size()
|
|
|
|
if n == 0 {
|
|
|
|
log.Info("No notifications due.")
|
|
|
|
return nil
|
|
|
|
} else {
|
|
|
|
log.Infof("Notifying for %v checks turned bad in total...", results.Size())
|
|
|
|
}
|
|
|
|
|
|
|
|
// FIXME: only update cache when notifications sent successfully
|
|
|
|
for box, resultsDue := range results {
|
|
|
|
if len(resultsDue) == 0 {
|
|
|
|
continue
|
|
|
|
}
|
|
|
|
|
|
|
|
transport := box.NotifyConf.Notifications.Transport
|
|
|
|
notifyLog := log.WithFields(log.Fields{
|
|
|
|
"boxId": box.Id,
|
|
|
|
"transport": transport,
|
|
|
|
})
|
|
|
|
|
|
|
|
notifier, err := box.GetNotifier()
|
|
|
|
if err != nil {
|
|
|
|
notifyLog.Error(err)
|
|
|
|
errs = append(errs, err.Error())
|
|
|
|
continue
|
|
|
|
}
|
|
|
|
|
|
|
|
notification := notifier.ComposeNotification(box, resultsDue)
|
|
|
|
|
|
|
|
var submitErr error
|
|
|
|
submitErr = notifier.Submit(notification)
|
|
|
|
for retry := 1; submitErr != nil && retry < 3; retry++ {
|
|
|
|
time.Sleep(10 * time.Second)
|
|
|
|
notifyLog.Debugf("trying to submit (retry %v)", retry)
|
|
|
|
}
|
|
|
|
if submitErr != nil {
|
|
|
|
notifyLog.Error(submitErr)
|
|
|
|
errs = append(errs, submitErr.Error())
|
|
|
|
continue
|
|
|
|
}
|
|
|
|
|
|
|
|
notifyLog.Infof("Sent notification for %s via %s with %v new issues", box.Name, transport, len(resultsDue))
|
|
|
|
}
|
|
|
|
|
|
|
|
if len(errs) != 0 {
|
|
|
|
return fmt.Errorf(strings.Join(errs, "\n"))
|
|
|
|
}
|
|
|
|
return nil
|
|
|
|
}
|
|
|
|
|
|
|
|
func (results BoxCheckResults) FilterChangedFromCache(keepOk bool) BoxCheckResults {
|
|
|
|
remaining := BoxCheckResults{}
|
|
|
|
|
|
|
|
for box, boxResults := range results {
|
|
|
|
// get results from cache. they are indexed by an event ID per boxId
|
|
|
|
// filter, so that only changed result.Status remain
|
|
|
|
remaining[box] = []CheckResult{}
|
|
|
|
for _, result := range boxResults {
|
|
|
|
cached := viper.GetStringMap(fmt.Sprintf("watchcache.%s.%s", box.Id, result.EventID()))
|
|
|
|
if result.Status != cached["laststatus"] {
|
|
|
|
if result.Status != CheckOk || keepOk {
|
|
|
|
remaining[box] = append(remaining[box], result)
|
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
// TODO: reminder functionality: extract additional results with Status ERR
|
|
|
|
// from cache with time.Since(lastNotifyDate) > remindAfter.
|
|
|
|
// would require to serialize the full result..
|
|
|
|
}
|
|
|
|
|
|
|
|
// upate cache, setting lastNotifyDate to Now()
|
|
|
|
for box, boxResults := range results {
|
|
|
|
for _, result := range boxResults {
|
|
|
|
// FIXME: somehow this is not persisted?
|
|
|
|
key := fmt.Sprintf("watchcache.%s.%s", box.Id, result.EventID())
|
|
|
|
viper.Set(key+".laststatus", result.Status)
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
return remaining
|
|
|
|
}
|