grafana/pkg/setting/provider.go
Joan López de la Franca Beltran c41b08bd59
Settings: Encapsulate settings within an extensible provider (#32219)
* Encapsulate settings with a provider with support for runtime reloads

* SettingsProvider: reload is controlled by the services

* naive impl of reload handlers for settings

* working naive detection on new changes

* Trigger settings reload from API endpoint

* validation step added

* validation of settings

* Fix linting errors

* Replace DB_Varchar by DB_NVarchar

* Reduce settings columns (section, key) lenghts

* wip db update logic

* Db Settings: separate updates and removals

* Fix: removes incorrectly added code

* Minor code improvements

* Runtime settings: moved oss -> ee

* Remove no longer used setting.Cfg SAML-related fields

* Rename file setting/settings.go => setting/provider.go

* Apply suggestions from code review

Co-authored-by: Agnès Toulet <35176601+AgnesToulet@users.noreply.github.com>

* Minor code improvements on OSS settings provider

* Fix some login API tests

* Correct some GoDoc comments

* Apply suggestions from code review

Co-authored-by: Agnès Toulet <35176601+AgnesToulet@users.noreply.github.com>

Co-authored-by: Leonard Gram <leo@xlson.com>
Co-authored-by: Agnès Toulet <35176601+AgnesToulet@users.noreply.github.com>
2021-04-28 11:26:58 +02:00

142 lines
3.4 KiB
Go

package setting
import (
"errors"
"strings"
"time"
"gopkg.in/ini.v1"
)
var (
ErrOperationNotPermitted = errors.New("operation not permitted")
)
type ValidationError struct {
Errors []error
}
func (v ValidationError) Error() string {
builder := strings.Builder{}
for i, e := range v.Errors {
builder.WriteString(e.Error())
if i != len(v.Errors)-1 {
builder.WriteString(", ")
}
}
return builder.String()
}
// Provider is a settings provider abstraction
// with thread-safety and runtime updates.
type Provider interface {
// Update
Update(updates SettingsBag, removals SettingsRemovals) error
// KeyValue returns a key-value abstraction
// for the given pair of section and key.
KeyValue(section, key string) KeyValue
// Section returns a settings section
// abstraction for the given section name.
Section(section string) Section
// RegisterReloadHandler registers a handler for validation and reload
// of configuration updates tied to a specific section
RegisterReloadHandler(section string, handler ReloadHandler)
}
// Section is a settings section copy
// with all of its pairs of keys-values.
type Section interface {
// KeyValue returns a key-value
// abstraction for the given key.
KeyValue(key string) KeyValue
}
// KeyValue represents a settings key-value
// for a given pair of section and key.
type KeyValue interface {
// Key returns pair's key.
Key() string
// Value returns pair's value.
Value() string
// MustString returns the value's string representation
// If empty, then it returns the given default.
MustString(defaultVal string) string
// MustBool returns the value's boolean representation
// Otherwise returns the given default.
MustBool(defaultVal bool) bool
// MustDuration returns the value's time.Duration
// representation. Otherwise returns the given default.
MustDuration(defaultVal time.Duration) time.Duration
}
// ReloadHandler defines the expected behaviour from a
// service that have support for configuration reloads.
type ReloadHandler interface {
// Reload handles reloading of configuration changes.
Reload(section Section) error
// Validate validates the configuration, if the validation
// fails the configuration will not be updated neither reloaded.
Validate(section Section) error
}
type SettingsBag map[string]map[string]string
type SettingsRemovals map[string][]string
type OSSImpl struct {
Cfg *Cfg `inject:""`
}
func (o OSSImpl) Init() error {
return nil
}
func (OSSImpl) Update(SettingsBag, SettingsRemovals) error {
return errors.New("oss settings provider do not have support for settings updates")
}
func (o *OSSImpl) KeyValue(section, key string) KeyValue {
return o.Section(section).KeyValue(key)
}
func (o *OSSImpl) Section(section string) Section {
return &sectionImpl{section: o.Cfg.Raw.Section(section)}
}
func (OSSImpl) RegisterReloadHandler(string, ReloadHandler) {}
type keyValImpl struct {
key *ini.Key
}
func (k *keyValImpl) Key() string {
return k.key.Name()
}
func (k *keyValImpl) Value() string {
return k.key.Value()
}
func (k *keyValImpl) MustString(defaultVal string) string {
return k.key.MustString(defaultVal)
}
func (k *keyValImpl) MustBool(defaultVal bool) bool {
return k.key.MustBool(defaultVal)
}
func (k *keyValImpl) MustDuration(defaultVal time.Duration) time.Duration {
return k.key.MustDuration(defaultVal)
}
type sectionImpl struct {
section *ini.Section
}
func (s *sectionImpl) KeyValue(key string) KeyValue {
return &keyValImpl{s.section.Key(key)}
}