func main() { runtime.GOMAXPROCS(runtime.NumCPU()) kingpin.Version(Version + " built on the " + BuildDate) kingpin.Parse() fmtlog.SetFlags(fmtlog.Lshortfile | fmtlog.LstdFlags) var srv *manners.GracefulServer var configurationRouter *mux.Router var configurationChan = make(chan types.ConfigMessage, 10) defer close(configurationChan) var configurationChanValidated = make(chan types.ConfigMessage, 10) defer close(configurationChanValidated) var sigs = make(chan os.Signal, 1) defer close(sigs) var stopChan = make(chan bool) defer close(stopChan) var providers = []provider.Provider{} signal.Notify(sigs, syscall.SIGINT, syscall.SIGTERM) var serverLock sync.Mutex // load global configuration globalConfiguration := LoadFileConfig(*globalConfigFile) loggerMiddleware := middlewares.NewLogger(globalConfiguration.AccessLogsFile) defer loggerMiddleware.Close() // logging level, err := log.ParseLevel(strings.ToLower(globalConfiguration.LogLevel)) if err != nil { log.Fatal("Error getting level", err) } log.SetLevel(level) if len(globalConfiguration.TraefikLogsFile) > 0 { fi, err := os.OpenFile(globalConfiguration.TraefikLogsFile, os.O_RDWR|os.O_CREATE|os.O_APPEND, 0666) defer fi.Close() if err != nil { log.Fatal("Error opening file", err) } else { log.SetOutput(fi) log.SetFormatter(&log.TextFormatter{DisableColors: true, FullTimestamp: true, DisableSorting: true}) } } else { log.SetFormatter(&log.TextFormatter{FullTimestamp: true, DisableSorting: true}) } log.Debugf("Global configuration loaded %+v", globalConfiguration) configurationRouter = LoadDefaultConfig(globalConfiguration) // listen new configurations from providers go func() { lastReceivedConfiguration := time.Unix(0, 0) lastConfigs := make(map[string]*types.ConfigMessage) for { configMsg := <-configurationChan log.Infof("Configuration receveived from provider %s: %#v", configMsg.ProviderName, configMsg.Configuration) lastConfigs[configMsg.ProviderName] = &configMsg if time.Now().After(lastReceivedConfiguration.Add(time.Duration(globalConfiguration.ProvidersThrottleDuration))) { log.Infof("Last %s config received more than %s, OK", configMsg.ProviderName, globalConfiguration.ProvidersThrottleDuration) // last config received more than n s ago configurationChanValidated <- configMsg } else { log.Infof("Last %s config received less than %s, waiting...", configMsg.ProviderName, globalConfiguration.ProvidersThrottleDuration) go func() { <-time.After(globalConfiguration.ProvidersThrottleDuration) if time.Now().After(lastReceivedConfiguration.Add(time.Duration(globalConfiguration.ProvidersThrottleDuration))) { log.Infof("Waited for %s config, OK", configMsg.ProviderName) configurationChanValidated <- *lastConfigs[configMsg.ProviderName] } }() } lastReceivedConfiguration = time.Now() } }() go func() { for { configMsg := <-configurationChanValidated if configMsg.Configuration == nil { log.Info("Skipping empty Configuration") } else if reflect.DeepEqual(currentConfigurations[configMsg.ProviderName], configMsg.Configuration) { log.Info("Skipping same configuration") } else { // Copy configurations to new map so we don't change current if LoadConfig fails newConfigurations := make(configs) for k, v := range currentConfigurations { newConfigurations[k] = v } newConfigurations[configMsg.ProviderName] = configMsg.Configuration newConfigurationRouter, err := LoadConfig(newConfigurations, globalConfiguration) if err == nil { serverLock.Lock() currentConfigurations = newConfigurations configurationRouter = newConfigurationRouter oldServer := srv newsrv, err := prepareServer(configurationRouter, globalConfiguration, oldServer, loggerMiddleware, metrics) if err != nil { log.Fatal("Error preparing server: ", err) } go startServer(newsrv, globalConfiguration) srv = newsrv time.Sleep(1 * time.Second) if oldServer != nil { log.Info("Stopping old server") oldServer.Close() } serverLock.Unlock() } else { log.Error("Error loading new configuration, aborted ", err) } } } }() // configure providers if globalConfiguration.Docker != nil { providers = append(providers, globalConfiguration.Docker) } if globalConfiguration.Marathon != nil { providers = append(providers, globalConfiguration.Marathon) } if globalConfiguration.File != nil { if len(globalConfiguration.File.Filename) == 0 { // no filename, setting to global config file globalConfiguration.File.Filename = *globalConfigFile } providers = append(providers, globalConfiguration.File) } if globalConfiguration.Web != nil { providers = append(providers, globalConfiguration.Web) } if globalConfiguration.Consul != nil { providers = append(providers, globalConfiguration.Consul) } if globalConfiguration.Etcd != nil { providers = append(providers, globalConfiguration.Etcd) } if globalConfiguration.Zookeeper != nil { providers = append(providers, globalConfiguration.Zookeeper) } if globalConfiguration.Boltdb != nil { providers = append(providers, globalConfiguration.Boltdb) } // start providers for _, provider := range providers { log.Infof("Starting provider %v %+v", reflect.TypeOf(provider), provider) currentProvider := provider go func() { err := currentProvider.Provide(configurationChan) if err != nil { log.Errorf("Error starting provider %s", err) } }() } go func() { sig := <-sigs log.Infof("I have to go... %+v", sig) log.Info("Stopping server") srv.Close() stopChan <- true }() //negroni.Use(middlewares.NewCircuitBreaker(oxyLogger)) //negroni.Use(middlewares.NewRoutes(configurationRouter)) var er error serverLock.Lock() srv, er = prepareServer(configurationRouter, globalConfiguration, nil, loggerMiddleware, metrics) if er != nil { log.Fatal("Error preparing server: ", er) } go startServer(srv, globalConfiguration) //TODO change that! time.Sleep(100 * time.Millisecond) serverLock.Unlock() <-stopChan log.Info("Shutting down") }
func main() { runtime.GOMAXPROCS(runtime.NumCPU()) kingpin.Parse() fmtlog.SetFlags(fmtlog.Lshortfile | fmtlog.LstdFlags) var srv *manners.GracefulServer var configurationRouter *mux.Router var configurationChan = make(chan configMessage, 10) defer close(configurationChan) var sigs = make(chan os.Signal, 1) defer close(sigs) var stopChan = make(chan bool) defer close(stopChan) var providers = []Provider{} signal.Notify(sigs, syscall.SIGINT, syscall.SIGTERM) // load global configuration globalConfiguration := LoadFileConfig(*globalConfigFile) loggerMiddleware := middlewares.NewLogger(globalConfiguration.AccessLogsFile) defer loggerMiddleware.Close() // logging level, err := log.ParseLevel(strings.ToLower(globalConfiguration.LogLevel)) if err != nil { log.Fatal("Error getting level", err) } log.SetLevel(level) if len(globalConfiguration.TraefikLogsFile) > 0 { fi, err := os.OpenFile(globalConfiguration.TraefikLogsFile, os.O_RDWR|os.O_CREATE|os.O_APPEND, 0666) defer fi.Close() if err != nil { log.Fatal("Error opening file", err) } else { log.SetOutput(fi) log.SetFormatter(&log.TextFormatter{DisableColors: true, FullTimestamp: true, DisableSorting: true}) } } else { log.SetFormatter(&log.TextFormatter{FullTimestamp: true, DisableSorting: true}) } configurationRouter = LoadDefaultConfig(globalConfiguration) // listen new configurations from providers go func() { for { configMsg := <-configurationChan log.Infof("Configuration receveived from provider %v: %+v", configMsg.providerName, configMsg.configuration) if configMsg.configuration == nil { log.Info("Skipping empty configuration") } else if reflect.DeepEqual(currentConfigurations[configMsg.providerName], configMsg.configuration) { log.Info("Skipping same configuration") } else { // Copy configurations to new map so we don't change current if LoadConfig fails newConfigurations := make(configs) for k, v := range currentConfigurations { newConfigurations[k] = v } newConfigurations[configMsg.providerName] = configMsg.configuration newConfigurationRouter, err := LoadConfig(newConfigurations, globalConfiguration) if err == nil { currentConfigurations = newConfigurations configurationRouter = newConfigurationRouter oldServer := srv newsrv := prepareServer(configurationRouter, globalConfiguration, oldServer, loggerMiddleware, metrics) go startServer(newsrv, globalConfiguration) srv = newsrv time.Sleep(2 * time.Second) if oldServer != nil { log.Info("Stopping old server") oldServer.Close() } } else { log.Error("Error loading new configuration, aborted ", err) } } } }() // configure providers if globalConfiguration.Docker != nil { providers = append(providers, globalConfiguration.Docker) } if globalConfiguration.Marathon != nil { providers = append(providers, globalConfiguration.Marathon) } if globalConfiguration.File != nil { if len(globalConfiguration.File.Filename) == 0 { // no filename, setting to global config file globalConfiguration.File.Filename = *globalConfigFile } providers = append(providers, globalConfiguration.File) } if globalConfiguration.Web != nil { providers = append(providers, globalConfiguration.Web) } if globalConfiguration.Consul != nil { providers = append(providers, globalConfiguration.Consul) } // start providers for _, provider := range providers { log.Infof("Starting provider %v %+v", reflect.TypeOf(provider), provider) currentProvider := provider go func() { currentProvider.Provide(configurationChan) }() } go func() { sig := <-sigs log.Infof("I have to go... %+v", sig) log.Info("Stopping server") srv.Close() stopChan <- true }() //negroni.Use(middlewares.NewCircuitBreaker(oxyLogger)) //negroni.Use(middlewares.NewRoutes(configurationRouter)) srv = prepareServer(configurationRouter, globalConfiguration, nil, loggerMiddleware, metrics) go startServer(srv, globalConfiguration) <-stopChan log.Info("Shutting down") }