diff --git a/cmd/windows_exporter/main.go b/cmd/windows_exporter/main.go
index a652160f..16eeaec2 100644
--- a/cmd/windows_exporter/main.go
+++ b/cmd/windows_exporter/main.go
@@ -71,10 +71,6 @@ func run() int {
"config.file",
"YAML configuration file to use. Values set in this file will be overridden by CLI flags.",
).String()
- insecureSkipVerify = app.Flag(
- "config.file.insecure-skip-verify",
- "Skip TLS verification in loading YAML configuration.",
- ).Default("false").Bool()
webConfig = webflag.AddFlags(app, ":9182")
metricsPath = app.Flag(
"telemetry.path",
@@ -122,11 +118,9 @@ func run() 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.Error("Failed to parse CLI args",
+ slog.Error("Failed to load configuration",
slog.Any("err", err),
)
@@ -145,52 +139,12 @@ func run() int {
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
- }
- }
-
logger.LogAttrs(ctx, slog.LevelDebug, "logging has Started")
+ if configFile != nil && *configFile != "" {
+ logger.InfoContext(ctx, "using configuration file: "+*configFile)
+ }
+
if err = setPriorityWindows(logger, os.Getpid(), *processPriority); err != nil {
logger.Error("failed to set process priority",
slog.Any("err", err),
diff --git a/installer/main.wxs b/installer/main.wxs
index dee64094..cabb77e2 100644
--- a/installer/main.wxs
+++ b/installer/main.wxs
@@ -115,10 +115,9 @@
-
-
+
-
+
diff --git a/internal/config/config.go b/internal/config/config.go
index aec44748..14b36dd8 100644
--- a/internal/config/config.go
+++ b/internal/config/config.go
@@ -16,12 +16,7 @@
package config
import (
- "context"
- "crypto/tls"
"fmt"
- "io"
- "log/slog"
- "net/http"
"os"
"strings"
@@ -38,8 +33,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 (
@@ -47,18 +86,9 @@ func NewResolver(ctx context.Context, file string, logger *slog.Logger, insecure
fileBytes []byte
)
- 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.")
-
- fileBytes, err = readFromURL(ctx, file, logger, insecureSkipVerify)
- if err != nil {
- return nil, err
- }
- } else {
- fileBytes, err = readFromFile(ctx, file, logger)
- if err != nil {
- return nil, err
- }
+ fileBytes, err = readFromFile(file)
+ if err != nil {
+ return nil, err
}
var rawValues map[string]interface{}
@@ -79,9 +109,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,39 +122,6 @@ 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)
-
- tr := &http.Transport{
- TLSClientConfig: &tls.Config{InsecureSkipVerify: insecureSkipVerify}, //nolint:gosec
- }
-
- if insecureSkipVerify {
- logger.WarnContext(ctx, "Loading configuration file with TLS verification disabled")
- }
-
- client := &http.Client{Transport: tr}
-
- req, err := http.NewRequestWithContext(ctx, http.MethodGet, file, nil)
- if err != nil {
- return nil, fmt.Errorf("failed to create HTTP request: %w", err)
- }
-
- resp, err := client.Do(req)
- if err != nil {
- return nil, fmt.Errorf("failed to read configuration file from URL: %w", err)
- }
-
- defer resp.Body.Close()
-
- fileBytes, err := io.ReadAll(resp.Body)
- if err != nil {
- return nil, err
- }
-
- return fileBytes, nil
-}
-
func (c *Resolver) setDefault(v getFlagger) {
for name, value := range c.flags {
f := v.GetFlag(name)