mirror of
https://github.com/netbirdio/netbird.git
synced 2026-09-22 06:39:08 +02:00
[management,signal,proxy,relay,misc] Unify service configuration loading
Service entry points currently resolve defaults, files, environment variables, and flags differently, which makes precedence inconsistent and prevents some services from using config files. Introduce one Viper-backed loader and migrate Combined, Management, Relay, Signal, and Proxy while preserving compatibility aliases and Management template expansion.
This commit is contained in:
@@ -114,8 +114,8 @@ func withAdminConfig(cmd *cobra.Command, applyIDPDefaults bool, fn func(ctx cont
|
||||
}
|
||||
|
||||
func loadAdminMgmtConfig(ctx context.Context, applyIDPDefaults bool) (*nbconfig.Config, string, error) {
|
||||
config := &nbconfig.Config{}
|
||||
if _, err := util.ReadJsonWithEnvSub(nbconfig.MgmtConfigPath, config); err != nil {
|
||||
config, err := loadManagementConfig(nbconfig.MgmtConfigPath)
|
||||
if err != nil {
|
||||
return nil, "", err
|
||||
}
|
||||
|
||||
|
||||
@@ -0,0 +1,13 @@
|
||||
package cmd
|
||||
|
||||
import (
|
||||
nbconfig "github.com/netbirdio/netbird/management/internals/server/config"
|
||||
configloader "github.com/netbirdio/netbird/util/config"
|
||||
)
|
||||
|
||||
func loadManagementConfig(configPath string) (*nbconfig.Config, error) {
|
||||
return configloader.Load(configPath, &nbconfig.Config{Datadir: defaultMgmtDataDir}, configloader.Options{
|
||||
TagName: "json",
|
||||
Transform: configloader.ExpandEnvTemplate,
|
||||
})
|
||||
}
|
||||
@@ -0,0 +1,50 @@
|
||||
package cmd
|
||||
|
||||
import (
|
||||
"os"
|
||||
"path/filepath"
|
||||
"testing"
|
||||
"time"
|
||||
|
||||
"github.com/stretchr/testify/assert"
|
||||
"github.com/stretchr/testify/require"
|
||||
)
|
||||
|
||||
func TestLoadManagementConfigSources(t *testing.T) {
|
||||
t.Setenv("MANAGEMENT_DATA_DIR", "/template-data")
|
||||
t.Setenv("MANAGEMENT_ENCRYPTION_KEY", "template-key")
|
||||
t.Setenv("NB_DATADIR", "/environment-data")
|
||||
t.Setenv("NB_HTTPCONFIG_AUTHAUDIENCE", "environment-audience")
|
||||
configPath := filepath.Join(t.TempDir(), "management.json")
|
||||
require.NoError(t, os.WriteFile(configPath, []byte(`{
|
||||
"Datadir": "{{ .MANAGEMENT_DATA_DIR }}",
|
||||
"DataStoreEncryptionKey": "{{ .MANAGEMENT_ENCRYPTION_KEY }}",
|
||||
"HttpConfig": {
|
||||
"AuthAudience": "file-audience"
|
||||
},
|
||||
"TURNConfig": {
|
||||
"CredentialsTTL": "1h"
|
||||
}
|
||||
}`), 0o600))
|
||||
|
||||
cfg, err := loadManagementConfig(configPath)
|
||||
require.NoError(t, err)
|
||||
assert.Equal(t, "/environment-data", cfg.Datadir, "Bound environment values should override template values")
|
||||
assert.Equal(t, "template-key", cfg.DataStoreEncryptionKey, "Template environment values should be expanded")
|
||||
require.NotNil(t, cfg.HttpConfig, "Nested configuration should be decoded")
|
||||
assert.Equal(t, "environment-audience", cfg.HttpConfig.AuthAudience, "Bound environment values should override the file")
|
||||
require.NotNil(t, cfg.TURNConfig, "TURN configuration should be decoded")
|
||||
assert.Equal(t, time.Hour, cfg.TURNConfig.CredentialsTTL.Duration, "JSON duration types should be decoded")
|
||||
|
||||
datadirFlag := mgmtCmd.Flags().Lookup("datadir")
|
||||
oldDatadir := datadirFlag.Value.String()
|
||||
oldChanged := datadirFlag.Changed
|
||||
t.Cleanup(func() {
|
||||
require.NoError(t, datadirFlag.Value.Set(oldDatadir))
|
||||
datadirFlag.Changed = oldChanged
|
||||
})
|
||||
require.NoError(t, datadirFlag.Value.Set("/flag-data"))
|
||||
datadirFlag.Changed = true
|
||||
ApplyCommandLineOverrides(cfg, mgmtCmd.Flags())
|
||||
assert.Equal(t, "/flag-data", cfg.Datadir, "Flags should override environment values")
|
||||
}
|
||||
@@ -19,6 +19,7 @@ import (
|
||||
|
||||
log "github.com/sirupsen/logrus"
|
||||
"github.com/spf13/cobra"
|
||||
"github.com/spf13/pflag"
|
||||
|
||||
"github.com/netbirdio/netbird/management/server/types"
|
||||
|
||||
@@ -60,7 +61,7 @@ var (
|
||||
// detect whether user specified a port
|
||||
userPort := cmd.Flag("port").Changed
|
||||
|
||||
config, err = LoadMgmtConfig(ctx, nbconfig.MgmtConfigPath)
|
||||
config, err = LoadMgmtConfig(ctx, nbconfig.MgmtConfigPath, cmd.Flags())
|
||||
if err != nil {
|
||||
return fmt.Errorf("failed reading provided config file: %s: %v", nbconfig.MgmtConfigPath, err)
|
||||
}
|
||||
@@ -70,7 +71,7 @@ var (
|
||||
}
|
||||
|
||||
var tlsEnabled bool
|
||||
if mgmtLetsencryptDomain != "" || (config.HttpConfig.CertFile != "" && config.HttpConfig.CertKey != "") {
|
||||
if config.HttpConfig.LetsEncryptDomain != "" || (config.HttpConfig.CertFile != "" && config.HttpConfig.CertKey != "") {
|
||||
tlsEnabled = true
|
||||
}
|
||||
|
||||
@@ -171,15 +172,15 @@ var (
|
||||
}
|
||||
)
|
||||
|
||||
func LoadMgmtConfig(ctx context.Context, mgmtConfigPath string) (*nbconfig.Config, error) {
|
||||
loadedConfig := &nbconfig.Config{}
|
||||
if _, err := util.ReadJsonWithEnvSub(mgmtConfigPath, loadedConfig); err != nil {
|
||||
func LoadMgmtConfig(ctx context.Context, mgmtConfigPath string, flags *pflag.FlagSet) (*nbconfig.Config, error) {
|
||||
loadedConfig, err := loadManagementConfig(mgmtConfigPath)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
|
||||
ApplyCommandLineOverrides(loadedConfig)
|
||||
ApplyCommandLineOverrides(loadedConfig, flags)
|
||||
|
||||
err := grpc.ValidateSyncMessageVersion(loadedConfig.HighestSupportedSyncMessageVersion)
|
||||
err = grpc.ValidateSyncMessageVersion(loadedConfig.HighestSupportedSyncMessageVersion)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
@@ -211,14 +212,18 @@ func LoadMgmtConfig(ctx context.Context, mgmtConfigPath string) (*nbconfig.Confi
|
||||
}
|
||||
|
||||
// ApplyCommandLineOverrides applies command-line flag overrides to the config
|
||||
func ApplyCommandLineOverrides(cfg *nbconfig.Config) {
|
||||
if mgmtLetsencryptDomain != "" {
|
||||
func ApplyCommandLineOverrides(cfg *nbconfig.Config, flags *pflag.FlagSet) {
|
||||
hasCertOverride := flags.Changed("cert-key") && flags.Changed("cert-file")
|
||||
if (flags.Changed("letsencrypt-domain") || hasCertOverride) && cfg.HttpConfig == nil {
|
||||
cfg.HttpConfig = &nbconfig.HttpServerConfig{}
|
||||
}
|
||||
if flags.Changed("letsencrypt-domain") {
|
||||
cfg.HttpConfig.LetsEncryptDomain = mgmtLetsencryptDomain
|
||||
}
|
||||
if mgmtDataDir != "" {
|
||||
if flags.Changed("datadir") {
|
||||
cfg.Datadir = mgmtDataDir
|
||||
}
|
||||
if certKey != "" && certFile != "" {
|
||||
if hasCertOverride {
|
||||
cfg.HttpConfig.CertFile = certFile
|
||||
cfg.HttpConfig.CertKey = certKey
|
||||
}
|
||||
|
||||
@@ -36,7 +36,7 @@ func Test_LoadMgmtConfig(t *testing.T) {
|
||||
tmpFile, err := createConfig(exampleConfig)
|
||||
assert.NoError(t, err)
|
||||
|
||||
cfg, err := LoadMgmtConfig(context.Background(), tmpFile)
|
||||
cfg, err := LoadMgmtConfig(context.Background(), tmpFile, mgmtCmd.Flags())
|
||||
assert.NoError(t, err)
|
||||
assert.NotEmpty(t, cfg.Relay)
|
||||
assert.NotEmpty(t, cfg.Relay.Addresses)
|
||||
@@ -54,7 +54,7 @@ func Test_LoadMgmtConfig_Empty(t *testing.T) {
|
||||
}`)
|
||||
assert.NoError(t, err)
|
||||
|
||||
cfg, err := LoadMgmtConfig(context.Background(), tmpFile)
|
||||
cfg, err := LoadMgmtConfig(context.Background(), tmpFile, mgmtCmd.Flags())
|
||||
assert.NoError(t, err)
|
||||
assert.Nil(t, cfg.HighestSupportedSyncMessageVersion)
|
||||
assert.Nil(t, cfg.PerAccountHighestSupportedSyncMessageVersion)
|
||||
|
||||
Reference in New Issue
Block a user