Пример #1
0
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
}
Пример #2
0
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.")
}