[0.30] support web.listen-addr from CLI (#3)

Signed-off-by: Jan-Otto Kröpke <mail@jkroepke.de>
Signed-off-by: Jan-Otto Kröpke <github@jkroepke.de>
This commit is contained in:
Jan-Otto Kröpke
2025-04-06 03:36:58 +02:00
committed by GitHub
parent 759faee1c3
commit 2c4698f119
2 changed files with 58 additions and 67 deletions

View File

@@ -74,7 +74,7 @@ func run(ctx context.Context, args []string) int {
"config.file",
"YAML configuration file to use. Values set in this file will be overridden by CLI flags.",
).String()
insecureSkipVerify = app.Flag(
_ = app.Flag(
"config.file.insecure-skip-verify",
"Skip TLS verification in loading YAML configuration.",
).Default("false").Bool()
@@ -125,11 +125,9 @@ func run(ctx context.Context, args []string) int {
// Initialize collectors before loading and parsing CLI arguments
collectors := collector.NewWithFlags(app)
// Load values from configuration file(s). Executable flags must first be parsed, in order
// to load the specified file(s).
if _, err := app.Parse(os.Args[1:]); err != nil {
if err := config.Parse(app, os.Args[1:]); err != nil {
//nolint:sloglint // we do not have an logger yet
slog.LogAttrs(ctx, slog.LevelError, "Failed to parse CLI args",
slog.LogAttrs(ctx, slog.LevelError, "Failed to load configuration",
slog.Any("err", err),
)
@@ -137,58 +135,16 @@ func run(ctx context.Context, args []string) int {
}
debug.SetMemoryLimit(*memoryLimit)
logger, err := log.New(logConfig)
if err != nil {
logger.LogAttrs(ctx, slog.LevelError, "failed to create logger",
slog.Any("err", err),
)
return 1
}
if *configFile != "" {
resolver, err := config.NewResolver(ctx, *configFile, logger, *insecureSkipVerify)
if err != nil {
logger.Error("could not load config file",
slog.Any("err", err),
)
return 1
}
if err = resolver.Bind(app, os.Args[1:]); err != nil {
logger.ErrorContext(ctx, "failed to bind configuration",
slog.Any("err", err),
)
return 1
}
// Parse flags once more to include those discovered in configuration file(s).
if _, err = app.Parse(os.Args[1:]); err != nil {
logger.ErrorContext(ctx, "failed to parse CLI args from YAML file",
slog.Any("err", err),
)
return 1
}
// NOTE: This is temporary fix for issue #1092, calling kingpin.Parse
// twice makes slices flags duplicate its value, this clean up
// the first parse before the second call.
slices.Sort(*webConfig.WebListenAddresses)
*webConfig.WebListenAddresses = slices.Clip(slices.Compact(*webConfig.WebListenAddresses))
logger, err = log.New(logConfig)
if err != nil {
//nolint:sloglint // we do not have an logger yet
slog.Error("failed to create logger",
slog.Any("err", err),
)
return 1
}
if configFile != nil && *configFile != "" {
logger.InfoContext(ctx, "using configuration file: "+*configFile)
}
logger.LogAttrs(ctx, slog.LevelDebug, "logging has Started")

View File

@@ -16,7 +16,6 @@
package config
import (
"context"
"crypto/tls"
"fmt"
"io"
@@ -38,8 +37,52 @@ type Resolver struct {
flags map[string]string
}
// NewResolver returns a Resolver structure.
func NewResolver(ctx context.Context, file string, logger *slog.Logger, insecureSkipVerify bool) (*Resolver, error) {
// Parse parses the command line arguments and configuration files.
func Parse(app *kingpin.Application, args []string) error {
configFile := ParseConfigFile(args)
if configFile != "" {
resolver, err := NewConfigFileResolver(configFile)
if err != nil {
return fmt.Errorf("failed to load configuration file: %w", err)
}
if err = resolver.Bind(app, args); err != nil {
return fmt.Errorf("failed to bind configuration: %w", err)
}
}
if _, err := app.Parse(args); err != nil {
return fmt.Errorf("failed to parse flags: %w", err)
}
return nil
}
// ParseConfigFile manually parses the configuration file from the command line arguments.
func ParseConfigFile(args []string) string {
for i, cliFlag := range args {
if strings.HasPrefix(cliFlag, "--config.file=") {
return strings.TrimPrefix(cliFlag, "--config.file=")
}
if strings.HasPrefix(cliFlag, "-config.file=") {
return strings.TrimPrefix(cliFlag, "-config.file=")
}
if strings.HasSuffix(cliFlag, "-config.file") {
if len(os.Args) <= i+1 {
return ""
}
return os.Args[i+1]
}
}
return ""
}
// NewConfigFileResolver returns a Resolver structure.
func NewConfigFileResolver(file string) (*Resolver, error) {
flags := map[string]string{}
var (
@@ -48,14 +91,14 @@ func NewResolver(ctx context.Context, file string, logger *slog.Logger, insecure
)
if strings.HasPrefix(file, "http://") || strings.HasPrefix(file, "https://") {
logger.WarnContext(ctx, "Loading configuration file from URL is deprecated and will be removed in 0.31.0. Use a local file instead.")
slog.Warn("Loading configuration file from URL is deprecated and will be removed in 0.31.0. Use a local file instead.")
fileBytes, err = readFromURL(ctx, file, logger, insecureSkipVerify)
fileBytes, err = readFromURL(file)
if err != nil {
return nil, err
}
} else {
fileBytes, err = readFromFile(ctx, file, logger)
fileBytes, err = readFromFile(file)
if err != nil {
return nil, err
}
@@ -79,9 +122,7 @@ func NewResolver(ctx context.Context, file string, logger *slog.Logger, insecure
return &Resolver{flags: flags}, nil
}
func readFromFile(ctx context.Context, file string, logger *slog.Logger) ([]byte, error) {
logger.InfoContext(ctx, "loading configuration file: "+file)
func readFromFile(file string) ([]byte, error) {
if _, err := os.Stat(file); err != nil {
return nil, fmt.Errorf("failed to read configuration file: %w", err)
}
@@ -94,20 +135,14 @@ func readFromFile(ctx context.Context, file string, logger *slog.Logger) ([]byte
return fileBytes, nil
}
func readFromURL(ctx context.Context, file string, logger *slog.Logger, insecureSkipVerify bool) ([]byte, error) {
logger.InfoContext(ctx, "loading configuration file from URL: "+file)
func readFromURL(file string) ([]byte, error) {
tr := &http.Transport{
TLSClientConfig: &tls.Config{InsecureSkipVerify: insecureSkipVerify}, //nolint:gosec
}
if insecureSkipVerify {
logger.WarnContext(ctx, "Loading configuration file with TLS verification disabled")
TLSClientConfig: &tls.Config{InsecureSkipVerify: true}, //nolint:gosec
}
client := &http.Client{Transport: tr}
req, err := http.NewRequestWithContext(ctx, http.MethodGet, file, nil)
req, err := http.NewRequest(http.MethodGet, file, nil)
if err != nil {
return nil, fmt.Errorf("failed to create HTTP request: %w", err)
}