2018-11-16 10:39:21 +01:00
|
|
|
package main
|
|
|
|
|
|
|
|
import (
|
|
|
|
"bytes"
|
|
|
|
"database/sql"
|
2018-11-18 21:38:04 +01:00
|
|
|
"database/sql/driver"
|
2018-11-16 10:39:21 +01:00
|
|
|
"encoding/json"
|
|
|
|
"flag"
|
2018-11-18 21:38:04 +01:00
|
|
|
"fmt"
|
2018-11-16 10:39:21 +01:00
|
|
|
"io/ioutil"
|
|
|
|
"log"
|
2018-12-10 09:34:00 +01:00
|
|
|
"os"
|
2018-11-18 21:38:04 +01:00
|
|
|
"strconv"
|
|
|
|
"strings"
|
2018-11-16 10:39:21 +01:00
|
|
|
"sync"
|
|
|
|
"time"
|
|
|
|
|
2021-12-02 15:57:00 +01:00
|
|
|
"git.zero-knowledge.org/gibheer/monzero"
|
2018-11-16 10:39:21 +01:00
|
|
|
)
|
|
|
|
|
|
|
|
var (
|
|
|
|
configPath = flag.String("config", "moncheck.conf", "path to the config file")
|
|
|
|
)
|
|
|
|
|
|
|
|
type (
|
|
|
|
Config struct {
|
2019-08-12 14:49:53 +02:00
|
|
|
DB string `json:"db"`
|
|
|
|
Timeout string `json:"timeout"`
|
|
|
|
Wait string `json:"wait"`
|
|
|
|
Path []string `json:"path"`
|
|
|
|
Workers int `json:"workers"`
|
|
|
|
CheckerID int `json:"checker_id"`
|
2018-11-16 10:39:21 +01:00
|
|
|
}
|
2018-11-18 21:38:04 +01:00
|
|
|
|
|
|
|
States []int
|
2018-11-16 10:39:21 +01:00
|
|
|
)
|
|
|
|
|
|
|
|
func main() {
|
|
|
|
flag.Parse()
|
|
|
|
|
|
|
|
raw, err := ioutil.ReadFile(*configPath)
|
|
|
|
if err != nil {
|
|
|
|
log.Fatalf("could not read config: %s", err)
|
|
|
|
}
|
2019-01-07 15:50:55 +01:00
|
|
|
config := Config{Timeout: "30s", Wait: "30s", Workers: 25}
|
2018-11-16 10:39:21 +01:00
|
|
|
if err := json.Unmarshal(raw, &config); err != nil {
|
|
|
|
log.Fatalf("could not parse config: %s", err)
|
|
|
|
}
|
|
|
|
|
2018-12-10 09:34:00 +01:00
|
|
|
if err := os.Setenv("PATH", strings.Join(config.Path, ":")); err != nil {
|
|
|
|
log.Fatalf("could not set PATH: %s", err)
|
|
|
|
}
|
|
|
|
|
2018-11-16 10:39:21 +01:00
|
|
|
waitDuration, err := time.ParseDuration(config.Wait)
|
|
|
|
if err != nil {
|
|
|
|
log.Fatalf("could not parse wait duration: %s", err)
|
|
|
|
}
|
2018-11-29 10:45:33 +01:00
|
|
|
timeout, err := time.ParseDuration(config.Timeout)
|
|
|
|
if err != nil {
|
|
|
|
log.Fatalf("could not parse timeout: %s", err)
|
|
|
|
}
|
2018-11-16 10:39:21 +01:00
|
|
|
|
|
|
|
db, err := sql.Open("postgres", config.DB)
|
|
|
|
if err != nil {
|
|
|
|
log.Fatalf("could not open database connection: %s", err)
|
|
|
|
}
|
|
|
|
|
2019-01-11 13:02:37 +01:00
|
|
|
hostname, err := os.Hostname()
|
|
|
|
if err != nil {
|
|
|
|
log.Fatalf("could not resolve hostname: %s", err)
|
|
|
|
}
|
|
|
|
|
2021-12-02 17:53:47 +01:00
|
|
|
checker, err := monzero.NewChecker(monzero.CheckerConfig{
|
|
|
|
CheckerID: config.CheckerID,
|
2021-12-02 15:57:00 +01:00
|
|
|
DB: db,
|
|
|
|
Timeout: timeout,
|
|
|
|
HostIdentifier: hostname,
|
|
|
|
Executor: monzero.CheckExec,
|
|
|
|
})
|
2021-12-02 17:53:47 +01:00
|
|
|
if err != nil {
|
|
|
|
log.Fatalf("could not create checker instance: %s", err)
|
|
|
|
}
|
2021-12-02 15:57:00 +01:00
|
|
|
|
2019-01-07 15:50:55 +01:00
|
|
|
for i := 0; i < config.Workers; i++ {
|
2021-12-02 15:57:00 +01:00
|
|
|
go check(checker, waitDuration)
|
2018-11-16 10:39:21 +01:00
|
|
|
}
|
|
|
|
wg := sync.WaitGroup{}
|
|
|
|
wg.Add(1)
|
|
|
|
wg.Wait()
|
|
|
|
}
|
|
|
|
|
2021-12-02 15:57:00 +01:00
|
|
|
func check(checker *monzero.Checker, waitDuration time.Duration) {
|
2018-11-16 10:39:21 +01:00
|
|
|
for {
|
2021-12-02 15:57:00 +01:00
|
|
|
if err := checker.Next(); err != nil {
|
|
|
|
if err != monzero.ErrNoCheck {
|
|
|
|
log.Printf("could not run check: %s", err)
|
2018-11-16 10:39:21 +01:00
|
|
|
}
|
2021-12-02 15:57:00 +01:00
|
|
|
time.Sleep(waitDuration)
|
2018-11-16 10:39:21 +01:00
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
2018-11-18 21:38:04 +01:00
|
|
|
|
|
|
|
func (s *States) Value() (driver.Value, error) {
|
|
|
|
last := len(*s)
|
|
|
|
if last == 0 {
|
|
|
|
return "{}", nil
|
|
|
|
}
|
|
|
|
result := strings.Builder{}
|
|
|
|
_, err := result.WriteString("{")
|
|
|
|
if err != nil {
|
|
|
|
return "", fmt.Errorf("could not write to buffer: %s", err)
|
|
|
|
}
|
|
|
|
for i, state := range *s {
|
|
|
|
if _, err := fmt.Fprintf(&result, "%d", state); err != nil {
|
|
|
|
return "", fmt.Errorf("could not write to buffer: %s", err)
|
|
|
|
}
|
|
|
|
if i < last-1 {
|
|
|
|
if _, err := result.WriteString(","); err != nil {
|
|
|
|
return "", fmt.Errorf("could not write to buffer: %s", err)
|
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
if _, err := result.WriteString("}"); err != nil {
|
|
|
|
return "", fmt.Errorf("could not write to buffer: %s", err)
|
|
|
|
}
|
|
|
|
return result.String(), nil
|
|
|
|
}
|
|
|
|
|
|
|
|
func (s *States) Scan(src interface{}) error {
|
|
|
|
switch src := src.(type) {
|
|
|
|
case []byte:
|
|
|
|
tmp := bytes.Trim(src, "{}")
|
|
|
|
states := bytes.Split(tmp, []byte(","))
|
|
|
|
result := make([]int, len(states))
|
|
|
|
for i, state := range states {
|
|
|
|
var err error
|
|
|
|
result[i], err = strconv.Atoi(string(state))
|
|
|
|
if err != nil {
|
|
|
|
return fmt.Errorf("could not parse element %s: %s", state, err)
|
|
|
|
}
|
|
|
|
}
|
|
|
|
*s = result
|
|
|
|
return nil
|
|
|
|
default:
|
|
|
|
return fmt.Errorf("could not convert %T to states", src)
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
// Append prepends the new state before all others.
|
|
|
|
func (s *States) Add(state int) {
|
|
|
|
vals := *s
|
|
|
|
statePos := 5
|
|
|
|
if len(vals) < 6 {
|
|
|
|
statePos = len(vals)
|
|
|
|
}
|
|
|
|
*s = append([]int{state}, vals[:statePos]...)
|
|
|
|
return
|
|
|
|
}
|
2018-11-20 21:47:35 +01:00
|
|
|
|
|
|
|
// ToOK returns true when the state returns from != 0 to 0.
|
|
|
|
func (s *States) ToOK() bool {
|
|
|
|
vals := *s
|
|
|
|
if len(vals) == 0 {
|
|
|
|
return false
|
|
|
|
}
|
|
|
|
if len(vals) <= 1 {
|
|
|
|
return vals[0] == 0
|
|
|
|
}
|
|
|
|
if vals[0] == 0 && vals[1] > 0 {
|
|
|
|
return true
|
|
|
|
}
|
|
|
|
return false
|
|
|
|
}
|