You can not select more than 25 topics Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.

115 lines
2.1 KiB

package main
import (
"math/rand"
"net"
"time"
"github.com/erikh/ping"
"github.com/pkg/errors"
)
func init() {
rand.Seed(time.Now().Unix())
}
type monitor interface {
New() monitor
Name() string
Type() string
Interval() time.Duration
Query() error
FromConfig(monitorConfig) error
}
type pingMonitor struct {
name string
host string
count uint
timeout time.Duration
pollInterval time.Duration
}
func (pm *pingMonitor) New() monitor {
return &pingMonitor{}
}
func (pm *pingMonitor) Name() string {
return pm.name
}
func (pm *pingMonitor) Type() string {
return "ping"
}
func (pm *pingMonitor) Interval() time.Duration {
return pm.pollInterval
}
func (pm *pingMonitor) Query() error {
addrs, err := net.LookupHost(pm.host)
if err != nil {
return err
}
errChan := make(chan error, len(addrs))
doneChan := make(chan struct{}, len(addrs))
for i := uint(0); i < pm.count; i++ {
for _, addr := range addrs {
go func(addr string) {
defer func() { doneChan <- struct{}{} }()
ip := net.ParseIP(addr)
if err := ping.Pinger(&net.IPAddr{IP: ip}, pm.timeout); err != nil {
errChan <- err
}
}(addr)
}
for i := 0; i < len(addrs); i++ {
select {
case err := <-errChan:
return err
case <-doneChan:
}
}
time.Sleep(10 * time.Millisecond)
}
return nil
}
func (pm *pingMonitor) FromConfig(mc monitorConfig) error {
pm.name = mc.baseConfig.Name
if host, ok := mc.Params["host"].(string); ok {
pm.host = host
} else {
return errors.Errorf("missing host in %q ping monitor", pm.name)
}
if count, ok := mc.Params["count"].(int); ok {
pm.count = uint(count)
} else {
return errors.Errorf("missing count in %q ping monitor", pm.name)
}
if timeout, ok := mc.Params["timeout"].(string); ok {
var err error
pm.timeout, err = time.ParseDuration(timeout)
if err != nil {
return errors.Wrapf(err, "invalid timeout in %q ping monitor", pm.name)
}
} else {
return errors.Errorf("missing timeout in %q ping monitor", pm.name)
}
if mc.Interval == 0 {
return errors.Errorf("missing interval in %q ping monitor", pm.name)
}
pm.pollInterval = mc.Interval
return nil
}