package main import ( "bytes" "database/sql" "database/sql/driver" "encoding/json" "flag" "fmt" "io/ioutil" "log" "os" "strconv" "strings" "sync" "time" "git.zero-knowledge.org/gibheer/monzero" "github.com/lib/pq" ) var ( configPath = flag.String("config", "moncheck.conf", "path to the config file") ) type ( Config struct { 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"` } States []int ) func main() { flag.Parse() raw, err := ioutil.ReadFile(*configPath) if err != nil { log.Fatalf("could not read config: %s", err) } config := Config{Timeout: "30s", Wait: "30s", Workers: 25} if err := json.Unmarshal(raw, &config); err != nil { log.Fatalf("could not parse config: %s", err) } if err := os.Setenv("PATH", strings.Join(config.Path, ":")); err != nil { log.Fatalf("could not set PATH: %s", err) } waitDuration, err := time.ParseDuration(config.Wait) if err != nil { log.Fatalf("could not parse wait duration: %s", err) } timeout, err := time.ParseDuration(config.Timeout) if err != nil { log.Fatalf("could not parse timeout: %s", err) } db, err := sql.Open("postgres", config.DB) if err != nil { log.Fatalf("could not open database connection: %s", err) } hostname, err := os.Hostname() if err != nil { log.Fatalf("could not resolve hostname: %s", err) } checker := monzero.NewChecker(monzero.CheckerConfig{ CheckerID: cfg.CheckerID, DB: db, Timeout: timeout, HostIdentifier: hostname, Executor: monzero.CheckExec, }) for i := 0; i < config.Workers; i++ { go check(checker, waitDuration) } wg := sync.WaitGroup{} wg.Add(1) wg.Wait() } func check(checker *monzero.Checker, waitDuration time.Duration) { for { if err := checker.Next(); err != nil { if err != monzero.ErrNoCheck { log.Printf("could not run check: %s", err) } time.Sleep(waitDuration) } } } 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 } // 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 }