mirror of
https://codeberg.org/cunicu/cunicu.git
synced 2026-04-22 22:57:04 +08:00
0d3ec32c6f
Signed-off-by: Steffen Vogel <post@steffenvogel.de>
186 lines
3.9 KiB
Go
186 lines
3.9 KiB
Go
package config
|
|
|
|
import (
|
|
"fmt"
|
|
"net/url"
|
|
"os"
|
|
"path/filepath"
|
|
"strings"
|
|
|
|
"github.com/knadh/koanf"
|
|
"github.com/knadh/koanf/providers/env"
|
|
"github.com/knadh/koanf/providers/posflag"
|
|
"github.com/spf13/pflag"
|
|
)
|
|
|
|
var (
|
|
envPrefix = "CUNICU_"
|
|
|
|
// Map flags from the flags to to Koanf settings
|
|
flagMap = map[string]string{
|
|
// Feature flags
|
|
"discover-peers": "discover_peers",
|
|
"discover-endpoints": "discover_endpoints",
|
|
"sync-config": "sync_config",
|
|
"sync-hosts": "sync_hosts",
|
|
"sync-routes": "sync_routes",
|
|
|
|
"backend": "backends",
|
|
"watch-interval": "watch_interval",
|
|
|
|
// Socket
|
|
"rpc-socket": "rpc.socket",
|
|
"rpc-wait": "rpc.wait",
|
|
|
|
// WireGuard
|
|
"wg-userspace": "userspace",
|
|
|
|
// Endpoint discovery
|
|
"url": "ice.urls",
|
|
"username": "ice.username",
|
|
"password": "ice.password",
|
|
"ice-candidate-type": "ice.candidate_types",
|
|
"ice-network-type": "ice.network_types",
|
|
|
|
// Peer discovery
|
|
"community": "community",
|
|
"hostname": "hostname",
|
|
|
|
// Route synchronization
|
|
"routing-table": "routing_table",
|
|
}
|
|
)
|
|
|
|
type Watchable interface {
|
|
Watch(cb func(event interface{}, err error)) error
|
|
}
|
|
|
|
type Orderable interface {
|
|
Order() []string
|
|
}
|
|
|
|
type SubProvidable interface {
|
|
SubProviders() []koanf.Provider
|
|
}
|
|
|
|
type Versioned interface {
|
|
Version() any
|
|
}
|
|
|
|
type Provider struct {
|
|
koanf.Provider
|
|
|
|
Config *koanf.Koanf
|
|
}
|
|
|
|
// Load loads configuration settings from various sources
|
|
//
|
|
// Settings are loaded in the following order where the later overwrite the previous settings:
|
|
// - defaults
|
|
// - dns lookups
|
|
// - configuration files
|
|
// - environment variables
|
|
// - command line flags
|
|
func (c *Config) GetProviders() ([]koanf.Provider, error) {
|
|
ps := []koanf.Provider{
|
|
StructsProvider(&DefaultSettings, "koanf"),
|
|
WireGuardProvider(),
|
|
}
|
|
|
|
// Load settings from DNS lookups
|
|
for _, domain := range c.Domains {
|
|
p := LookupProvider(domain)
|
|
ps = append(ps, p)
|
|
}
|
|
|
|
// Search for config files
|
|
if len(c.Files) == 0 {
|
|
searchPath := []string{"/etc", "/etc/cunicu"}
|
|
|
|
if cwd, err := os.Getwd(); err != nil {
|
|
return nil, fmt.Errorf("failed to get working directory")
|
|
} else {
|
|
searchPath = append(searchPath, cwd)
|
|
}
|
|
|
|
if cfgDir := os.Getenv("CUNICU_CONFIG_DIR"); cfgDir != "" {
|
|
searchPath = append(searchPath, cfgDir)
|
|
}
|
|
|
|
for _, path := range searchPath {
|
|
fn := filepath.Join(path, "cunicu.yaml")
|
|
if fi, err := os.Stat(fn); err == nil && !fi.IsDir() {
|
|
c.Files = append(c.Files, fn)
|
|
}
|
|
}
|
|
}
|
|
|
|
// Add config files providers
|
|
for _, f := range c.Files {
|
|
u, err := url.Parse(f)
|
|
if err != nil {
|
|
return nil, fmt.Errorf("ignoring config file with invalid name: %w", err)
|
|
}
|
|
|
|
var p koanf.Provider
|
|
switch u.Scheme {
|
|
case "http", "https":
|
|
p = RemoteFileProvider(u)
|
|
case "":
|
|
p = LocalFileProvider(u)
|
|
default:
|
|
return nil, fmt.Errorf("unsupported scheme '%s' for config file", u.Scheme)
|
|
}
|
|
|
|
ps = append(ps, p)
|
|
}
|
|
|
|
// Add a runtime configuration file if it exists
|
|
if fi, err := os.Stat(RuntimeConfigFile); err == nil && !fi.IsDir() {
|
|
ps = append(ps,
|
|
LocalFileProvider(&url.URL{
|
|
Path: RuntimeConfigFile,
|
|
}),
|
|
)
|
|
}
|
|
|
|
ps = append(ps,
|
|
c.EnvironmentProvider(),
|
|
c.FlagProvider(),
|
|
)
|
|
|
|
return ps, nil
|
|
}
|
|
|
|
func (c *Config) EnvironmentProvider() koanf.Provider {
|
|
// Load environment variables
|
|
envKeyMap := map[string]string{}
|
|
for _, k := range c.Meta.Keys() {
|
|
m := strings.ToUpper(k)
|
|
e := envPrefix + strings.ReplaceAll(m, ".", "_")
|
|
envKeyMap[e] = k
|
|
}
|
|
|
|
return env.ProviderWithValue(envPrefix, ".", func(e, v string) (string, any) {
|
|
k := envKeyMap[e]
|
|
|
|
if p := strings.Split(v, ","); len(p) > 1 {
|
|
return k, p
|
|
}
|
|
|
|
return k, v
|
|
|
|
})
|
|
}
|
|
|
|
func (c *Config) FlagProvider() koanf.Provider {
|
|
return posflag.ProviderWithFlag(c.flags, ".", nil, func(f *pflag.Flag) (string, any) {
|
|
setting, ok := flagMap[f.Name]
|
|
if !ok {
|
|
return "", nil
|
|
}
|
|
|
|
return setting, posflag.FlagVal(c.flags, f)
|
|
})
|
|
}
|