mirror of
https://github.com/speatzle/nfsense.git
synced 2025-09-13 15:19:08 +00:00
Implement Config Manager
This commit is contained in:
parent
f6bcffd8df
commit
f4cdd809cd
9 changed files with 219 additions and 0 deletions
41
internal/config/apply.go
Normal file
41
internal/config/apply.go
Normal file
|
@ -0,0 +1,41 @@
|
|||
package config
|
||||
|
||||
import (
|
||||
"fmt"
|
||||
|
||||
"golang.org/x/exp/slog"
|
||||
"nfsense.net/nfsense/internal/definitions"
|
||||
)
|
||||
|
||||
// ApplyPendingChanges Takes all pending Changes and Tries to Apply them using the Registered Apply Functions.
|
||||
// In Case of error it Attempts to Revert to the Current Config
|
||||
func (m *ConfigManager) ApplyPendingChanges() error {
|
||||
slog.Info("Applying Pending Changes...")
|
||||
for _, fn := range m.applyFunctions {
|
||||
err := fn(*m.pendingConfig)
|
||||
if err != nil {
|
||||
slog.Error("Applying Pending Changes", err)
|
||||
err2 := revertToCurrent(m)
|
||||
if err2 != nil {
|
||||
slog.Error("Reverting Error", err2)
|
||||
return fmt.Errorf("Apply Error %w; Reverting Error %w", err, err2)
|
||||
}
|
||||
return err
|
||||
}
|
||||
}
|
||||
return nil
|
||||
}
|
||||
|
||||
func revertToCurrent(m *ConfigManager) error {
|
||||
for _, fn := range m.applyFunctions {
|
||||
err := fn(*m.currentConfig)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
}
|
||||
return nil
|
||||
}
|
||||
|
||||
func (m *ConfigManager) RegisterApplyFunction(fn func(definitions.Config) error) {
|
||||
m.applyFunctions = append(m.applyFunctions, fn)
|
||||
}
|
11
internal/config/diff.go
Normal file
11
internal/config/diff.go
Normal file
|
@ -0,0 +1,11 @@
|
|||
package config
|
||||
|
||||
import "github.com/r3labs/diff/v3"
|
||||
|
||||
func (m *ConfigManager) AreChangesPending() bool {
|
||||
return diff.Changed(m.currentConfig, m.pendingConfig)
|
||||
}
|
||||
|
||||
func (m *ConfigManager) GetPendingChangelog() (diff.Changelog, error) {
|
||||
return diff.Diff(m.currentConfig, m.pendingConfig)
|
||||
}
|
6
internal/config/discard.go
Normal file
6
internal/config/discard.go
Normal file
|
@ -0,0 +1,6 @@
|
|||
package config
|
||||
|
||||
func (m *ConfigManager) DiscardPendingConfig() error {
|
||||
m.pendingConfig = m.currentConfig.Clone()
|
||||
return nil
|
||||
}
|
11
internal/config/get.go
Normal file
11
internal/config/get.go
Normal file
|
@ -0,0 +1,11 @@
|
|||
package config
|
||||
|
||||
import "nfsense.net/nfsense/internal/definitions"
|
||||
|
||||
func (m *ConfigManager) GetCurrentConfig() definitions.Config {
|
||||
return *m.currentConfig.Clone()
|
||||
}
|
||||
|
||||
func (m *ConfigManager) GetPendingConfig() definitions.Config {
|
||||
return *m.pendingConfig.Clone()
|
||||
}
|
57
internal/config/load.go
Normal file
57
internal/config/load.go
Normal file
|
@ -0,0 +1,57 @@
|
|||
package config
|
||||
|
||||
import (
|
||||
"encoding/json"
|
||||
"fmt"
|
||||
"os"
|
||||
|
||||
"nfsense.net/nfsense/internal/definitions"
|
||||
)
|
||||
|
||||
func (m *ConfigManager) LoadCurrentConfigFromDisk() error {
|
||||
var config definitions.Config
|
||||
configFile, err := os.Open(m.currentConfigFilePath)
|
||||
if err != nil {
|
||||
return fmt.Errorf("opening Config File %w", err)
|
||||
}
|
||||
defer configFile.Close()
|
||||
|
||||
jsonParser := json.NewDecoder(configFile)
|
||||
jsonParser.DisallowUnknownFields()
|
||||
err = jsonParser.Decode(&config)
|
||||
if err != nil {
|
||||
return fmt.Errorf("decoding Config File %w", err)
|
||||
}
|
||||
|
||||
err = definitions.ValidateConfig(&config)
|
||||
if err != nil {
|
||||
return fmt.Errorf("validating Config: %w", err)
|
||||
}
|
||||
|
||||
m.currentConfig = &config
|
||||
return nil
|
||||
}
|
||||
|
||||
func (m *ConfigManager) LoadPendingConfigFromDisk() error {
|
||||
var config definitions.Config
|
||||
configFile, err := os.Open(m.pendingConfigFilePath)
|
||||
if err != nil {
|
||||
return fmt.Errorf("opening Config File %w", err)
|
||||
}
|
||||
defer configFile.Close()
|
||||
|
||||
jsonParser := json.NewDecoder(configFile)
|
||||
jsonParser.DisallowUnknownFields()
|
||||
err = jsonParser.Decode(&config)
|
||||
if err != nil {
|
||||
return fmt.Errorf("decoding Config File %w", err)
|
||||
}
|
||||
|
||||
err = definitions.ValidateConfig(&config)
|
||||
if err != nil {
|
||||
return fmt.Errorf("validating Config: %w", err)
|
||||
}
|
||||
|
||||
m.pendingConfig = &config
|
||||
return nil
|
||||
}
|
29
internal/config/manager.go
Normal file
29
internal/config/manager.go
Normal file
|
@ -0,0 +1,29 @@
|
|||
package config
|
||||
|
||||
import (
|
||||
"sync"
|
||||
|
||||
"nfsense.net/nfsense/internal/definitions"
|
||||
)
|
||||
|
||||
type ConfigManager struct {
|
||||
currentConfigFilePath string
|
||||
pendingConfigFilePath string
|
||||
|
||||
currentConfig *definitions.Config
|
||||
pendingConfig *definitions.Config
|
||||
|
||||
transactionMutex sync.Mutex
|
||||
|
||||
applyFunctions []func(definitions.Config) error
|
||||
}
|
||||
|
||||
func CreateConfigManager() *ConfigManager {
|
||||
manager := ConfigManager{
|
||||
currentConfigFilePath: "config.json",
|
||||
pendingConfigFilePath: "pending.json",
|
||||
currentConfig: &definitions.Config{},
|
||||
pendingConfig: &definitions.Config{},
|
||||
}
|
||||
return &manager
|
||||
}
|
55
internal/config/transaction.go
Normal file
55
internal/config/transaction.go
Normal file
|
@ -0,0 +1,55 @@
|
|||
package config
|
||||
|
||||
import (
|
||||
"fmt"
|
||||
"sync"
|
||||
|
||||
"nfsense.net/nfsense/internal/definitions"
|
||||
)
|
||||
|
||||
type ConfigTransaction struct {
|
||||
finished bool
|
||||
mutex sync.Mutex
|
||||
configManager *ConfigManager
|
||||
changes *definitions.Config
|
||||
}
|
||||
|
||||
func (m *ConfigManager) StartTransaction() (*ConfigTransaction, *definitions.Config) {
|
||||
m.transactionMutex.Lock()
|
||||
confCopy := m.pendingConfig.Clone()
|
||||
return &ConfigTransaction{
|
||||
configManager: m,
|
||||
changes: confCopy,
|
||||
}, confCopy
|
||||
}
|
||||
|
||||
func (t *ConfigTransaction) Commit() error {
|
||||
t.mutex.Lock()
|
||||
defer t.mutex.Unlock()
|
||||
|
||||
if t.finished {
|
||||
return fmt.Errorf("transaction already finished")
|
||||
}
|
||||
|
||||
t.finished = true
|
||||
defer t.configManager.transactionMutex.Unlock()
|
||||
|
||||
err := definitions.ValidateConfig(t.changes)
|
||||
if err != nil {
|
||||
return fmt.Errorf("validating Config before Apply: %w", err)
|
||||
}
|
||||
|
||||
t.configManager.pendingConfig = t.changes.Clone()
|
||||
|
||||
return nil
|
||||
}
|
||||
|
||||
func (t *ConfigTransaction) Discard() {
|
||||
t.mutex.Lock()
|
||||
defer t.mutex.Unlock()
|
||||
|
||||
if !t.finished {
|
||||
t.finished = true
|
||||
t.configManager.transactionMutex.Unlock()
|
||||
}
|
||||
}
|
Loading…
Add table
Add a link
Reference in a new issue