refactor notifier config validation

master
Norwin 5 years ago
parent a9659de229
commit 3a48d3ae5a

@ -51,11 +51,10 @@ var debugCacheCmd = &cobra.Command{
},
}
var debugNotificationsCmd = &cobra.Command{
Use: "notifications",
Short: "Verify that notifications are working",
Long: `osem_notify debug notifications sends a test notification according
Long: `osem_notify debug notifications sends a test notification according
to healthchecks.default.notifications.options as defined in the config file`,
RunE: func(cmd *cobra.Command, args []string) error {
defaultNotifyConf := &core.NotifyConfig{}
@ -66,11 +65,11 @@ to healthchecks.default.notifications.options as defined in the config file`,
for transport, notifier := range core.Notifiers {
notLog := log.WithField("transport", transport)
opts := defaultNotifyConf.Notifications.Options
notLog.Infof("testing notifer %s with options %v", transport, opts)
opts := defaultNotifyConf.Notifications
notLog.Infof("testing notifer %s with options %v", transport, opts.Options)
n, err := notifier.New(opts)
if err != nil {
notLog.Warnf("could not initialize %s notifier. configuration might be missing?", transport)
notLog.Warnf("could not initialize %s notifier: %s", transport, err)
continue
}

@ -39,24 +39,22 @@ func initConfig() {
}
func validateConfig() {
transport := viper.GetString("defaultHealthchecks.notifications.transport")
if viper.GetBool("notify") && transport == "email" {
if len(viper.GetStringSlice("defaultHealthchecks.notifications.options.recipients")) == 0 {
log.Warn("No recipients set up for transport email")
if viper.GetString("notify") != "" {
if len(viper.GetStringSlice("healthchecks.default.notifications.options.recipients")) == 0 {
log.Warn("No default recipients set up for notifications!")
}
emailRequired := []string{
viper.GetString("email.host"),
viper.GetString("email.port"),
viper.GetString("email.user"),
viper.GetString("email.pass"),
viper.GetString("email.from"),
var conf = &core.TransportConfig{}
if err := viper.UnmarshalKey("healthchecks.default.notifications", conf); err != nil {
log.Error("invalid default notification configuration: ", err)
os.Exit(1)
}
for _, conf := range emailRequired {
if conf == "" {
log.Error("Default transport set as email, but missing email config")
os.Exit(1)
}
// creating a notifier validates its configuration
_, err := core.GetNotifier(conf)
if err != nil {
log.Error(err)
os.Exit(1)
}
}
}
@ -85,8 +83,7 @@ func getNotifyConf(boxID string) (*core.NotifyConfig, error) {
if keyDefined("healthchecks.default.events") {
conf.Events = []core.NotifyEvent{}
}
err := viper.UnmarshalKey("healthchecks.default", conf)
if err != nil {
if err := viper.UnmarshalKey("healthchecks.default", conf); err != nil {
return nil, err
}
@ -94,8 +91,7 @@ func getNotifyConf(boxID string) (*core.NotifyConfig, error) {
if keyDefined("healthchecks." + boxID + ".events") {
conf.Events = []core.NotifyEvent{}
}
err = viper.UnmarshalKey("healthchecks."+boxID, conf)
if err != nil {
if err := viper.UnmarshalKey("healthchecks."+boxID, conf); err != nil {
return nil, err
}

@ -10,22 +10,31 @@ import (
"github.com/spf13/viper"
)
// box config required for the EmailNotifier
// box config required for the EmailNotifier (TransportConfig.Options)
type EmailNotifier struct {
Recipients []string
}
func (n EmailNotifier) New(config interface{}) (AbstractNotifier, error) {
func (n EmailNotifier) New(config TransportConfig) (AbstractNotifier, error) {
// validate transport configuration
// :TransportConfSourceHack @FIXME: dont get these values from viper, as the core package
// should be agnostic of the source of configuration!
requiredConf := []string{"email.user", "email.pass", "email.host", "email.port", "email.from"}
for _, key := range requiredConf {
if viper.GetString(key) == "" {
return nil, fmt.Errorf("Missing configuration key %s", key)
}
}
// assign configuration to the notifier after ensuring the correct type.
// lesson of this project: golang requires us to fuck around with type
// assertions, instead of providing us with proper inheritance.
asserted, ok := config.(EmailNotifier)
asserted, ok := config.Options.(EmailNotifier)
if !ok || asserted.Recipients == nil {
// config did not contain valid options.
// first try fallback: parse result of viper is a map[string]interface{},
// which requires a different assertion change
asserted2, ok := config.(map[string]interface{})
asserted2, ok := config.Options.(map[string]interface{})
if ok {
asserted3, ok := asserted2["recipients"].([]interface{})
if ok {
@ -79,6 +88,7 @@ func (n EmailNotifier) ComposeNotification(box *Box, checks []CheckResult) Notif
}
func (n EmailNotifier) Submit(notification Notification) error {
// :TransportConfSourceHack
auth := smtp.PlainAuth(
"",
viper.GetString("email.user"),

@ -6,26 +6,34 @@ import (
"strings"
"time"
"github.com/spf13/viper"
xmpp "github.com/mattn/go-xmpp"
"github.com/spf13/viper"
)
// box config required for the XmppNotifier
// box config required for the XmppNotifier (TransportConfig.Options)
type XmppNotifier struct {
Recipients []string
}
func (n XmppNotifier) New(config interface{}) (AbstractNotifier, error) {
func (n XmppNotifier) New(config TransportConfig) (AbstractNotifier, error) {
// validate transport configuration
// :TransportConfSourceHack
requiredConf := []string{"xmpp.user", "xmpp.pass", "xmpp.host", "xmpp.starttls"}
for _, key := range requiredConf {
if viper.GetString(key) == "" {
return nil, fmt.Errorf("Missing configuration key %s", key)
}
}
// assign configuration to the notifier after ensuring the correct type.
// lesson of this project: golang requires us to fuck around with type
// assertions, instead of providing us with proper inheritance.
asserted, ok := config.(XmppNotifier)
asserted, ok := config.Options.(XmppNotifier)
if !ok || asserted.Recipients == nil {
// config did not contain valid options.
// first try fallback: parse result of viper is a map[string]interface{},
// which requires a different assertion change
asserted2, ok := config.(map[string]interface{})
asserted2, ok := config.Options.(map[string]interface{})
if ok {
asserted3, ok := asserted2["recipients"].([]interface{})
if ok {
@ -79,6 +87,7 @@ func (n XmppNotifier) ComposeNotification(box *Box, checks []CheckResult) Notifi
}
func (n XmppNotifier) Submit(notification Notification) error {
// :TransportConfSourceHack
xmppOpts := xmpp.Options{
Host: viper.GetString("xmpp.host"),
User: viper.GetString("xmpp.user"),
@ -98,9 +107,9 @@ func (n XmppNotifier) Submit(notification Notification) error {
for _, recipient := range n.Recipients {
_, err = client.Send(xmpp.Chat{
Remote: recipient,
Remote: recipient,
Subject: notification.Subject,
Text: fmt.Sprintf("%s\n\n%s", notification.Subject, notification.Body),
Text: fmt.Sprintf("%s\n\n%s", notification.Subject, notification.Body),
})
if err != nil {

@ -14,7 +14,7 @@ var Notifiers = map[string]AbstractNotifier{
}
type AbstractNotifier interface {
New(config interface{}) (AbstractNotifier, error)
New(config TransportConfig) (AbstractNotifier, error)
ComposeNotification(box *Box, checks []CheckResult) Notification
Submit(notification Notification) error
}
@ -27,7 +27,12 @@ type Notification struct {
//////
func (box Box) GetNotifier() (AbstractNotifier, error) {
transport := box.NotifyConf.Notifications.Transport
return GetNotifier(&box.NotifyConf.Notifications)
}
func GetNotifier(config *TransportConfig) (AbstractNotifier, error) {
transport := config.Transport
if transport == "" {
return nil, fmt.Errorf("No notification transport provided")
}
@ -37,7 +42,7 @@ func (box Box) GetNotifier() (AbstractNotifier, error) {
return nil, fmt.Errorf("%s is not a supported notification transport", transport)
}
return notifier.New(box.NotifyConf.Notifications.Options)
return notifier.New(*config)
}
func (results BoxCheckResults) SendNotifications(notifyTypes []string, useCache bool) error {

Loading…
Cancel
Save