package main import ( "context" "flag" "fmt" "net/http" "os" "sync" "git.frostfs.info/TrueCloudLab/frostfs-node/internal/logs" "git.frostfs.info/TrueCloudLab/frostfs-node/misc" "git.frostfs.info/TrueCloudLab/frostfs-node/pkg/innerring" httputil "git.frostfs.info/TrueCloudLab/frostfs-node/pkg/util/http" "git.frostfs.info/TrueCloudLab/frostfs-node/pkg/util/logger" "github.com/prometheus/client_golang/prometheus/promhttp" "github.com/spf13/viper" "go.uber.org/zap" ) const ( // ErrorReturnCode returns when application crashed at initialization stage. ErrorReturnCode = 1 // SuccessReturnCode returns when application closed without panic. SuccessReturnCode = 0 EnvPrefix = "FROSTFS_IR" ) var ( wg = new(sync.WaitGroup) intErr = make(chan error) // internal inner ring errors logPrm = new(logger.Prm) innerRing *innerring.Server httpServers []*httputil.Server log *logger.Logger cfg *viper.Viper configFile *string configDir *string ) func exitErr(err error) { if err != nil { fmt.Println(err) os.Exit(ErrorReturnCode) } } func main() { configFile = flag.String("config", "", "path to config") configDir = flag.String("config-dir", "", "path to config directory") versionFlag := flag.Bool("version", false, "frostfs-ir node version") flag.Parse() if *versionFlag { fmt.Print(misc.BuildInfo("FrostFS Inner Ring node")) os.Exit(SuccessReturnCode) } var err error cfg, err = newConfig() exitErr(err) err = logPrm.SetLevelString( cfg.GetString("logger.level"), ) exitErr(err) log, err = logger.NewLogger(logPrm) exitErr(err) ctx, cancel := context.WithCancel(context.Background()) initHTTPServers(cfg) innerRing, err = innerring.New(ctx, log, cfg, intErr) exitErr(err) // start HTTP servers for _, srv := range httpServers { wg.Add(1) go func(srv *httputil.Server) { exitErr(srv.Serve()) wg.Done() }(srv) } // start inner ring err = innerRing.Start(ctx, intErr) exitErr(err) log.Info(logs.CommonApplicationStarted, zap.String("version", misc.Version)) watchForSignal(cancel) <-ctx.Done() // graceful shutdown log.Debug(logs.FrostFSNodeWaitingForAllProcessesToStop) wg.Wait() log.Info(logs.FrostFSIRApplicationStopped) } func initHTTPServers(cfg *viper.Viper) { items := []struct { cfgPrefix string handler func() http.Handler }{ {"pprof", httputil.Handler}, {"prometheus", promhttp.Handler}, } httpServers = make([]*httputil.Server, 0, len(items)) for _, item := range items { if !cfg.GetBool(item.cfgPrefix + ".enabled") { log.Info(item.cfgPrefix + " is disabled, skip") continue } addr := cfg.GetString(item.cfgPrefix + ".address") var prm httputil.HTTPSrvPrm prm.Address = addr prm.Handler = item.handler() httpServers = append(httpServers, httputil.New(prm, httputil.WithShutdownTimeout( cfg.GetDuration(item.cfgPrefix+".shutdown_timeout"), ), ), ) } } func shutdown() { innerRing.Stop() // shut down HTTP servers for _, srv := range httpServers { wg.Add(1) go func(srv *httputil.Server) { err := srv.Shutdown() if err != nil { log.Debug(logs.FrostFSIRCouldNotShutdownHTTPServer, zap.String("error", err.Error()), ) } wg.Done() }(srv) } }