func testParse(t *testing.T, rawurl string) *url.URL { u, err := myurl.ParseWithSocket(rawurl) if err != nil { t.Fatal(e.Trace(e.Forward(err))) } return u }
func main() { confs := flag.String("conf", "monitor.ini", "Monitor configuration file.") logfile := flag.String("log", "", "Log file.") version := flag.Bool("version", false, "Monitor version number.") flag.Parse() if *version { fmt.Println("Monitor version is:", definitions.Version) os.Exit(0) } pid := os.Getpid() pidstr := strconv.FormatInt(int64(pid), 10) log.SetPrefix("monitor (" + pidstr + ") ") if *logfile != "" { file := logToFile(*logfile) sig := make(chan os.Signal) signal.Notify(sig, syscall.SIGHUP) go func() { for { select { case <-sig: log.Println("Closing log...") oldfile := file file = logToFile(*logfile) oldfile.Close() log.Println("Log restarted.") } } }() } log.Println("Starting...") file, err := ini.LoadFile(*confs) if err != nil { log.Fatal("Open failed with error:", err) } var em *mail.Email if section, ok := file["smtp"]; ok { tos := strings.Split(strings.Trim(section["to"], "\""), ",") for i, to := range tos { tos[i] = strings.TrimSpace(to) } skipVerify := false if section["skip_verify"] == "true" { skipVerify = true } var timeout int64 = 30 if section["timeout"] != "" { timeout, err = strconv.ParseInt(section["timeout"], 10, 64) if err != nil { log.Fatal("Invalid smtp timeout.") } } em = &mail.Email{ Smtp: strings.Trim(section["smtp"], "\""), From: strings.Trim(section["from"], "\""), To: tos, Hello: strings.Trim(section["hello"], "\""), User: strings.Trim(section["user"], "\""), Pass: strings.Trim(section["pass"], "\""), Timeout: time.Duration(timeout) * time.Second, InsecureSkipVerify: skipVerify, } } status.Name = "monitor" status.Email = em status.Debug = status.Normal if section, ok := file["debug"]; ok { if l, err := strconv.ParseInt(section["level"], 10, 8); err == nil { status.Debug = status.DebugLevel(l) } } wait := definitions.WaitDefault conntries := definitions.ConnTriesDefault if section, ok := file["connections"]; ok { if w, err := strconv.ParseInt(section["wait"], 10, 32); err == nil { wait = time.Duration(w) * time.Second } if r, err := strconv.ParseInt(section["retries"], 10, 32); err == nil { conntries = int(r) } if t, ok := section["TLSChecks"]; ok { if t == "false" { ping.SkipSecurityChecksTLS(true) } else if t == "true" { ping.SkipSecurityChecksTLS(false) } else { ping.SkipSecurityChecksTLS(false) log.Println("TLSChecks option is invalid.") } } if r, err := strconv.ParseInt(section["DialTimeout"], 10, 32); err == nil { ping.DialTimeout = time.Duration(r) * time.Second } if r, err := strconv.ParseInt(section["TLSHandshakeTimeout"], 10, 32); err == nil { ping.TLSHandshakeTimeout = time.Duration(r) * time.Second } if r, err := strconv.ParseInt(section["HttpResponseHeaderTimeout"], 10, 32); err == nil { ping.ResponseHeaderTimeout = time.Duration(r) * time.Second } if r, err := strconv.ParseInt(section["HttpTimeout"], 10, 32); err == nil { ping.HttpTimeout = time.Duration(r) * time.Second } } monitors := make([]monitors.Monitor, 0, len(file)) var numQueues uint64 = 1<<64 - 1 serversQueue := queue.NewPriority(numQueues, func() (queue.Queue, error) { return queue.NewSimple(10, 1), nil }) defer serversQueue.Stop() monitorsQueue := queue.NewPriority(numQueues, func() (queue.Queue, error) { return queue.NewSimple(10, 1), nil }) defer monitorsQueue.Stop() serversQueue.Process() monitorsQueue.Process() for name, section := range file { switch { case strings.Contains(name, "server:"): if em == nil { log.Fatal("smtp section not found") } d := new(daemon.Daemon) d.DaemonName = strings.TrimPrefix(name, "server:") cmd, args := util.SplitCmd(strings.Trim(section["cmd"], "\"")) d.RestartCmd = cmd d.RestartArgs = args forcekillcmd, forcekillargs := util.SplitCmd(strings.Trim(section["forcekill"], "\"")) d.ForceKillCmd = forcekillcmd d.ForceKillArgs = forcekillargs urls := strings.Split(strings.Trim(section["urls"], "\""), " ") d.Urls = make([]*url.URL, len(urls)) j := 0 for i, u := range urls { u = strings.TrimSpace(u) if u == "" { continue } d.Urls[i], err = utilUrl.ParseWithSocket(u) if err != nil { err = e.Push(e.Forward(err), e.New("url [%v] is invalid", u)) log.Fatal("Url in", d.DaemonName, "is invalid:", e.Trace(e.Forward(err))) } j++ } d.Urls = d.Urls[:j] sleep, err := strconv.ParseInt(section["sleep"], 10, 32) if err != nil { log.Fatal("sleep value for", d.DaemonName, "is invalid:", e.Trace(e.Forward(err))) } d.Sleep = time.Duration(sleep) * time.Second tries64, _ := strconv.ParseInt(section["tries"], 10, 32) d.Tries = int(tries64) d.PidFile = strings.Trim(section["pidFile"], "\"") d.Prio = numQueues - 1 if p, err := strconv.ParseUint(section["prio"], 10, 32); err == nil { d.Prio = uint64(p) } d.Queue = serversQueue d.ExecTimeout = 4 * time.Minute monitor, err := daemon.Init(d) if err != nil { log.Fatal("New daemon for "+d.DaemonName+" failed with error ", e.Trace(e.Forward(err))) } log.Println("Monitor installed for " + d.DaemonName + ".") defer monitor.Close() monitors = append(monitors, monitor) case strings.Contains(name, "monitor:"): if em == nil { log.Fatal("smtp section not found") } vs := new(virtualserver.VirtualServer) vs.VirtualServerName = strings.TrimPrefix(name, "monitor:") vs.PidFile = strings.Trim(section["pidFile"], "\"") cmdargs := strings.Split(strings.Trim(section["cmd"], "\""), " ") if len(cmdargs) == 0 { log.Fatal("cmd value for", vs.VirtualServerName, "is invalid.") } vs.RestartCmd = cmdargs[0] vs.RestartArgs = make([]string, 0) if len(cmdargs) > 1 { vs.RestartArgs = cmdargs[1:] } net := strings.Trim(section["net"], "\"") if net == "" { log.Fatal("net value for", vs.VirtualServerName, "is invalid.") } vs.MonitorUrl, err = utilUrl.ParseWithSocket(net) if err != nil { log.Fatal("net value for", vs.VirtualServerName, "is invalid:", e.Trace(e.Forward(err))) } sleep, err := strconv.ParseInt(section["sleep"], 10, 32) if err != nil { log.Fatal("sleep value for", vs.VirtualServerName, "is invalid:", e.Trace(e.Forward(err))) } vs.Sleep = time.Duration(sleep) * time.Second tries64, _ := strconv.ParseInt(section["tries"], 10, 32) vs.Tries = int(tries64) forcekill := strings.Trim(section["forcekill"], "\"") if forcekill == "" { log.Fatal("forcekill value for", vs.VirtualServerName, "is invalid:", e.Trace(e.Forward(err))) } vs.ForceKillCmd, vs.ForceKillArgs = util.SplitCmd(forcekill) beforestart := strings.Trim(section["beforestart"], "\"") if beforestart == "" { log.Fatal("beforestart value for", vs.VirtualServerName, "is invalid:", e.Trace(e.Forward(err))) } vs.BeforeStartCmd, vs.BeforeStartArgs = util.SplitCmd(beforestart) vs.Prio = numQueues - 1 if p, err := strconv.ParseUint(section["prio"], 10, 32); err == nil { vs.Prio = uint64(p) } vs.ConnWait = wait vs.ConnTries = conntries vs.Email = em vs.Queue = monitorsQueue vs.ExecTimeout = 6 * time.Minute monitor, err := virtualserver.Init(vs) if err != nil { log.Fatal("NewMetaMonitor for "+vs.VirtualServerName+" failed with error ", e.Trace(e.Forward(err))) } defer monitor.Close() log.Println("Meta monitor installed for " + vs.VirtualServerName + ".") monitors = append(monitors, monitor) case strings.Contains(name, "disk:"): if em == nil { log.Fatal("smtp section not found") } name := strings.TrimPrefix(name, "disk:") if name == "" { continue } sleep, err := strconv.ParseInt(section["sleep"], 10, 32) if err != nil { log.Fatal("sleep value for", name, "is invalid:", e.Trace(e.Forward(err))) continue } minfree, err := strconv.ParseFloat(section["min"], 32) if err != nil { log.Fatal("min value for", name, "is invalid:", e.Trace(e.Forward(err))) continue } var alarm time.Duration if alarmInt, err := strconv.ParseInt(section["alarm"], 10, 32); err == nil { alarm = time.Duration(alarmInt) * time.Second } dm := disk.New(name, strings.Trim(section["mount"], "\""), int(sleep), float32(minfree), em, alarm) defer dm.Close() log.Println("Disk monitor installed for " + name + ".") monitors = append(monitors, dm) } } if section, ok := file["alive"]; ok { if em == nil { log.Fatal("smtp section not found") } urlStr, ok := section["url"] if !ok { log.Fatal("Alive section doesn't have the url entry.") } urlStr = strings.Trim(urlStr, "\"") url, err := utilUrl.ParseWithSocket(urlStr) if err != nil { log.Fatal("Invalid url:", e.Trace(e.Forward(err))) } a, err := alive.New(url.Scheme, url.Host, em, monitors) if err != nil { log.Fatal("Can't start alive:", e.Trace(e.Forward(err))) } defer a.Close() monitors = append(monitors, a) log.Println("Alive server installed.") } if len(monitors) > 0 { time := time.Now().Format("jan 2, 2006 at 3:04pm (MST)") msg := "Monitor, pid " + pidstr + ", started at " + time + " monitoring this:\n\n" for _, m := range monitors { msg += "\t- " + m.Type().String() + " " + m.Name() + "\n" } err := em.Send("Monitor started ("+pidstr+").", msg) if err != nil { log.Println("Can't send the email informing the start of the monitors, error:", e.Trace(e.Forward(err))) } // Termination signal stuff sig := make(chan os.Signal) signal.Notify(sig, syscall.SIGINT, syscall.SIGKILL, syscall.SIGTERM) <-sig err = em.Send("Monitor stoped ("+pidstr+").", "") if err != nil { log.Println("Can't send the email informing the end of the monitors, error:", e.Trace(e.Forward(err))) } } // End defer log.Println("End.") }