v0.2.5: Reloading a badly formated configuration wont crash, so the old configuration will keep running.
This commit is contained in:
		
							
								
								
									
										60
									
								
								main.go
									
									
									
									
									
								
							
							
						
						
									
										60
									
								
								main.go
									
									
									
									
									
								
							@ -34,7 +34,7 @@ import (
 | 
			
		||||
)
 | 
			
		||||
 | 
			
		||||
const (
 | 
			
		||||
	gVersion = "0.2.4"
 | 
			
		||||
	gVersion = "0.2.5"
 | 
			
		||||
	// Default datasource timeout is 10 seconds
 | 
			
		||||
	gDefaultDSTimeout = 10
 | 
			
		||||
)
 | 
			
		||||
@ -329,7 +329,7 @@ func getGraph(name string) (Graph, error) {
 | 
			
		||||
	return Graph{}, fmt.Errorf("Graph not found: %s", name)
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
func initRoutes(r *gin.Engine) {
 | 
			
		||||
func initRoutes(r *gin.Engine, confFile string) {
 | 
			
		||||
	r.GET("/ping", func(c *gin.Context) {
 | 
			
		||||
		c.JSON(http.StatusOK, gin.H{
 | 
			
		||||
			"message": "pong",
 | 
			
		||||
@ -338,7 +338,10 @@ func initRoutes(r *gin.Engine) {
 | 
			
		||||
	
 | 
			
		||||
	// An endpoint to force read of configuration file
 | 
			
		||||
	r.POST("/reload", func(c *gin.Context) {
 | 
			
		||||
		reloadConfigFile()
 | 
			
		||||
		if err := reloadConfigFile(confFile); err != nil {
 | 
			
		||||
			c.JSON(http.StatusInternalServerError, gin.H{"error": err.Error()})
 | 
			
		||||
			return
 | 
			
		||||
		}
 | 
			
		||||
		c.JSON(http.StatusOK, gin.H{
 | 
			
		||||
			"message": "configuration successfully reloaded",
 | 
			
		||||
		})
 | 
			
		||||
@ -469,16 +472,32 @@ func newEdgeClone(src *Edge) *Edge {
 | 
			
		||||
	}
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
func reloadConfigFile() {
 | 
			
		||||
	// First reread config file
 | 
			
		||||
	if err := viper.ReadInConfig(); err != nil {
 | 
			
		||||
		if _, ok := err.(viper.ConfigFileNotFoundError); ok {
 | 
			
		||||
			log.Fatalf("config file not found")
 | 
			
		||||
			os.Exit(1)
 | 
			
		||||
		} else {
 | 
			
		||||
			log.Fatalf("unknown error looking for config file: %v", err)
 | 
			
		||||
			os.Exit(1)
 | 
			
		||||
// This function assume we already have a running configuration.
 | 
			
		||||
func reloadConfigFile(confFile string) error {
 | 
			
		||||
	oldConfigRestored := false
 | 
			
		||||
	// We need to keep this config, incase the new one is b0rken
 | 
			
		||||
	fname := fmt.Sprintf("/tmp/nodegopher.%d.yaml", os.Getpid())
 | 
			
		||||
	if err := viper.WriteConfigAs(fname); err != nil {
 | 
			
		||||
		log.Errorf("Unable to save current running config to %s, wont reload configuration.\n", fname)
 | 
			
		||||
		return fmt.Errorf("Unable to save current configuration, configuration not reloaded. See logs.")
 | 
			
		||||
	}
 | 
			
		||||
	defer os.Remove(fname)
 | 
			
		||||
 | 
			
		||||
	// Reread config file
 | 
			
		||||
	if oldErr := viper.ReadInConfig(); oldErr != nil {
 | 
			
		||||
		if _, ok := oldErr.(viper.ConfigFileNotFoundError); ok {
 | 
			
		||||
			log.Errorf("config file not found")
 | 
			
		||||
		} else {
 | 
			
		||||
			log.Errorf("unknown error looking for config file: %v", oldErr)
 | 
			
		||||
		}
 | 
			
		||||
		// Restore old configuration and notify.
 | 
			
		||||
		log.Debugf("Fallback on previous configuration.\n")
 | 
			
		||||
		viper.SetConfigFile(fname)
 | 
			
		||||
		if err := viper.ReadInConfig(); err != nil {
 | 
			
		||||
			log.Fatalf("Unable to restore configuration, and new is invalid. fix it now.\n")
 | 
			
		||||
		}
 | 
			
		||||
		viper.SetConfigFile(confFile)
 | 
			
		||||
		oldConfigRestored = true
 | 
			
		||||
	}
 | 
			
		||||
 | 
			
		||||
	switch viper.Get("language").(string) {
 | 
			
		||||
@ -503,6 +522,7 @@ func reloadConfigFile() {
 | 
			
		||||
	gCfgMutex.Lock()
 | 
			
		||||
	defer gCfgMutex.Unlock()
 | 
			
		||||
 | 
			
		||||
	// We need to keep this config, incase the new one is b0rken
 | 
			
		||||
	for _, g := range gGraphs {
 | 
			
		||||
		g.Nodes = nil
 | 
			
		||||
		g.Edges = nil
 | 
			
		||||
@ -538,8 +558,8 @@ func reloadConfigFile() {
 | 
			
		||||
	}
 | 
			
		||||
 | 
			
		||||
	if viper.Get("datasources") == nil {
 | 
			
		||||
		log.Printf("no datasources found, data will be static")
 | 
			
		||||
		return
 | 
			
		||||
		log.Warningf("no datasources found, data will be static")
 | 
			
		||||
		return nil
 | 
			
		||||
	}
 | 
			
		||||
	dss := viper.Get("datasources").([]interface{})
 | 
			
		||||
	for _, d := range dss {
 | 
			
		||||
@ -552,6 +572,10 @@ func reloadConfigFile() {
 | 
			
		||||
		}
 | 
			
		||||
		gDataSources = append(gDataSources, ds)
 | 
			
		||||
	}
 | 
			
		||||
	if oldConfigRestored {
 | 
			
		||||
		return fmt.Errorf("Unable to load new configuration, keeping old one. See logs.")
 | 
			
		||||
	}
 | 
			
		||||
	return nil
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
func main() {
 | 
			
		||||
@ -604,7 +628,7 @@ func main() {
 | 
			
		||||
	// FIXME: Watch config changes. Does not work on FreeBSD. TODO: Test with linux
 | 
			
		||||
	viper.OnConfigChange(func(e fsnotify.Event) {
 | 
			
		||||
		log.Printf("Config file changed, reloading data\n")
 | 
			
		||||
		reloadConfigFile()
 | 
			
		||||
		reloadConfigFile(confFile)
 | 
			
		||||
	})
 | 
			
		||||
 | 
			
		||||
	// Lets reload config on SIGHUP
 | 
			
		||||
@ -614,11 +638,11 @@ func main() {
 | 
			
		||||
		for {
 | 
			
		||||
			_ = <- sigs
 | 
			
		||||
			log.Infof("SIGHUP received, reloading configuration\n")
 | 
			
		||||
			reloadConfigFile()
 | 
			
		||||
			reloadConfigFile(confFile)
 | 
			
		||||
		}
 | 
			
		||||
	}()
 | 
			
		||||
 | 
			
		||||
	reloadConfigFile()
 | 
			
		||||
	reloadConfigFile(confFile)
 | 
			
		||||
 | 
			
		||||
	// Capture variable name. There should be only one variable. Space is tolerated before and after name.
 | 
			
		||||
	gDSVarCompRegex = regexp.MustCompile(`^\{\{(?:\ )?([a-zA-Z0-9\-_]+)(?:\ )?\}\}$`)
 | 
			
		||||
@ -629,6 +653,6 @@ func main() {
 | 
			
		||||
	log.Printf("Starting NodeGopher v.%s\n", gVersion)
 | 
			
		||||
 | 
			
		||||
	r := gin.Default()
 | 
			
		||||
	initRoutes(r)
 | 
			
		||||
	initRoutes(r, confFile)
 | 
			
		||||
	r.Run(listen)
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
		Reference in New Issue
	
	Block a user