Files
cachet-monitor/config.go
Matej Kramny 162d55b3f3 huge refactor
- extendable backends
- better project structure
- better cli interface
2019-02-20 11:14:45 +08:00

176 lines
4.0 KiB
Go

package cachet
import (
"encoding/json"
"errors"
"io/ioutil"
"net"
"net/http"
"net/url"
"os"
"strings"
"github.com/castawaylabs/cachet-monitor/backends"
cachetbackend "github.com/castawaylabs/cachet-monitor/backends/cachet"
"github.com/castawaylabs/cachet-monitor/monitors"
"github.com/mitchellh/mapstructure"
"github.com/sirupsen/logrus"
yaml "gopkg.in/yaml.v2"
)
type CachetMonitor struct {
RawMonitors []map[string]interface{} `json:"monitors" yaml:"monitors"`
RawBackend map[string]interface{} `json:"backend" yaml:"backend"`
SystemName string `json:"system_name" yaml:"system_name"`
Backend backends.BackendInterface `json:"-" yaml:"-"`
Monitors []monitors.MonitorInterface `json:"-" yaml:"-"`
Immediate bool `json:"-" yaml:"-"`
}
func New(path string) (*CachetMonitor, error) {
var cfg *CachetMonitor
var data []byte
// test if its a url
url, err := url.ParseRequestURI(path)
if err == nil && len(url.Scheme) > 0 {
// download config
response, err := http.Get(path)
if err != nil {
logrus.Warn("Unable to download network configuration")
return nil, err
}
defer response.Body.Close()
data, _ = ioutil.ReadAll(response.Body)
logrus.Info("Downloaded network configuration.")
} else {
data, err = ioutil.ReadFile(path)
if err != nil {
return nil, errors.New("Unable to open file: '" + path + "'")
}
}
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")
return nil, err
}
// get default type
if backend, ok := cfg.RawBackend["type"].(string); !ok {
err = errors.New("Cannot determine backend type")
} else {
switch backend {
case "cachet":
var backend cachetbackend.CachetBackend
err = mapstructure.Decode(cfg.RawBackend, &backend)
cfg.Backend = &backend
// backend.config = cfg
default:
err = errors.New("Invalid backend type: %v" + backend)
}
}
if errs := cfg.Backend.Validate(); len(errs) > 0 {
logrus.Errorf("Backend validation errors: %v", errs)
os.Exit(1)
}
if err != nil {
logrus.Errorf("Unable to unmarshal backend: %v", err)
return nil, err
}
cfg.Monitors = make([]monitors.MonitorInterface, len(cfg.RawMonitors))
for index, rawMonitor := range cfg.RawMonitors {
var t monitors.MonitorInterface
// get default type
monType := GetMonitorType("")
if t, ok := rawMonitor["type"].(string); ok {
monType = GetMonitorType(t)
}
switch monType {
case "http":
var mon monitors.HTTPMonitor
err = mapstructure.Decode(rawMonitor, &mon)
t = &mon
case "dns":
var mon monitors.DNSMonitor
err = mapstructure.Decode(rawMonitor, &mon)
t = &mon
default:
logrus.Errorf("Invalid monitor type (index: %d) %v", index, monType)
continue
}
if err != nil {
logrus.Errorf("Unable to unmarshal monitor to type (index: %d): %v", index, err)
continue
}
mon := t.GetMonitor()
mon.Type = monType
cfg.Monitors[index] = t
}
return cfg, err
}
// Validate configuration
func (cfg *CachetMonitor) Validate() bool {
valid := true
if len(cfg.SystemName) == 0 {
// get hostname
cfg.SystemName = getHostname()
}
if len(cfg.Monitors) == 0 {
logrus.Warnf("No monitors defined!\nSee help for example configuration")
valid = false
}
for index, monitor := range cfg.Monitors {
if errs := monitor.Validate(cfg.Backend.ValidateMonitor); len(errs) > 0 {
logrus.Warnf("Monitor validation errors (index %d): %v", index, "\n - "+strings.Join(errs, "\n - "))
valid = false
}
}
return valid
}
// getHostname returns id of the current system
func getHostname() string {
hostname, err := os.Hostname()
if err == nil && len(hostname) > 0 {
return hostname
}
addrs, err := net.InterfaceAddrs()
if err != nil || len(addrs) == 0 {
return "unknown"
}
return addrs[0].String()
}
func GetMonitorType(t string) string {
if len(t) == 0 {
return "http"
}
return strings.ToLower(t)
}