feat: Add config file validation (#2011)

This commit is contained in:
Jan-Otto Kröpke
2025-04-24 23:45:21 +02:00
committed by GitHub
parent 554607fee2
commit 769363d157
25 changed files with 107 additions and 66 deletions

View File

@@ -19,6 +19,7 @@ linters:
- maintidx - maintidx
- mnd - mnd
- paralleltest - paralleltest
- tagliatelle
- testpackage - testpackage
- varnamelen - varnamelen
- wrapcheck - wrapcheck

View File

@@ -34,7 +34,7 @@ import (
const Name = "dfsr" const Name = "dfsr"
type Config struct { type Config struct {
CollectorsEnabled []string `yaml:"collectors_enabled"` CollectorsEnabled []string `yaml:"sources-enabled"`
} }
//nolint:gochecknoglobals //nolint:gochecknoglobals

View File

@@ -41,7 +41,7 @@ const (
) )
type Config struct { type Config struct {
CollectorsEnabled []string `yaml:"collectors_enabled"` CollectorsEnabled []string `yaml:"enabled"`
} }
//nolint:gochecknoglobals //nolint:gochecknoglobals

View File

@@ -38,7 +38,7 @@ const (
) )
type Config struct { type Config struct {
CollectorsEnabled []string `yaml:"collectors_enabled"` CollectorsEnabled []string `yaml:"enabled"`
} }
//nolint:gochecknoglobals //nolint:gochecknoglobals

View File

@@ -46,7 +46,7 @@ const (
) )
type Config struct { type Config struct {
CollectorsEnabled []string `yaml:"collectors_enabled"` CollectorsEnabled []string `yaml:"enabled"`
} }
//nolint:gochecknoglobals //nolint:gochecknoglobals

View File

@@ -35,7 +35,7 @@ import (
const Name = "filetime" const Name = "filetime"
type Config struct { type Config struct {
FilePatterns []string FilePatterns []string `yaml:"file-patterns"`
} }
//nolint:gochecknoglobals //nolint:gochecknoglobals

View File

@@ -52,7 +52,7 @@ const (
) )
type Config struct { type Config struct {
CollectorsEnabled []string `yaml:"collectors_enabled"` CollectorsEnabled []string `yaml:"enabled"`
} }
//nolint:gochecknoglobals //nolint:gochecknoglobals

View File

@@ -35,10 +35,10 @@ import (
const Name = "iis" const Name = "iis"
type Config struct { type Config struct {
SiteInclude *regexp.Regexp `yaml:"site_include"` SiteInclude *regexp.Regexp `yaml:"site-include"`
SiteExclude *regexp.Regexp `yaml:"site_exclude"` SiteExclude *regexp.Regexp `yaml:"site-exclude"`
AppInclude *regexp.Regexp `yaml:"app_include"` AppInclude *regexp.Regexp `yaml:"app-include"`
AppExclude *regexp.Regexp `yaml:"app_exclude"` AppExclude *regexp.Regexp `yaml:"app-exclude"`
} }
//nolint:gochecknoglobals //nolint:gochecknoglobals

View File

@@ -38,8 +38,8 @@ import (
const Name = "logical_disk" const Name = "logical_disk"
type Config struct { type Config struct {
VolumeInclude *regexp.Regexp `yaml:"volume_include"` VolumeInclude *regexp.Regexp `yaml:"volume-include"`
VolumeExclude *regexp.Regexp `yaml:"volume_exclude"` VolumeExclude *regexp.Regexp `yaml:"volume-exclude"`
} }
//nolint:gochecknoglobals //nolint:gochecknoglobals

View File

@@ -41,7 +41,7 @@ const (
) )
type Config struct { type Config struct {
CollectorsEnabled []string `yaml:"collectors_enabled"` CollectorsEnabled []string `yaml:"enabled"`
} }
//nolint:gochecknoglobals //nolint:gochecknoglobals

View File

@@ -54,7 +54,7 @@ const (
) )
type Config struct { type Config struct {
CollectorsEnabled []string `yaml:"collectors_enabled"` CollectorsEnabled []string `yaml:"enabled"`
} }
//nolint:gochecknoglobals //nolint:gochecknoglobals

View File

@@ -43,9 +43,9 @@ const (
) )
type Config struct { type Config struct {
NicExclude *regexp.Regexp `yaml:"nic_exclude"` NicExclude *regexp.Regexp `yaml:"nic-exclude"`
NicInclude *regexp.Regexp `yaml:"nic_include"` NicInclude *regexp.Regexp `yaml:"nic-include"`
CollectorsEnabled []string `yaml:"collectors_enabled"` CollectorsEnabled []string `yaml:"enabled"`
} }
//nolint:gochecknoglobals //nolint:gochecknoglobals

View File

@@ -33,7 +33,7 @@ import (
const Name = "netframework" const Name = "netframework"
type Config struct { type Config struct {
CollectorsEnabled []string `yaml:"collectors_enabled"` CollectorsEnabled []string `yaml:"enabled"`
} }
//nolint:gochecknoglobals //nolint:gochecknoglobals

View File

@@ -19,6 +19,7 @@ package performancecounter
import ( import (
"github.com/prometheus-community/windows_exporter/internal/pdh" "github.com/prometheus-community/windows_exporter/internal/pdh"
"gopkg.in/yaml.v3"
) )
type Object struct { type Object struct {
@@ -41,3 +42,7 @@ type Counter struct {
} }
// https://github.com/open-telemetry/opentelemetry-collector-contrib/blob/54691ebe11bb9ec32b4e35cd31fcb94a352de134/receiver/windowsperfcountersreceiver/README.md?plain=1#L150 // https://github.com/open-telemetry/opentelemetry-collector-contrib/blob/54691ebe11bb9ec32b4e35cd31fcb94a352de134/receiver/windowsperfcountersreceiver/README.md?plain=1#L150
func (*Config) UnmarshalYAML(*yaml.Node) error {
return nil
}

View File

@@ -33,8 +33,8 @@ import (
const Name = "physical_disk" const Name = "physical_disk"
type Config struct { type Config struct {
DiskInclude *regexp.Regexp `yaml:"disk_include"` DiskInclude *regexp.Regexp `yaml:"disk-include"`
DiskExclude *regexp.Regexp `yaml:"disk_exclude"` DiskExclude *regexp.Regexp `yaml:"disk-exclude"`
} }
//nolint:gochecknoglobals //nolint:gochecknoglobals

View File

@@ -46,8 +46,8 @@ var printerStatusMap = map[uint16]string{
} }
type Config struct { type Config struct {
PrinterInclude *regexp.Regexp `yaml:"printer_include"` PrinterInclude *regexp.Regexp `yaml:"include"`
PrinterExclude *regexp.Regexp `yaml:"printer_exclude"` PrinterExclude *regexp.Regexp `yaml:"exclude"`
} }
//nolint:gochecknoglobals //nolint:gochecknoglobals

View File

@@ -39,9 +39,9 @@ import (
const Name = "process" const Name = "process"
type Config struct { type Config struct {
ProcessInclude *regexp.Regexp `yaml:"process_include"` ProcessInclude *regexp.Regexp `yaml:"include"`
ProcessExclude *regexp.Regexp `yaml:"process_exclude"` ProcessExclude *regexp.Regexp `yaml:"exclude"`
EnableWorkerProcess bool `yaml:"enable_iis_worker_process"` //nolint:tagliatelle EnableWorkerProcess bool `yaml:"iis"`
} }
//nolint:gochecknoglobals //nolint:gochecknoglobals

View File

@@ -36,8 +36,8 @@ import (
const Name = "scheduled_task" const Name = "scheduled_task"
type Config struct { type Config struct {
TaskExclude *regexp.Regexp `yaml:"task_exclude"` TaskExclude *regexp.Regexp `yaml:"exclude"`
TaskInclude *regexp.Regexp `yaml:"task_include"` TaskInclude *regexp.Regexp `yaml:"include"`
} }
//nolint:gochecknoglobals //nolint:gochecknoglobals

View File

@@ -38,8 +38,8 @@ import (
const Name = "service" const Name = "service"
type Config struct { type Config struct {
ServiceInclude *regexp.Regexp `yaml:"service_include"` ServiceInclude *regexp.Regexp `yaml:"include"`
ServiceExclude *regexp.Regexp `yaml:"service_exclude"` ServiceExclude *regexp.Regexp `yaml:"exclude"`
} }
//nolint:gochecknoglobals //nolint:gochecknoglobals

View File

@@ -32,8 +32,8 @@ import (
const Name = "smtp" const Name = "smtp"
type Config struct { type Config struct {
ServerInclude *regexp.Regexp `yaml:"server_include"` ServerInclude *regexp.Regexp `yaml:"server-include"`
ServerExclude *regexp.Regexp `yaml:"server_exclude"` ServerExclude *regexp.Regexp `yaml:"server-exclude"`
} }
//nolint:gochecknoglobals //nolint:gochecknoglobals

View File

@@ -36,7 +36,7 @@ import (
const Name = "tcp" const Name = "tcp"
type Config struct { type Config struct {
CollectorsEnabled []string `yaml:"collectors_enabled"` CollectorsEnabled []string `yaml:"enabled"`
} }
//nolint:gochecknoglobals //nolint:gochecknoglobals

View File

@@ -41,7 +41,7 @@ import (
const Name = "textfile" const Name = "textfile"
type Config struct { type Config struct {
TextFileDirectories []string `yaml:"text_file_directories"` TextFileDirectories []string `yaml:"directories"`
} }
//nolint:gochecknoglobals //nolint:gochecknoglobals

View File

@@ -43,7 +43,7 @@ const (
) )
type Config struct { type Config struct {
CollectorsEnabled []string `yaml:"collectors_enabled"` CollectorsEnabled []string `yaml:"enabled"`
} }
//nolint:gochecknoglobals //nolint:gochecknoglobals

View File

@@ -19,13 +19,49 @@ package config
import ( import (
"fmt" "fmt"
"io"
"os" "os"
"strings" "strings"
"github.com/alecthomas/kingpin/v2" "github.com/alecthomas/kingpin/v2"
"github.com/prometheus-community/windows_exporter/pkg/collector"
"gopkg.in/yaml.v3" "gopkg.in/yaml.v3"
) )
// configFile represents the structure of the windows_exporter configuration file,
// including configuration from the collector and web packages.
type configFile struct {
Debug struct {
Enabled bool `yaml:"enabled"`
} `yaml:"debug"`
Collectors struct {
Enabled string `yaml:"enabled"`
} `yaml:"collectors"`
Collector collector.Config `yaml:"collector"`
Log struct {
Level string `yaml:"level"`
Format string `yaml:"format"`
File string `yaml:"file"`
} `yaml:"log"`
Process struct {
Priority string `yaml:"priority"`
MemoryLimit string `yaml:"memory-limit"`
} `yaml:"process"`
Scrape struct {
TimeoutMargin string `yaml:"timeout-margin"`
} `yaml:"scrape"`
Telemetry struct {
Path string `yaml:"path"`
} `yaml:"telemetry"`
Web struct {
DisableExporterMetrics bool `yaml:"disable-exporter-metrics"`
ListenAddresses any `yaml:"listen-address"`
Config struct {
File string `yaml:"file"`
} `yaml:"config"`
} `yaml:"web"`
}
type getFlagger interface { type getFlagger interface {
GetFlag(name string) *kingpin.FlagClause GetFlag(name string) *kingpin.FlagClause
} }
@@ -80,24 +116,37 @@ func ParseConfigFile(args []string) string {
} }
// NewConfigFileResolver returns a Resolver structure. // NewConfigFileResolver returns a Resolver structure.
func NewConfigFileResolver(file string) (*Resolver, error) { func NewConfigFileResolver(filePath string) (*Resolver, error) {
flags := map[string]string{} flags := map[string]string{}
var ( file, err := os.Open(filePath)
err error
fileBytes []byte
)
fileBytes, err = readFromFile(file)
if err != nil { if err != nil {
return nil, err return nil, fmt.Errorf("failed to open configuration file: %w", err)
}
defer func() {
_ = file.Close()
}()
var configFileStructure configFile
decoder := yaml.NewDecoder(file)
decoder.KnownFields(true)
if err = decoder.Decode(&configFileStructure); err != nil {
return nil, fmt.Errorf("configuration file validation error: %w", err)
}
_, err = file.Seek(0, io.SeekStart)
if err != nil {
return nil, fmt.Errorf("failed to rewind file: %w", err)
} }
var rawValues map[string]interface{} var rawValues map[string]interface{}
err = yaml.Unmarshal(fileBytes, &rawValues) decoder = yaml.NewDecoder(file)
if err != nil { if err = decoder.Decode(&rawValues); err != nil {
return nil, fmt.Errorf("failed to unmarshal configuration file: %w", err) return nil, fmt.Errorf("failed to parse configuration file: %w", err)
} }
// Flatten nested YAML values // Flatten nested YAML values
@@ -111,23 +160,9 @@ func NewConfigFileResolver(file string) (*Resolver, error) {
return &Resolver{flags: flags}, nil return &Resolver{flags: flags}, nil
} }
func readFromFile(file string) ([]byte, error) {
if _, err := os.Stat(file); err != nil {
return nil, fmt.Errorf("failed to read configuration file: %w", err)
}
fileBytes, err := os.ReadFile(file)
if err != nil {
return nil, fmt.Errorf("failed to read configuration file: %w", err)
}
return fileBytes, nil
}
func (c *Resolver) setDefault(v getFlagger) { func (c *Resolver) setDefault(v getFlagger) {
for name, value := range c.flags { for name, value := range c.flags {
f := v.GetFlag(name) if f := v.GetFlag(name); f != nil {
if f != nil {
f.Default(value) f.Default(value)
} }
} }

View File

@@ -79,26 +79,26 @@ type Config struct {
Cs cs.Config `yaml:"cs"` Cs cs.Config `yaml:"cs"`
DFSR dfsr.Config `yaml:"dfsr"` DFSR dfsr.Config `yaml:"dfsr"`
Dhcp dhcp.Config `yaml:"dhcp"` Dhcp dhcp.Config `yaml:"dhcp"`
DiskDrive diskdrive.Config `yaml:"disk_drive"` DiskDrive diskdrive.Config `yaml:"diskdrive"`
DNS dns.Config `yaml:"dns"` DNS dns.Config `yaml:"dns"`
Exchange exchange.Config `yaml:"exchange"` Exchange exchange.Config `yaml:"exchange"`
Filetime filetime.Config `yaml:"filetime"` Filetime filetime.Config `yaml:"filetime"`
Fsrmquota fsrmquota.Config `yaml:"fsrmquota"` Fsrmquota fsrmquota.Config `yaml:"fsrmquota"`
HyperV hyperv.Config `yaml:"hyper_v"` HyperV hyperv.Config `yaml:"hyperv"`
IIS iis.Config `yaml:"iis"` IIS iis.Config `yaml:"iis"`
License license.Config `yaml:"license"` License license.Config `yaml:"license"`
LogicalDisk logical_disk.Config `yaml:"logical_disk"` LogicalDisk logical_disk.Config `yaml:"logical_disk"`
Logon logon.Config `yaml:"logon"` Logon logon.Config `yaml:"logon"`
Memory memory.Config `yaml:"memory"` Memory memory.Config `yaml:"memory"`
MSCluster mscluster.Config `yaml:"ms_cluster"` MSCluster mscluster.Config `yaml:"mscluster"`
Msmq msmq.Config `yaml:"msmq"` Msmq msmq.Config `yaml:"msmq"`
Mssql mssql.Config `yaml:"mssql"` Mssql mssql.Config `yaml:"mssql"`
Net net.Config `yaml:"net"` Net net.Config `yaml:"net"`
NetFramework netframework.Config `yaml:"net_framework"` NetFramework netframework.Config `yaml:"netframework"`
Nps nps.Config `yaml:"nps"` Nps nps.Config `yaml:"nps"`
OS os.Config `yaml:"os"` OS os.Config `yaml:"os"`
Paging pagefile.Config `yaml:"paging"` Paging pagefile.Config `yaml:"paging"`
PerformanceCounter performancecounter.Config `yaml:"performance_counter"` PerformanceCounter performancecounter.Config `yaml:"performancecounter"`
PhysicalDisk physical_disk.Config `yaml:"physical_disk"` PhysicalDisk physical_disk.Config `yaml:"physical_disk"`
Printer printer.Config `yaml:"printer"` Printer printer.Config `yaml:"printer"`
Process process.Config `yaml:"process"` Process process.Config `yaml:"process"`
@@ -112,7 +112,7 @@ type Config struct {
TCP tcp.Config `yaml:"tcp"` TCP tcp.Config `yaml:"tcp"`
TerminalServices terminal_services.Config `yaml:"terminal_services"` TerminalServices terminal_services.Config `yaml:"terminal_services"`
Textfile textfile.Config `yaml:"textfile"` Textfile textfile.Config `yaml:"textfile"`
ThermalZone thermalzone.Config `yaml:"thermal_zone"` ThermalZone thermalzone.Config `yaml:"thermalzone"`
Time time.Config `yaml:"time"` Time time.Config `yaml:"time"`
UDP udp.Config `yaml:"udp"` UDP udp.Config `yaml:"udp"`
Update update.Config `yaml:"update"` Update update.Config `yaml:"update"`