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  }