func main() { flag.Parse() if *flagVersion { fmt.Println(version.GetVersionInfo("bosun")) os.Exit(0) } for _, m := range mains { m() } runtime.GOMAXPROCS(runtime.NumCPU()) c, err := conf.ParseFile(*flagConf) if err != nil { slog.Fatal(err) } if *flagTest { os.Exit(0) } httpListen := &url.URL{ Scheme: "http", Host: c.HTTPListen, } if strings.HasPrefix(httpListen.Host, ":") { httpListen.Host = "localhost" + httpListen.Host } if err := metadata.Init(httpListen, false); err != nil { slog.Fatal(err) } if err := sched.Load(c); err != nil { slog.Fatal(err) } if c.RelayListen != "" { go func() { mux := http.NewServeMux() mux.Handle("/api/", httputil.NewSingleHostReverseProxy(httpListen)) s := &http.Server{ Addr: c.RelayListen, Handler: mux, } slog.Fatal(s.ListenAndServe()) }() } if c.TSDBHost != "" { if err := collect.Init(httpListen, "bosun"); err != nil { slog.Fatal(err) } tsdbHost := &url.URL{ Scheme: "http", Host: c.TSDBHost, } if *flagReadonly { rp := httputil.NewSingleHostReverseProxy(tsdbHost) ts := httptest.NewServer(http.HandlerFunc(func(w http.ResponseWriter, r *http.Request) { if r.URL.Path == "/api/put" { w.WriteHeader(204) return } rp.ServeHTTP(w, r) })) slog.Infoln("readonly relay at", ts.URL, "to", tsdbHost) tsdbHost, _ = url.Parse(ts.URL) c.TSDBHost = tsdbHost.Host } } if *flagQuiet { c.Quiet = true } go func() { slog.Fatal(web.Listen(c.HTTPListen, *flagDev, c.TSDBHost)) }() go func() { if !*flagNoChecks { sched.Run() } }() go func() { sc := make(chan os.Signal, 1) signal.Notify(sc, os.Interrupt) killing := false for range sc { if killing { slog.Infoln("Second interrupt: exiting") os.Exit(1) } killing = true go func() { slog.Infoln("Interrupt: closing down...") sched.Close() slog.Infoln("done") os.Exit(1) }() } }() if *flagWatch { watch(".", "*.go", quit) watch(filepath.Join("web", "static", "templates"), "*.html", web.RunEsc) base := filepath.Join("web", "static", "js") watch(base, "*.ts", web.RunTsc) } select {} }
func main() { flag.Parse() if *flagVersion { fmt.Println(version.GetVersionInfo("bosun")) os.Exit(0) } for _, m := range mains { m() } systemConf, err := conf.LoadSystemConfigFile(*flagConf) if err != nil { slog.Fatalf("couldn't read system configuration: %v", err) } sysProvider, err := systemConf.GetSystemConfProvider() if err != nil { slog.Fatal(err) } ruleConf, err := rule.ParseFile(sysProvider.GetRuleFilePath(), systemConf.EnabledBackends()) if err != nil { slog.Fatalf("couldn't read rules: %v", err) } if *flagTest { os.Exit(0) } var ruleProvider conf.RuleConfProvider = ruleConf httpListen := &url.URL{ Scheme: "http", Host: sysProvider.GetHTTPListen(), } if strings.HasPrefix(httpListen.Host, ":") { httpListen.Host = "localhost" + httpListen.Host } if err := metadata.Init(httpListen, false); err != nil { slog.Fatal(err) } if err := sched.Load(sysProvider, ruleProvider, *flagSkipLast, *flagQuiet); err != nil { slog.Fatal(err) } if sysProvider.GetRelayListen() != "" { go func() { mux := http.NewServeMux() mux.Handle("/api/", util.NewSingleHostProxy(httpListen)) s := &http.Server{ Addr: sysProvider.GetRelayListen(), Handler: mux, } slog.Fatal(s.ListenAndServe()) }() } if sysProvider.GetTSDBHost() != "" { if err := collect.Init(httpListen, "bosun"); err != nil { slog.Fatal(err) } tsdbHost := &url.URL{ Scheme: "http", Host: sysProvider.GetTSDBHost(), } if *flagReadonly { rp := util.NewSingleHostProxy(tsdbHost) ts := httptest.NewServer(http.HandlerFunc(func(w http.ResponseWriter, r *http.Request) { if r.URL.Path == "/api/put" { w.WriteHeader(204) return } rp.ServeHTTP(w, r) })) slog.Infoln("readonly relay at", ts.URL, "to", tsdbHost) tsdbHost, _ = url.Parse(ts.URL) sysProvider.SetTSDBHost(tsdbHost.Host) } } if systemConf.GetPing() { go ping.PingHosts(sched.DefaultSched.Search, systemConf.GetPingDuration()) } if sysProvider.GetInternetProxy() != "" { web.InternetProxy, err = url.Parse(sysProvider.GetInternetProxy()) if err != nil { slog.Fatalf("InternetProxy error: %s", err) } } var cmdHook conf.SaveHook if hookPath := sysProvider.GetCommandHookPath(); hookPath != "" { cmdHook, err = conf.MakeSaveCommandHook(hookPath) if err != nil { slog.Fatal(err) } ruleProvider.SetSaveHook(cmdHook) } var reload func() error reloading := make(chan bool, 1) // a lock that we can give up acquiring reload = func() error { select { case reloading <- true: // Got lock default: return fmt.Errorf("not reloading, reload in progress") } defer func() { <-reloading }() newConf, err := rule.ParseFile(sysProvider.GetRuleFilePath(), sysProvider.EnabledBackends()) if err != nil { return err } newConf.SetSaveHook(cmdHook) newConf.SetReload(reload) oldSched := sched.DefaultSched oldDA := oldSched.DataAccess oldSearch := oldSched.Search sched.Close(true) sched.Reset() newSched := sched.DefaultSched newSched.Search = oldSearch newSched.DataAccess = oldDA slog.Infoln("schedule shutdown, loading new schedule") // Load does not set the DataAccess or Search if it is already set if err := sched.Load(sysProvider, newConf, *flagSkipLast, *flagQuiet); err != nil { slog.Fatal(err) } web.ResetSchedule() // Signal web to point to the new DefaultSchedule go func() { slog.Infoln("running new schedule") if !*flagNoChecks { sched.Run() } }() slog.Infoln("config reload complete") return nil } ruleProvider.SetReload(reload) go func() { slog.Fatal(web.Listen(sysProvider.GetHTTPListen(), *flagDev, sysProvider.GetTSDBHost(), reload)) }() go func() { if !*flagNoChecks { sched.Run() } }() go func() { sc := make(chan os.Signal, 1) signal.Notify(sc, os.Interrupt, syscall.SIGTERM) killing := false for range sc { if killing { slog.Infoln("Second interrupt: exiting") os.Exit(1) } killing = true go func() { slog.Infoln("Interrupt: closing down...") sched.Close(false) slog.Infoln("done") os.Exit(1) }() } }() if *flagWatch { watch(".", "*.go", quit) watch(filepath.Join("web", "static", "templates"), "*.html", web.RunEsc) base := filepath.Join("web", "static", "js") watch(base, "*.ts", web.RunTsc) } select {} }