2019-06-03 15:38:46 +02:00
|
|
|
package runtime
|
|
|
|
|
|
|
|
import (
|
2019-06-05 12:00:11 +02:00
|
|
|
"net"
|
|
|
|
"sync"
|
|
|
|
"time"
|
2019-06-03 15:38:46 +02:00
|
|
|
|
2019-06-05 12:00:11 +02:00
|
|
|
"github.com/FreifunkBremen/yanic/lib/duration"
|
|
|
|
"github.com/digineo/go-ping"
|
|
|
|
"github.com/jinzhu/gorm"
|
|
|
|
log "github.com/sirupsen/logrus"
|
2019-06-03 15:38:46 +02:00
|
|
|
|
2019-06-05 12:00:11 +02:00
|
|
|
"github.com/FreifunkBremen/freifunkmanager/data"
|
2019-06-03 15:38:46 +02:00
|
|
|
)
|
|
|
|
|
2019-06-05 12:00:11 +02:00
|
|
|
type PingerConfig struct {
|
|
|
|
Enable bool `toml:"enable"`
|
|
|
|
Every duration.Duration `toml:"every"`
|
|
|
|
Timeout duration.Duration `toml:"timeout"`
|
|
|
|
Count int `toml:"count"`
|
|
|
|
}
|
|
|
|
|
2019-06-03 15:38:46 +02:00
|
|
|
type Pinger struct {
|
|
|
|
db *gorm.DB
|
2019-06-05 12:00:11 +02:00
|
|
|
config *PingerConfig
|
|
|
|
blacklistFor time.Duration
|
2019-06-03 15:38:46 +02:00
|
|
|
sendResult func(*data.PingResult)
|
2019-06-05 12:00:11 +02:00
|
|
|
stop bool
|
|
|
|
wg sync.WaitGroup
|
|
|
|
p *ping.Pinger
|
2019-06-03 15:38:46 +02:00
|
|
|
}
|
|
|
|
|
2019-06-05 12:00:11 +02:00
|
|
|
func NewPinger(db *gorm.DB, config *PingerConfig, blacklistFor time.Duration, sendResult func(*data.PingResult)) (*Pinger, error) {
|
|
|
|
ping, err := ping.New("", "::")
|
|
|
|
if err != nil {
|
|
|
|
return nil, err
|
|
|
|
}
|
|
|
|
|
2019-06-03 15:38:46 +02:00
|
|
|
return &Pinger{
|
|
|
|
db: db,
|
2019-06-05 12:00:11 +02:00
|
|
|
config: config,
|
|
|
|
blacklistFor: blacklistFor,
|
2019-06-03 15:38:46 +02:00
|
|
|
sendResult: sendResult,
|
2019-06-05 12:00:11 +02:00
|
|
|
stop: false,
|
|
|
|
p: ping,
|
2019-06-03 15:38:46 +02:00
|
|
|
}, nil
|
|
|
|
}
|
|
|
|
|
|
|
|
func (pinger *Pinger) Start() {
|
2019-06-05 12:00:11 +02:00
|
|
|
pinger.wg.Add(1)
|
|
|
|
timer := time.NewTimer(pinger.config.Every.Duration)
|
|
|
|
for !pinger.stop {
|
|
|
|
select {
|
|
|
|
case <-timer.C:
|
|
|
|
pinger.run()
|
|
|
|
timer.Reset(pinger.config.Every.Duration)
|
|
|
|
}
|
|
|
|
}
|
|
|
|
timer.Stop()
|
|
|
|
pinger.wg.Done()
|
2019-06-03 15:38:46 +02:00
|
|
|
}
|
|
|
|
|
|
|
|
func (pinger *Pinger) Stop() {
|
2019-06-05 12:00:11 +02:00
|
|
|
pinger.stop = true
|
|
|
|
pinger.wg.Wait()
|
2019-06-03 15:38:46 +02:00
|
|
|
}
|
|
|
|
|
|
|
|
func (pinger *Pinger) run() {
|
2019-06-05 12:00:11 +02:00
|
|
|
result := &data.PingResult{}
|
|
|
|
now := time.Now()
|
2019-06-03 15:38:46 +02:00
|
|
|
|
2019-06-05 12:00:11 +02:00
|
|
|
count := 0
|
|
|
|
var nodes []*Node
|
2019-06-03 15:38:46 +02:00
|
|
|
|
2019-06-05 12:00:11 +02:00
|
|
|
pinger.db.Find(&nodes).Count(&count)
|
2019-06-03 15:38:46 +02:00
|
|
|
|
2019-06-05 12:00:11 +02:00
|
|
|
wg := sync.WaitGroup{}
|
|
|
|
wg.Add(count)
|
2019-06-03 15:38:46 +02:00
|
|
|
|
2019-06-05 12:00:11 +02:00
|
|
|
for _, node := range nodes {
|
2019-06-03 15:38:46 +02:00
|
|
|
go func(n *Node) {
|
2019-06-05 12:00:11 +02:00
|
|
|
defer wg.Done()
|
|
|
|
if n.Blacklist.After(now.Add(-pinger.blacklistFor)) {
|
|
|
|
return
|
|
|
|
}
|
|
|
|
|
|
|
|
addr, err := net.ResolveIPAddr("ip6", n.Address)
|
|
|
|
if err != nil {
|
|
|
|
return
|
|
|
|
}
|
|
|
|
|
|
|
|
_, err = pinger.p.PingAttempts(addr, pinger.config.Timeout.Duration, pinger.config.Count)
|
|
|
|
|
|
|
|
if err == nil {
|
|
|
|
result.True = append(result.True, n.NodeID)
|
|
|
|
} else {
|
|
|
|
result.False = append(result.False, n.NodeID)
|
|
|
|
}
|
|
|
|
|
|
|
|
}(node)
|
|
|
|
}
|
|
|
|
wg.Wait()
|
|
|
|
|
|
|
|
log.WithFields(map[string]interface{}{
|
|
|
|
"count": count,
|
|
|
|
"count_skipped": count - (len(result.True) + len(result.False)),
|
|
|
|
"count_false": len(result.False),
|
|
|
|
"count_true": len(result.True),
|
|
|
|
}).Debug("pinger complete")
|
|
|
|
|
|
|
|
pinger.sendResult(result)
|
|
|
|
}
|