Files
nats-server/server/reload.go
2017-05-30 16:18:36 -05:00

100 lines
2.7 KiB
Go

package server
import (
"errors"
"fmt"
"reflect"
"strings"
)
// FlagSnapshot captures the server options as specified by CLI flags at
// startup. This should not be modified once the server has started.
var FlagSnapshot = &Options{}
// option is a hot-swappable configuration setting.
type option interface {
// Apply the server option.
Apply(server *Server)
}
// traceOption implements the option interface for the `trace` setting.
type traceOption struct {
newValue bool
}
// Apply the tracing change by reconfiguring the server's logger.
func (t *traceOption) Apply(server *Server) {
Noticef("Reloaded: trace = %v", t.newValue)
server.ConfigureLogger()
}
// Reload reads the current configuration file and applies any supported
// changes. This returns an error if the server was not started with a config
// file or an option which doesn't support hot-swapping was changed.
func (s *Server) Reload() error {
if s.configFile == "" {
return errors.New("Can only reload config when a file is provided using -c or --config")
}
newOpts, err := ProcessConfigFile(s.configFile)
if err != nil {
// TODO: Dump previous good config to a .bak file?
return fmt.Errorf("Config reload failed: %s", err)
}
// Apply flags over config file settings.
newOpts = MergeOptions(newOpts, FlagSnapshot)
processOptions(newOpts)
return s.reloadOptions(newOpts)
}
// reloadOptions reloads the server config with the provided options. If an
// option that doesn't support hot-swapping is changed, this returns an error.
func (s *Server) reloadOptions(newOpts *Options) error {
changed, err := s.diffOptions(newOpts)
if err != nil {
return err
}
s.setOpts(newOpts)
s.applyOptions(changed)
return nil
}
// diffOptions returns a slice containing options which have been changed. If
// an option that doesn't support hot-swapping is changed, this returns an
// error.
func (s *Server) diffOptions(newOpts *Options) ([]option, error) {
var (
oldConfig = reflect.ValueOf(s.opts).Elem()
newConfig = reflect.ValueOf(newOpts).Elem()
opts = []option{}
)
for i := 0; i < oldConfig.NumField(); i++ {
var (
field = oldConfig.Type().Field(i)
oldValue = oldConfig.Field(i).Interface()
newValue = newConfig.Field(i).Interface()
changed = !reflect.DeepEqual(oldValue, newValue)
)
if !changed {
continue
}
switch strings.ToLower(field.Name) {
case "trace":
opts = append(opts, &traceOption{newValue.(bool)})
default:
// Bail out if attempting to reload any unsupported options.
return nil, fmt.Errorf("Config reload not supported for %s", field.Name)
}
}
return opts, nil
}
func (s *Server) applyOptions(opts []option) {
for _, opt := range opts {
opt.Apply(s)
}
Noticef("Reloaded server configuration")
}