MM-14143 config cleanup final (#10374)
* TestGetLicenseFileFromDisk: avoid using fileutils.FindConfigFile * config: abstract config-related file access, extend memory store * simplify config validate to avoid file knowledge * fix relative file tests * cluster: fix ConfigChanged event The old and new configurations were swapped when notifying the enterprise code of configuration changes, creating needless instability in propagating config updates across a cluster. * config/database: ignore duplicates * test cleanup * remove unnecessary Save() in test
Этот коммит содержится в:
коммит произвёл
GitHub
родитель
3716918c57
Коммит
1e462da2d4
134
config/memory.go
134
config/memory.go
@@ -5,7 +5,7 @@ package config
|
||||
|
||||
import (
|
||||
"bytes"
|
||||
"encoding/json"
|
||||
"fmt"
|
||||
"io/ioutil"
|
||||
|
||||
"github.com/pkg/errors"
|
||||
@@ -15,24 +15,50 @@ import (
|
||||
|
||||
// memoryStore implements the Store interface. It is meant primarily for testing.
|
||||
type memoryStore struct {
|
||||
emitter
|
||||
|
||||
Config *model.Config
|
||||
EnvironmentOverrides map[string]interface{}
|
||||
commonStore
|
||||
|
||||
allowEnvironmentOverrides bool
|
||||
validate bool
|
||||
files map[string][]byte
|
||||
savedConfig *model.Config
|
||||
}
|
||||
|
||||
// NewMemoryStore creates a new memoryStore instance.
|
||||
func NewMemoryStore(allowEnvironmentOverrides bool) (*memoryStore, error) {
|
||||
defaultCfg := &model.Config{}
|
||||
defaultCfg.SetDefaults()
|
||||
// MemoryStoreOptions makes configuration of the memory store explicit.
|
||||
type MemoryStoreOptions struct {
|
||||
IgnoreEnvironmentOverrides bool
|
||||
SkipValidation bool
|
||||
InitialConfig *model.Config
|
||||
InitialFiles map[string][]byte
|
||||
}
|
||||
|
||||
// NewMemoryStore creates a new memoryStore instance with default options.
|
||||
func NewMemoryStore() (*memoryStore, error) {
|
||||
return NewMemoryStoreWithOptions(&MemoryStoreOptions{})
|
||||
}
|
||||
|
||||
// NewMemoryStoreWithOptions creates a new memoryStore instance.
|
||||
func NewMemoryStoreWithOptions(options *MemoryStoreOptions) (*memoryStore, error) {
|
||||
savedConfig := options.InitialConfig
|
||||
if savedConfig == nil {
|
||||
savedConfig = &model.Config{}
|
||||
savedConfig.SetDefaults()
|
||||
}
|
||||
|
||||
initialFiles := options.InitialFiles
|
||||
if initialFiles == nil {
|
||||
initialFiles = make(map[string][]byte)
|
||||
}
|
||||
|
||||
ms := &memoryStore{
|
||||
Config: defaultCfg,
|
||||
allowEnvironmentOverrides: allowEnvironmentOverrides,
|
||||
allowEnvironmentOverrides: !options.IgnoreEnvironmentOverrides,
|
||||
validate: !options.SkipValidation,
|
||||
files: initialFiles,
|
||||
savedConfig: savedConfig,
|
||||
}
|
||||
|
||||
ms.commonStore.config = &model.Config{}
|
||||
ms.commonStore.config.SetDefaults()
|
||||
|
||||
if err := ms.Load(); err != nil {
|
||||
return nil, err
|
||||
}
|
||||
@@ -40,59 +66,89 @@ func NewMemoryStore(allowEnvironmentOverrides bool) (*memoryStore, error) {
|
||||
return ms, nil
|
||||
}
|
||||
|
||||
// Get fetches the current, cached configuration.
|
||||
func (ms *memoryStore) Get() *model.Config {
|
||||
return ms.Config
|
||||
}
|
||||
|
||||
// GetEnvironmentOverrides fetches the configuration fields overridden by environment variables.
|
||||
func (ms *memoryStore) GetEnvironmentOverrides() map[string]interface{} {
|
||||
return ms.EnvironmentOverrides
|
||||
}
|
||||
|
||||
// Set replaces the current configuration in its entirety.
|
||||
func (ms *memoryStore) Set(newCfg *model.Config) (*model.Config, error) {
|
||||
oldCfg := ms.Config
|
||||
validate := ms.commonStore.validate
|
||||
if !ms.validate {
|
||||
validate = nil
|
||||
}
|
||||
|
||||
newCfg.SetDefaults()
|
||||
ms.Config = newCfg
|
||||
|
||||
return oldCfg, nil
|
||||
return ms.commonStore.set(newCfg, validate, ms.persist)
|
||||
}
|
||||
|
||||
// serialize converts the given configuration into JSON bytes for persistence.
|
||||
func (ms *memoryStore) serialize(cfg *model.Config) ([]byte, error) {
|
||||
return json.MarshalIndent(cfg, "", " ")
|
||||
// persist copies the active config to the saved config.
|
||||
func (ms *memoryStore) persist(cfg *model.Config) error {
|
||||
ms.savedConfig = cfg.Clone()
|
||||
|
||||
return nil
|
||||
}
|
||||
|
||||
// Load applies environment overrides to the current config as if a re-load had occurred.
|
||||
// Load applies environment overrides to the default config as if a re-load had occurred.
|
||||
func (ms *memoryStore) Load() (err error) {
|
||||
var cfgBytes []byte
|
||||
cfgBytes, err = ms.serialize(ms.Config)
|
||||
cfgBytes, err = marshalConfig(ms.savedConfig)
|
||||
if err != nil {
|
||||
return errors.Wrap(err, "failed to serialize config")
|
||||
}
|
||||
|
||||
f := ioutil.NopCloser(bytes.NewReader(cfgBytes))
|
||||
|
||||
allowEnvironmentOverrides := true
|
||||
loadedCfg, environmentOverrides, err := unmarshalConfig(f, allowEnvironmentOverrides)
|
||||
if err != nil {
|
||||
return errors.Wrap(err, "failed to load config")
|
||||
validate := ms.commonStore.validate
|
||||
if !ms.validate {
|
||||
validate = nil
|
||||
}
|
||||
|
||||
ms.Config = loadedCfg
|
||||
ms.EnvironmentOverrides = environmentOverrides
|
||||
return ms.commonStore.load(f, false, validate, ms.persist)
|
||||
}
|
||||
|
||||
// GetFile fetches the contents of a previously persisted configuration file.
|
||||
func (ms *memoryStore) GetFile(name string) ([]byte, error) {
|
||||
ms.configLock.RLock()
|
||||
defer ms.configLock.RUnlock()
|
||||
|
||||
data, ok := ms.files[name]
|
||||
if !ok {
|
||||
return nil, fmt.Errorf("file %s not stored", name)
|
||||
}
|
||||
|
||||
return data, nil
|
||||
}
|
||||
|
||||
// SetFile sets or replaces the contents of a configuration file.
|
||||
func (ms *memoryStore) SetFile(name string, data []byte) error {
|
||||
ms.configLock.Lock()
|
||||
defer ms.configLock.Unlock()
|
||||
|
||||
ms.files[name] = data
|
||||
|
||||
return nil
|
||||
}
|
||||
|
||||
// HasFile returns true if the given file was previously persisted.
|
||||
func (ms *memoryStore) HasFile(name string) (bool, error) {
|
||||
ms.configLock.RLock()
|
||||
defer ms.configLock.RUnlock()
|
||||
|
||||
_, ok := ms.files[name]
|
||||
return ok, nil
|
||||
}
|
||||
|
||||
// RemoveFile removes a previously persisted configuration file.
|
||||
func (ms *memoryStore) RemoveFile(name string) error {
|
||||
ms.configLock.Lock()
|
||||
defer ms.configLock.Unlock()
|
||||
|
||||
delete(ms.files, name)
|
||||
|
||||
return nil
|
||||
}
|
||||
|
||||
// String returns a hard-coded description, as there is no backing store.
|
||||
func (ms *memoryStore) String() string {
|
||||
return "mock://"
|
||||
return "memory://"
|
||||
}
|
||||
|
||||
// Close does nothing for a mock store.
|
||||
// Close does nothing for a memory store.
|
||||
func (ms *memoryStore) Close() error {
|
||||
return nil
|
||||
}
|
||||
|
||||
Ссылка в новой задаче
Block a user