Files
mattermost/config/memory.go
Jesse Hallam 285b646d67 MM-13893: introduce file store (#10243)
* config file store

Introduce an interface and concrete implementation for accessing the config.

This mostly maps 1:1 with the exiting usage in `App`, except for internalizing the watcher. A future change will likely eliminate `App.PersistConfig()` and make this implicit on `Set` or `Patch`

* experimental file test changes

* emoji: move file driver checks from api4 to app

It is no longer possible to app.UpdateConfig and provide an invalid configuration, making it hard to test this case. This check doesn't really belong in the api anyway, since it's a configuration validity check and not a permissions check. Either way, the check now occurs at the App level.

* api4: generate valid public link salts for test

* TestStartServerRateLimiterCriticalError: use mock store to test invalid config

* remove config_test.go

* remove needsSave, and have Load() save to the backing store as necessary

* restore README.md

* move ldap UserFilter check to model isValid checks

* remove databaseStore until ready

* remove unimplemented Patch

* simplify unlockOnce implementation

* revert forgetting to set s.Ldap

* config/file.go: rename ReadOnlyConfigurationError to ErrReadOnlyConfiguration

* config: export FileStore

* add TestFileStoreSave

* improved config/utils test coverage

* restore config/README.md copy

* tweaks

* file store: acquire a write lock on Save/Close to safely close watcher

* fix unmarshal_test.go
2019-02-12 10:19:01 -08:00

104 lines
2.5 KiB
Go

// Copyright (c) 2015-present Mattermost, Inc. All Rights Reserved.
// See License.txt for license information.
package config
import (
"bytes"
"encoding/json"
"io/ioutil"
"github.com/pkg/errors"
"github.com/mattermost/mattermost-server/model"
)
// memoryStore implements the Store interface. It is meant primarily for testing.
type memoryStore struct {
emitter
Config *model.Config
EnvironmentOverrides map[string]interface{}
allowEnvironmentOverrides bool
}
// NewMemoryStore creates a new memoryStore instance.
func NewMemoryStore(allowEnvironmentOverrides bool) (*memoryStore, error) {
defaultCfg := &model.Config{}
defaultCfg.SetDefaults()
ms := &memoryStore{
Config: defaultCfg,
allowEnvironmentOverrides: allowEnvironmentOverrides,
}
if err := ms.Load(); err != nil {
return nil, err
}
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
newCfg.SetDefaults()
ms.Config = newCfg
return oldCfg, nil
}
// serialize converts the given configuration into JSON bytes for persistence.
func (ms *memoryStore) serialize(cfg *model.Config) ([]byte, error) {
return json.MarshalIndent(cfg, "", " ")
}
// Load applies environment overrides to the current config as if a re-load had occurred.
func (ms *memoryStore) Load() (err error) {
var cfgBytes []byte
cfgBytes, err = ms.serialize(ms.Config)
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")
}
ms.Config = loadedCfg
ms.EnvironmentOverrides = environmentOverrides
return nil
}
// Save does nothing, as there is no backing store.
func (ms *memoryStore) Save() error {
return nil
}
// String returns a hard-coded description, as there is no backing store.
func (ms *memoryStore) String() string {
return "mock://"
}
// Close does nothing for a mock store.
func (ms *memoryStore) Close() error {
return nil
}