[TrueCloudLab#21] Support multiple configs

Signed-off-by: Denis Kirillov <d.kirillov@yadro.com>
This commit is contained in:
Denis Kirillov 2023-02-03 13:00:18 +03:00 committed by Alex Vanin
parent b35f146cec
commit 1ce8b8a30d
6 changed files with 101 additions and 19 deletions

View file

@ -472,11 +472,11 @@ func shutdownContext() (context.Context, context.CancelFunc) {
func (a *App) configReload() { func (a *App) configReload() {
a.log.Info("SIGHUP config reload started") a.log.Info("SIGHUP config reload started")
if !a.cfg.IsSet(cmdConfig) { if !a.cfg.IsSet(cmdConfig) && !a.cfg.IsSet(cmdConfigDir) {
a.log.Warn("failed to reload config because it's missed") a.log.Warn("failed to reload config because it's missed")
return return
} }
if err := readConfig(a.cfg); err != nil { if err := readInConfig(a.cfg); err != nil {
a.log.Warn("failed to reload config", zap.Error(err)) a.log.Warn("failed to reload config", zap.Error(err))
return return
} }

View file

@ -3,6 +3,7 @@ package main
import ( import (
"fmt" "fmt"
"os" "os"
"path"
"runtime" "runtime"
"sort" "sort"
"strconv" "strconv"
@ -116,6 +117,7 @@ const ( // Settings.
cmdHelp = "help" cmdHelp = "help"
cmdVersion = "version" cmdVersion = "version"
cmdConfig = "config" cmdConfig = "config"
cmdConfigDir = "config-dir"
cmdPProf = "pprof" cmdPProf = "pprof"
cmdMetrics = "metrics" cmdMetrics = "metrics"
@ -214,7 +216,8 @@ func newSettings() *viper.Viper {
flags.StringP(cmdWallet, "w", "", `path to the wallet`) flags.StringP(cmdWallet, "w", "", `path to the wallet`)
flags.String(cmdAddress, "", `address of wallet account`) flags.String(cmdAddress, "", `address of wallet account`)
flags.String(cmdConfig, "", "config path") flags.StringArray(cmdConfig, nil, "config paths")
flags.String(cmdConfigDir, "", "config dir path")
flags.Duration(cfgHealthcheckTimeout, defaultHealthcheckTimeout, "set timeout to check node health during rebalance") flags.Duration(cfgHealthcheckTimeout, defaultHealthcheckTimeout, "set timeout to check node health during rebalance")
flags.Duration(cfgConnectTimeout, defaultConnectTimeout, "set timeout to connect to FrostFS nodes") flags.Duration(cfgConnectTimeout, defaultConnectTimeout, "set timeout to connect to FrostFS nodes")
@ -313,11 +316,9 @@ func newSettings() *viper.Viper {
os.Exit(0) os.Exit(0)
} }
if v.IsSet(cmdConfig) { if err := readInConfig(v); err != nil {
if err := readConfig(v); err != nil {
panic(err) panic(err)
} }
}
return v return v
} }
@ -332,6 +333,9 @@ func bindFlags(v *viper.Viper, flags *pflag.FlagSet) error {
if err := v.BindPFlag(cmdConfig, flags.Lookup(cmdConfig)); err != nil { if err := v.BindPFlag(cmdConfig, flags.Lookup(cmdConfig)); err != nil {
return err return err
} }
if err := v.BindPFlag(cmdConfigDir, flags.Lookup(cmdConfigDir)); err != nil {
return err
}
if err := v.BindPFlag(cfgWalletPath, flags.Lookup(cmdWallet)); err != nil { if err := v.BindPFlag(cfgWalletPath, flags.Lookup(cmdWallet)); err != nil {
return err return err
} }
@ -370,17 +374,72 @@ func bindFlags(v *viper.Viper, flags *pflag.FlagSet) error {
return nil return nil
} }
func readConfig(v *viper.Viper) error { func readInConfig(v *viper.Viper) error {
cfgFileName := v.GetString(cmdConfig) if v.IsSet(cmdConfig) {
cfgFile, err := os.Open(cfgFileName) if err := readConfig(v); err != nil {
return err
}
}
if v.IsSet(cmdConfigDir) {
if err := readConfigDir(v); err != nil {
return err
}
}
return nil
}
func readConfigDir(v *viper.Viper) error {
cfgSubConfigDir := v.GetString(cmdConfigDir)
entries, err := os.ReadDir(cfgSubConfigDir)
if err != nil { if err != nil {
return err return err
} }
if err = v.ReadConfig(cfgFile); err != nil {
for _, entry := range entries {
if entry.IsDir() {
continue
}
ext := path.Ext(entry.Name())
if ext != ".yaml" && ext != ".yml" {
continue
}
if err = mergeConfig(v, path.Join(cfgSubConfigDir, entry.Name())); err != nil {
return err
}
}
return nil
}
func readConfig(v *viper.Viper) error {
for _, fileName := range v.GetStringSlice(cmdConfig) {
if err := mergeConfig(v, fileName); err != nil {
return err
}
}
return nil
}
func mergeConfig(v *viper.Viper, fileName string) error {
cfgFile, err := os.Open(fileName)
if err != nil {
return err return err
} }
return cfgFile.Close() defer func() {
if errClose := cfgFile.Close(); errClose != nil {
panic(errClose)
}
}()
if err = v.MergeConfig(cfgFile); err != nil {
return err
}
return nil
} }
// newLogger constructs a Logger instance for the current application. // newLogger constructs a Logger instance for the current application.

View file

@ -55,11 +55,11 @@ resolve_order:
# Metrics # Metrics
pprof: pprof:
enabled: true enabled: false
address: localhost:8085 address: localhost:8085
prometheus: prometheus:
enabled: true enabled: false
address: localhost:8086 address: localhost:8086
# Timeout to connect to a node # Timeout to connect to a node

3
config/dir/pprof.yaml Normal file
View file

@ -0,0 +1,3 @@
pprof:
enabled: true
address: localhost:8085

View file

@ -0,0 +1,3 @@
prometheus:
enabled: true
address: localhost:8086

View file

@ -110,6 +110,23 @@ A path to a configuration file can be specified with `--config` parameter:
$ frostfs-s3-gw --config your-config.yaml $ frostfs-s3-gw --config your-config.yaml
``` ```
### Multiple configs
You can use several config files when running application. It allows you to split configuration into parts.
For example, you can use separate yaml file for pprof and prometheus section in config (see [config examples](../config)).
You can either provide several files with repeating `--config` flag or provide path to the dir that contains all configs using `--config-dir` flag.
Also, you can combine these flags:
```shell
$ frostfs-s3-gw --config ./config/config.yaml --config /your/partial/config.yaml --config-dir ./config/dir
```
**Note:** next file in `--config` flag overwrites values from the previous one.
Files from `--config-dir` directory overwrite values from `--config` files.
So the command above run `frostfs-s3-gw` to listen on `0.0.0.0:8080` address (value from `./config/config.yaml`),
applies parameters from `/your/partial/config.yaml`,
enable pprof (value from `./config/dir/pprof.yaml`) and prometheus (value from `./config/dir/prometheus.yaml`).
### Reload on SIGHUP ### Reload on SIGHUP
Some config values can be reloaded on SIGHUP signal. Some config values can be reloaded on SIGHUP signal.