diff --git a/cli/main.go b/cli/main.go index b2723c2..54e0b3e 100644 --- a/cli/main.go +++ b/cli/main.go @@ -8,11 +8,14 @@ import ( "net/url" "os" "os/signal" + "strings" "sync" "github.com/Sirupsen/logrus" cachet "github.com/castawaylabs/cachet-monitor" docopt "github.com/docopt/docopt-go" + "github.com/mitchellh/mapstructure" + "gopkg.in/yaml.v2" ) const usage = `cachet-monitor @@ -162,25 +165,31 @@ func getConfiguration(path string) (*cachet.CachetMonitor, error) { } } - if err = json.Unmarshal(data, &cfg); err != nil { + if strings.HasSuffix(path, ".yaml") || strings.HasSuffix(path, ".yml") { + err = yaml.Unmarshal(data, &cfg) + } else { + err = json.Unmarshal(data, &cfg) + } + + if err != nil { logrus.Warnf("Unable to parse configuration file") } cfg.Monitors = make([]cachet.MonitorInterface, len(cfg.RawMonitors)) for index, rawMonitor := range cfg.RawMonitors { var abstract cachet.AbstractMonitor - if err := json.Unmarshal(rawMonitor, &abstract); err != nil { - logrus.Errorf("Unable to unmarshal monitor (index: %d): %v", index, err) - continue - } - var t cachet.MonitorInterface var err error - switch abstract.Type { + monType := "" + if t, ok := rawMonitor["type"].(string); ok { + monType = t + } + + switch monType { case "http", "": var s cachet.HTTPMonitor - err = json.Unmarshal(rawMonitor, &s) + err = mapstructure.Decode(rawMonitor, &s) t = &s case "dns": // t = cachet.DNSMonitor diff --git a/config.go b/config.go index 0d4c161..9d92bac 100644 --- a/config.go +++ b/config.go @@ -1,22 +1,20 @@ package cachet import ( - "fmt" "net" "os" + "strings" "time" - "encoding/json" - "github.com/Sirupsen/logrus" ) type CachetMonitor struct { - SystemName string `json:"system_name"` - API CachetAPI `json:"api"` - RawMonitors []json.RawMessage `json:"monitors"` + SystemName string `json:"system_name"` + API CachetAPI `json:"api"` + RawMonitors []map[string]interface{} `json:"monitors" yaml:"monitors"` - Monitors []MonitorInterface `json:"-"` + Monitors []MonitorInterface `json:"-" yaml:"-"` } // Validate configuration @@ -28,7 +26,6 @@ func (cfg *CachetMonitor) Validate() bool { cfg.SystemName = getHostname() } - fmt.Println(cfg.API) if len(cfg.API.Token) == 0 || len(cfg.API.URL) == 0 { logrus.Warnf("API URL or API Token missing.\nGet help at https://github.com/castawaylabs/cachet-monitor") valid = false @@ -39,8 +36,9 @@ func (cfg *CachetMonitor) Validate() bool { valid = false } - for _, monitor := range cfg.Monitors { + for index, monitor := range cfg.Monitors { if errs := monitor.Validate(); len(errs) > 0 { + logrus.Warnf("Monitor validation errors (index %d): %v", index, "\n - "+strings.Join(errs, "\n - ")) valid = false } } diff --git a/http.go b/http.go index 6f06d3e..736b971 100644 --- a/http.go +++ b/http.go @@ -10,15 +10,33 @@ import ( "time" ) -type HTTPMonitor struct { - *AbstractMonitor +// // Investigating template +// var HTTPTemplate = MessageTemplate{ +// Subject: `{{ .Name }} - {{ .config.SystemName }}`, +// Message: `{{ .Name }} check **failed** - {{ .now }} - Method string `json:"method"` - ExpectedStatusCode int `json:"expected_status_code"` - Headers map[string]string `json:"headers"` +// {{ .lastFailReason }}`, +// } + +// // Fixed template +// var HTTPTemplate = MessageTemplate{ +// Subject: `{{ .Name }} - {{ .config.SystemName }}`, +// Message: `**Resolved** - {{ .now }} + +// - - - + +// {{ .incident.Message }}`, +// } + +type HTTPMonitor struct { + AbstractMonitor `mapstructure:",squash"` + + Method string + ExpectedStatusCode int `mapstructure:"expected_status_code"` + Headers map[string]string // compiled to Regexp - ExpectedBody string `json:"expected_body"` + ExpectedBody string `mapstructure:"expected_body"` bodyRegexp *regexp.Regexp } @@ -116,7 +134,7 @@ func (monitor *HTTPMonitor) Validate() []string { return errs } -func (mon *HTTPMonitor) GetMonitor() *AbstractMonitor { +func (mon *HTTPMonitor) GetMonitor() AbstractMonitor { return mon.AbstractMonitor } diff --git a/monitor.go b/monitor.go index fd1fa94..663c013 100644 --- a/monitor.go +++ b/monitor.go @@ -15,34 +15,34 @@ const HistorySize = 10 type MonitorInterface interface { do() bool Validate() []string - GetMonitor() *AbstractMonitor + GetMonitor() AbstractMonitor } // AbstractMonitor data model type AbstractMonitor struct { - Name string `json:"name"` - Target string `json:"target"` + Name string + Target string // (default)http, tcp, dns, icmp - Type string `json:"type"` + Type string // defaults true - Strict bool `json:"strict"` + Strict bool - Interval time.Duration `json:"interval"` - Timeout time.Duration `json:"timeout"` + Interval time.Duration + Timeout time.Duration - MetricID int `json:"metric_id"` - ComponentID int `json:"component_id"` + MetricID int `mapstructure:"metric_id"` + ComponentID int `mapstructure:"component_id"` // Templating stuff Template struct { - Investigating MessageTemplate `json:"investigating"` - Fixed MessageTemplate `json:"fixed"` - } `json:"template"` + Investigating MessageTemplate + Fixed MessageTemplate + } // Threshold = percentage - Threshold float32 `json:"threshold"` + Threshold float32 history []bool lastFailReason string @@ -59,7 +59,7 @@ func (mon *AbstractMonitor) do() bool { func (mon *AbstractMonitor) Validate() []string { return []string{} } -func (mon *AbstractMonitor) GetMonitor() *AbstractMonitor { +func (mon AbstractMonitor) GetMonitor() AbstractMonitor { return mon }