github.com/safing/portbase@v0.19.5/config/main.go (about) 1 package config 2 3 import ( 4 "encoding/json" 5 "errors" 6 "flag" 7 "fmt" 8 "io/fs" 9 "os" 10 "path/filepath" 11 "sort" 12 13 "github.com/safing/portbase/dataroot" 14 "github.com/safing/portbase/modules" 15 "github.com/safing/portbase/utils" 16 "github.com/safing/portbase/utils/debug" 17 ) 18 19 // ChangeEvent is the name of the config change event. 20 const ChangeEvent = "config change" 21 22 var ( 23 module *modules.Module 24 dataRoot *utils.DirStructure 25 26 exportConfig bool 27 ) 28 29 // SetDataRoot sets the data root from which the updates module derives its paths. 30 func SetDataRoot(root *utils.DirStructure) { 31 if dataRoot == nil { 32 dataRoot = root 33 } 34 } 35 36 func init() { 37 module = modules.Register("config", prep, start, nil, "database") 38 module.RegisterEvent(ChangeEvent, true) 39 40 flag.BoolVar(&exportConfig, "export-config-options", false, "export configuration registry and exit") 41 } 42 43 func prep() error { 44 SetDataRoot(dataroot.Root()) 45 if dataRoot == nil { 46 return errors.New("data root is not set") 47 } 48 49 if exportConfig { 50 modules.SetCmdLineOperation(exportConfigCmd) 51 } 52 53 return registerBasicOptions() 54 } 55 56 func start() error { 57 configFilePath = filepath.Join(dataRoot.Path, "config.json") 58 59 // Load log level from log package after it started. 60 err := loadLogLevel() 61 if err != nil { 62 return err 63 } 64 65 err = registerAsDatabase() 66 if err != nil && !errors.Is(err, fs.ErrNotExist) { 67 return err 68 } 69 70 err = loadConfig(false) 71 if err != nil && !errors.Is(err, fs.ErrNotExist) { 72 return fmt.Errorf("failed to load config file: %w", err) 73 } 74 return nil 75 } 76 77 func exportConfigCmd() error { 78 // Reset the metrics instance name option, as the default 79 // is set to the current hostname. 80 // Config key copied from metrics.CfgOptionInstanceKey. 81 option, err := GetOption("core/metrics/instance") 82 if err == nil { 83 option.DefaultValue = "" 84 } 85 86 data, err := json.MarshalIndent(ExportOptions(), "", " ") 87 if err != nil { 88 return err 89 } 90 91 _, err = os.Stdout.Write(data) 92 return err 93 } 94 95 // AddToDebugInfo adds all changed global config options to the given debug.Info. 96 func AddToDebugInfo(di *debug.Info) { 97 var lines []string 98 99 // Collect all changed settings. 100 _ = ForEachOption(func(opt *Option) error { 101 opt.Lock() 102 defer opt.Unlock() 103 104 if opt.ReleaseLevel <= getReleaseLevel() && opt.activeValue != nil { 105 if opt.Sensitive { 106 lines = append(lines, fmt.Sprintf("%s: [redacted]", opt.Key)) 107 } else { 108 lines = append(lines, fmt.Sprintf("%s: %v", opt.Key, opt.activeValue.getData(opt))) 109 } 110 } 111 112 return nil 113 }) 114 sort.Strings(lines) 115 116 // Add data as section. 117 di.AddSection( 118 fmt.Sprintf("Config: %d", len(lines)), 119 debug.UseCodeSection|debug.AddContentLineBreaks, 120 lines..., 121 ) 122 } 123 124 // GetActiveConfigValues returns a map with the active config values. 125 func GetActiveConfigValues() map[string]interface{} { 126 values := make(map[string]interface{}) 127 128 // Collect active values from options. 129 _ = ForEachOption(func(opt *Option) error { 130 opt.Lock() 131 defer opt.Unlock() 132 133 if opt.ReleaseLevel <= getReleaseLevel() && opt.activeValue != nil { 134 values[opt.Key] = opt.activeValue.getData(opt) 135 } 136 137 return nil 138 }) 139 140 return values 141 }