mirror of
https://github.com/safing/portbase
synced 2025-09-01 01:59:48 +00:00
Improve config import and export utils
This commit is contained in:
parent
01b03aa936
commit
4451b6985c
7 changed files with 109 additions and 45 deletions
|
@ -482,7 +482,6 @@ func (e *Endpoint) ServeHTTP(w http.ResponseWriter, r *http.Request) {
|
||||||
|
|
||||||
// Check for handler error.
|
// Check for handler error.
|
||||||
if err != nil {
|
if err != nil {
|
||||||
// if statusProvider, ok := err.(HTTPStatusProvider); ok {
|
|
||||||
var statusProvider HTTPStatusProvider
|
var statusProvider HTTPStatusProvider
|
||||||
if errors.As(err, &statusProvider) {
|
if errors.As(err, &statusProvider) {
|
||||||
http.Error(w, err.Error(), statusProvider.HTTPStatus())
|
http.Error(w, err.Error(), statusProvider.HTTPStatus())
|
||||||
|
|
|
@ -14,7 +14,7 @@ func parseAndReplaceConfig(jsonData string) error {
|
||||||
return err
|
return err
|
||||||
}
|
}
|
||||||
|
|
||||||
validationErrors := replaceConfig(m)
|
validationErrors, _ := ReplaceConfig(m)
|
||||||
if len(validationErrors) > 0 {
|
if len(validationErrors) > 0 {
|
||||||
return fmt.Errorf("%d errors, first: %w", len(validationErrors), validationErrors[0])
|
return fmt.Errorf("%d errors, first: %w", len(validationErrors), validationErrors[0])
|
||||||
}
|
}
|
||||||
|
@ -27,7 +27,7 @@ func parseAndReplaceDefaultConfig(jsonData string) error {
|
||||||
return err
|
return err
|
||||||
}
|
}
|
||||||
|
|
||||||
validationErrors := replaceDefaultConfig(m)
|
validationErrors, _ := ReplaceDefaultConfig(m)
|
||||||
if len(validationErrors) > 0 {
|
if len(validationErrors) > 0 {
|
||||||
return fmt.Errorf("%d errors, first: %w", len(validationErrors), validationErrors[0])
|
return fmt.Errorf("%d errors, first: %w", len(validationErrors), validationErrors[0])
|
||||||
}
|
}
|
||||||
|
|
|
@ -69,7 +69,7 @@ func start() error {
|
||||||
|
|
||||||
err = loadConfig(false)
|
err = loadConfig(false)
|
||||||
if err != nil && !errors.Is(err, fs.ErrNotExist) {
|
if err != nil && !errors.Is(err, fs.ErrNotExist) {
|
||||||
return err
|
return fmt.Errorf("failed to load config file: %w", err)
|
||||||
}
|
}
|
||||||
return nil
|
return nil
|
||||||
}
|
}
|
||||||
|
|
|
@ -325,6 +325,29 @@ func (option *Option) IsSetByUser() bool {
|
||||||
return option.activeValue != nil
|
return option.activeValue != nil
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// UserValue returns the value set by the user or nil if the value has not
|
||||||
|
// been changed from the default.
|
||||||
|
func (option *Option) UserValue() any {
|
||||||
|
option.Lock()
|
||||||
|
defer option.Unlock()
|
||||||
|
|
||||||
|
if option.activeValue == nil {
|
||||||
|
return nil
|
||||||
|
}
|
||||||
|
return option.activeValue.getData(option)
|
||||||
|
}
|
||||||
|
|
||||||
|
// ValidateValue checks if the given value is valid for the option.
|
||||||
|
func (option *Option) ValidateValue(value any) error {
|
||||||
|
option.Lock()
|
||||||
|
defer option.Unlock()
|
||||||
|
|
||||||
|
if _, err := validateValue(option, value); err != nil {
|
||||||
|
return err
|
||||||
|
}
|
||||||
|
return nil
|
||||||
|
}
|
||||||
|
|
||||||
// Export expors an option to a Record.
|
// Export expors an option to a Record.
|
||||||
func (option *Option) Export() (record.Record, error) {
|
func (option *Option) Export() (record.Record, error) {
|
||||||
option.Lock()
|
option.Lock()
|
||||||
|
|
|
@ -45,7 +45,7 @@ func loadConfig(requireValidConfig bool) error {
|
||||||
return err
|
return err
|
||||||
}
|
}
|
||||||
|
|
||||||
validationErrors := replaceConfig(newValues)
|
validationErrors, _ := ReplaceConfig(newValues)
|
||||||
if requireValidConfig && len(validationErrors) > 0 {
|
if requireValidConfig && len(validationErrors) > 0 {
|
||||||
return fmt.Errorf("encountered %d validation errors during config loading", len(validationErrors))
|
return fmt.Errorf("encountered %d validation errors during config loading", len(validationErrors))
|
||||||
}
|
}
|
||||||
|
|
120
config/set.go
120
config/set.go
|
@ -37,70 +37,112 @@ func signalChanges() {
|
||||||
module.TriggerEvent(ChangeEvent, nil)
|
module.TriggerEvent(ChangeEvent, nil)
|
||||||
}
|
}
|
||||||
|
|
||||||
// replaceConfig sets the (prioritized) user defined config.
|
// ValidateConfig validates the given configuration and returns all validation
|
||||||
func replaceConfig(newValues map[string]interface{}) []*ValidationError {
|
// errors as well as whether the given configuration contains unknown keys.
|
||||||
var validationErrors []*ValidationError
|
func ValidateConfig(newValues map[string]interface{}) (validationErrors []*ValidationError, requiresRestart bool, containsUnknown bool) {
|
||||||
|
|
||||||
// RLock the options because we are not adding or removing
|
// RLock the options because we are not adding or removing
|
||||||
// options from the registration but rather only update the
|
// options from the registration but rather only checking the
|
||||||
// options value which is guarded by the option's lock itself
|
// options value which is guarded by the option's lock itself.
|
||||||
optionsLock.RLock()
|
optionsLock.RLock()
|
||||||
defer optionsLock.RUnlock()
|
defer optionsLock.RUnlock()
|
||||||
|
|
||||||
|
var checked int
|
||||||
for key, option := range options {
|
for key, option := range options {
|
||||||
newValue, ok := newValues[key]
|
newValue, ok := newValues[key]
|
||||||
|
|
||||||
option.Lock()
|
|
||||||
option.activeValue = nil
|
|
||||||
|
|
||||||
if ok {
|
if ok {
|
||||||
valueCache, err := validateValue(option, newValue)
|
checked++
|
||||||
if err == nil {
|
|
||||||
option.activeValue = valueCache
|
|
||||||
} else {
|
|
||||||
validationErrors = append(validationErrors, err)
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
handleOptionUpdate(option, true)
|
func() {
|
||||||
option.Unlock()
|
option.Lock()
|
||||||
|
defer option.Unlock()
|
||||||
|
|
||||||
|
_, err := validateValue(option, newValue)
|
||||||
|
if err != nil {
|
||||||
|
validationErrors = append(validationErrors, err)
|
||||||
|
}
|
||||||
|
|
||||||
|
if option.RequiresRestart {
|
||||||
|
requiresRestart = true
|
||||||
|
}
|
||||||
|
}()
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
signalChanges()
|
return validationErrors, requiresRestart, checked < len(newValues)
|
||||||
|
|
||||||
return validationErrors
|
|
||||||
}
|
}
|
||||||
|
|
||||||
// replaceDefaultConfig sets the (fallback) default config.
|
// ReplaceConfig sets the (prioritized) user defined config.
|
||||||
func replaceDefaultConfig(newValues map[string]interface{}) []*ValidationError {
|
func ReplaceConfig(newValues map[string]interface{}) (validationErrors []*ValidationError, requiresRestart bool) {
|
||||||
var validationErrors []*ValidationError
|
|
||||||
|
|
||||||
// RLock the options because we are not adding or removing
|
// RLock the options because we are not adding or removing
|
||||||
// options from the registration but rather only update the
|
// options from the registration but rather only update the
|
||||||
// options value which is guarded by the option's lock itself
|
// options value which is guarded by the option's lock itself.
|
||||||
optionsLock.RLock()
|
optionsLock.RLock()
|
||||||
defer optionsLock.RUnlock()
|
defer optionsLock.RUnlock()
|
||||||
|
|
||||||
for key, option := range options {
|
for key, option := range options {
|
||||||
newValue, ok := newValues[key]
|
newValue, ok := newValues[key]
|
||||||
|
|
||||||
option.Lock()
|
func() {
|
||||||
option.activeDefaultValue = nil
|
option.Lock()
|
||||||
if ok {
|
defer option.Unlock()
|
||||||
valueCache, err := validateValue(option, newValue)
|
|
||||||
if err == nil {
|
option.activeValue = nil
|
||||||
option.activeDefaultValue = valueCache
|
if ok {
|
||||||
} else {
|
valueCache, err := validateValue(option, newValue)
|
||||||
validationErrors = append(validationErrors, err)
|
if err == nil {
|
||||||
|
option.activeValue = valueCache
|
||||||
|
} else {
|
||||||
|
validationErrors = append(validationErrors, err)
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
handleOptionUpdate(option, true)
|
||||||
handleOptionUpdate(option, true)
|
|
||||||
option.Unlock()
|
if option.RequiresRestart {
|
||||||
|
requiresRestart = true
|
||||||
|
}
|
||||||
|
}()
|
||||||
}
|
}
|
||||||
|
|
||||||
signalChanges()
|
signalChanges()
|
||||||
|
|
||||||
return validationErrors
|
return validationErrors, requiresRestart
|
||||||
|
}
|
||||||
|
|
||||||
|
// ReplaceDefaultConfig sets the (fallback) default config.
|
||||||
|
func ReplaceDefaultConfig(newValues map[string]interface{}) (validationErrors []*ValidationError, requiresRestart bool) {
|
||||||
|
// RLock the options because we are not adding or removing
|
||||||
|
// options from the registration but rather only update the
|
||||||
|
// options value which is guarded by the option's lock itself.
|
||||||
|
optionsLock.RLock()
|
||||||
|
defer optionsLock.RUnlock()
|
||||||
|
|
||||||
|
for key, option := range options {
|
||||||
|
newValue, ok := newValues[key]
|
||||||
|
|
||||||
|
func() {
|
||||||
|
option.Lock()
|
||||||
|
defer option.Unlock()
|
||||||
|
|
||||||
|
option.activeDefaultValue = nil
|
||||||
|
if ok {
|
||||||
|
valueCache, err := validateValue(option, newValue)
|
||||||
|
if err == nil {
|
||||||
|
option.activeDefaultValue = valueCache
|
||||||
|
} else {
|
||||||
|
validationErrors = append(validationErrors, err)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
handleOptionUpdate(option, true)
|
||||||
|
|
||||||
|
if option.RequiresRestart {
|
||||||
|
requiresRestart = true
|
||||||
|
}
|
||||||
|
}()
|
||||||
|
}
|
||||||
|
|
||||||
|
signalChanges()
|
||||||
|
|
||||||
|
return validationErrors, requiresRestart
|
||||||
}
|
}
|
||||||
|
|
||||||
// SetConfigOption sets a single value in the (prioritized) user defined config.
|
// SetConfigOption sets a single value in the (prioritized) user defined config.
|
||||||
|
|
|
@ -24,7 +24,7 @@ func TestLayersGetters(t *testing.T) { //nolint:paralleltest
|
||||||
t.Fatal(err)
|
t.Fatal(err)
|
||||||
}
|
}
|
||||||
|
|
||||||
validationErrors := replaceConfig(mapData)
|
validationErrors, _ := ReplaceConfig(mapData)
|
||||||
if len(validationErrors) > 0 {
|
if len(validationErrors) > 0 {
|
||||||
t.Fatalf("%d errors, first: %s", len(validationErrors), validationErrors[0].Error())
|
t.Fatalf("%d errors, first: %s", len(validationErrors), validationErrors[0].Error())
|
||||||
}
|
}
|
||||||
|
|
Loading…
Add table
Reference in a new issue