mirror of
https://github.com/prometheus/prometheus.git
synced 2025-02-21 03:16:00 -08:00
Merge pull request #796 from prometheus/fabxc/cfg-err
config: raise error on unknown config parameters
This commit is contained in:
commit
9013319d3a
|
@ -93,10 +93,24 @@ type Config struct {
|
||||||
RuleFiles []string `yaml:"rule_files,omitempty"`
|
RuleFiles []string `yaml:"rule_files,omitempty"`
|
||||||
ScrapeConfigs []*ScrapeConfig `yaml:"scrape_configs,omitempty"`
|
ScrapeConfigs []*ScrapeConfig `yaml:"scrape_configs,omitempty"`
|
||||||
|
|
||||||
|
// Catches all undefined fields and must be empty after parsing.
|
||||||
|
XXX map[string]interface{} `yaml:",inline"`
|
||||||
|
|
||||||
// original is the input from which the config was parsed.
|
// original is the input from which the config was parsed.
|
||||||
original string
|
original string
|
||||||
}
|
}
|
||||||
|
|
||||||
|
func checkOverflow(m map[string]interface{}, ctx string) error {
|
||||||
|
if len(m) > 0 {
|
||||||
|
var keys []string
|
||||||
|
for k := range m {
|
||||||
|
keys = append(keys, k)
|
||||||
|
}
|
||||||
|
return fmt.Errorf("unknown fields in %s: %s", ctx, strings.Join(keys, ", "))
|
||||||
|
}
|
||||||
|
return nil
|
||||||
|
}
|
||||||
|
|
||||||
func (c Config) String() string {
|
func (c Config) String() string {
|
||||||
if c.original != "" {
|
if c.original != "" {
|
||||||
return c.original
|
return c.original
|
||||||
|
@ -138,7 +152,7 @@ func (c *Config) UnmarshalYAML(unmarshal func(interface{}) error) error {
|
||||||
}
|
}
|
||||||
jobNames[scfg.JobName] = struct{}{}
|
jobNames[scfg.JobName] = struct{}{}
|
||||||
}
|
}
|
||||||
return nil
|
return checkOverflow(c.XXX, "config")
|
||||||
}
|
}
|
||||||
|
|
||||||
// GlobalConfig configures values that are used across other configuration
|
// GlobalConfig configures values that are used across other configuration
|
||||||
|
@ -150,9 +164,11 @@ type GlobalConfig struct {
|
||||||
ScrapeTimeout Duration `yaml:"scrape_timeout,omitempty"`
|
ScrapeTimeout Duration `yaml:"scrape_timeout,omitempty"`
|
||||||
// How frequently to evaluate rules by default.
|
// How frequently to evaluate rules by default.
|
||||||
EvaluationInterval Duration `yaml:"evaluation_interval,omitempty"`
|
EvaluationInterval Duration `yaml:"evaluation_interval,omitempty"`
|
||||||
|
|
||||||
// The labels to add to any timeseries that this Prometheus instance scrapes.
|
// The labels to add to any timeseries that this Prometheus instance scrapes.
|
||||||
Labels clientmodel.LabelSet `yaml:"labels,omitempty"`
|
Labels clientmodel.LabelSet `yaml:"labels,omitempty"`
|
||||||
|
|
||||||
|
// Catches all undefined fields and must be empty after parsing.
|
||||||
|
XXX map[string]interface{} `yaml:",inline"`
|
||||||
}
|
}
|
||||||
|
|
||||||
// UnmarshalYAML implements the yaml.Unmarshaler interface.
|
// UnmarshalYAML implements the yaml.Unmarshaler interface.
|
||||||
|
@ -162,7 +178,7 @@ func (c *GlobalConfig) UnmarshalYAML(unmarshal func(interface{}) error) error {
|
||||||
if err := unmarshal((*plain)(c)); err != nil {
|
if err := unmarshal((*plain)(c)); err != nil {
|
||||||
return err
|
return err
|
||||||
}
|
}
|
||||||
return nil
|
return checkOverflow(c.XXX, "global config")
|
||||||
}
|
}
|
||||||
|
|
||||||
// ScrapeConfig configures a scraping unit for Prometheus.
|
// ScrapeConfig configures a scraping unit for Prometheus.
|
||||||
|
@ -178,7 +194,7 @@ type ScrapeConfig struct {
|
||||||
// The URL scheme with which to fetch metrics from targets.
|
// The URL scheme with which to fetch metrics from targets.
|
||||||
Scheme string `yaml:"scheme,omitempty"`
|
Scheme string `yaml:"scheme,omitempty"`
|
||||||
// The HTTP basic authentication credentials for the targets.
|
// The HTTP basic authentication credentials for the targets.
|
||||||
BasicAuth *BasicAuth `yaml:"basic_auth"`
|
BasicAuth *BasicAuth `yaml:"basic_auth,omitempty"`
|
||||||
|
|
||||||
// List of labeled target groups for this job.
|
// List of labeled target groups for this job.
|
||||||
TargetGroups []*TargetGroup `yaml:"target_groups,omitempty"`
|
TargetGroups []*TargetGroup `yaml:"target_groups,omitempty"`
|
||||||
|
@ -190,6 +206,9 @@ type ScrapeConfig struct {
|
||||||
ConsulSDConfigs []*ConsulSDConfig `yaml:"consul_sd_configs,omitempty"`
|
ConsulSDConfigs []*ConsulSDConfig `yaml:"consul_sd_configs,omitempty"`
|
||||||
// List of relabel configurations.
|
// List of relabel configurations.
|
||||||
RelabelConfigs []*RelabelConfig `yaml:"relabel_configs,omitempty"`
|
RelabelConfigs []*RelabelConfig `yaml:"relabel_configs,omitempty"`
|
||||||
|
|
||||||
|
// Catches all undefined fields and must be empty after parsing.
|
||||||
|
XXX map[string]interface{} `yaml:",inline"`
|
||||||
}
|
}
|
||||||
|
|
||||||
// UnmarshalYAML implements the yaml.Unmarshaler interface.
|
// UnmarshalYAML implements the yaml.Unmarshaler interface.
|
||||||
|
@ -203,13 +222,26 @@ func (c *ScrapeConfig) UnmarshalYAML(unmarshal func(interface{}) error) error {
|
||||||
if !patJobName.MatchString(c.JobName) {
|
if !patJobName.MatchString(c.JobName) {
|
||||||
return fmt.Errorf("%q is not a valid job name", c.JobName)
|
return fmt.Errorf("%q is not a valid job name", c.JobName)
|
||||||
}
|
}
|
||||||
return nil
|
return checkOverflow(c.XXX, "scrape_config")
|
||||||
}
|
}
|
||||||
|
|
||||||
// BasicAuth contains basic HTTP authentication credentials.
|
// BasicAuth contains basic HTTP authentication credentials.
|
||||||
type BasicAuth struct {
|
type BasicAuth struct {
|
||||||
Username string `yaml:"username"`
|
Username string `yaml:"username"`
|
||||||
Password string `yaml:"password"`
|
Password string `yaml:"password"`
|
||||||
|
|
||||||
|
// Catches all undefined fields and must be empty after parsing.
|
||||||
|
XXX map[string]interface{} `yaml:",inline"`
|
||||||
|
}
|
||||||
|
|
||||||
|
// UnmarshalYAML implements the yaml.Unmarshaler interface.
|
||||||
|
func (a *BasicAuth) UnmarshalYAML(unmarshal func(interface{}) error) error {
|
||||||
|
type plain BasicAuth
|
||||||
|
err := unmarshal((*plain)(a))
|
||||||
|
if err != nil {
|
||||||
|
return err
|
||||||
|
}
|
||||||
|
return checkOverflow(a.XXX, "basic_auth")
|
||||||
}
|
}
|
||||||
|
|
||||||
// TargetGroup is a set of targets with a common label set.
|
// TargetGroup is a set of targets with a common label set.
|
||||||
|
@ -231,8 +263,9 @@ func (tg TargetGroup) String() string {
|
||||||
// UnmarshalYAML implements the yaml.Unmarshaler interface.
|
// UnmarshalYAML implements the yaml.Unmarshaler interface.
|
||||||
func (tg *TargetGroup) UnmarshalYAML(unmarshal func(interface{}) error) error {
|
func (tg *TargetGroup) UnmarshalYAML(unmarshal func(interface{}) error) error {
|
||||||
g := struct {
|
g := struct {
|
||||||
Targets []string `yaml:"targets"`
|
Targets []string `yaml:"targets"`
|
||||||
Labels clientmodel.LabelSet `yaml:"labels"`
|
Labels clientmodel.LabelSet `yaml:"labels"`
|
||||||
|
XXX map[string]interface{} `yaml:",inline"`
|
||||||
}{}
|
}{}
|
||||||
if err := unmarshal(&g); err != nil {
|
if err := unmarshal(&g); err != nil {
|
||||||
return err
|
return err
|
||||||
|
@ -247,7 +280,7 @@ func (tg *TargetGroup) UnmarshalYAML(unmarshal func(interface{}) error) error {
|
||||||
})
|
})
|
||||||
}
|
}
|
||||||
tg.Labels = g.Labels
|
tg.Labels = g.Labels
|
||||||
return nil
|
return checkOverflow(g.XXX, "target_group")
|
||||||
}
|
}
|
||||||
|
|
||||||
// MarshalYAML implements the yaml.Marshaler interface.
|
// MarshalYAML implements the yaml.Marshaler interface.
|
||||||
|
@ -291,6 +324,9 @@ func (tg *TargetGroup) UnmarshalJSON(b []byte) error {
|
||||||
type DNSSDConfig struct {
|
type DNSSDConfig struct {
|
||||||
Names []string `yaml:"names"`
|
Names []string `yaml:"names"`
|
||||||
RefreshInterval Duration `yaml:"refresh_interval,omitempty"`
|
RefreshInterval Duration `yaml:"refresh_interval,omitempty"`
|
||||||
|
|
||||||
|
// Catches all undefined fields and must be empty after parsing.
|
||||||
|
XXX map[string]interface{} `yaml:",inline"`
|
||||||
}
|
}
|
||||||
|
|
||||||
// UnmarshalYAML implements the yaml.Unmarshaler interface.
|
// UnmarshalYAML implements the yaml.Unmarshaler interface.
|
||||||
|
@ -304,13 +340,16 @@ func (c *DNSSDConfig) UnmarshalYAML(unmarshal func(interface{}) error) error {
|
||||||
if len(c.Names) == 0 {
|
if len(c.Names) == 0 {
|
||||||
return fmt.Errorf("DNS-SD config must contain at least one SRV record name")
|
return fmt.Errorf("DNS-SD config must contain at least one SRV record name")
|
||||||
}
|
}
|
||||||
return nil
|
return checkOverflow(c.XXX, "dns_sd_config")
|
||||||
}
|
}
|
||||||
|
|
||||||
// FileSDConfig is the configuration for file based discovery.
|
// FileSDConfig is the configuration for file based discovery.
|
||||||
type FileSDConfig struct {
|
type FileSDConfig struct {
|
||||||
Names []string `yaml:"names"`
|
Names []string `yaml:"names"`
|
||||||
RefreshInterval Duration `yaml:"refresh_interval,omitempty"`
|
RefreshInterval Duration `yaml:"refresh_interval,omitempty"`
|
||||||
|
|
||||||
|
// Catches all undefined fields and must be empty after parsing.
|
||||||
|
XXX map[string]interface{} `yaml:",inline"`
|
||||||
}
|
}
|
||||||
|
|
||||||
// UnmarshalYAML implements the yaml.Unmarshaler interface.
|
// UnmarshalYAML implements the yaml.Unmarshaler interface.
|
||||||
|
@ -329,7 +368,7 @@ func (c *FileSDConfig) UnmarshalYAML(unmarshal func(interface{}) error) error {
|
||||||
return fmt.Errorf("path name %q is not valid for file discovery", name)
|
return fmt.Errorf("path name %q is not valid for file discovery", name)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
return nil
|
return checkOverflow(c.XXX, "file_sd_config")
|
||||||
}
|
}
|
||||||
|
|
||||||
// ConsulSDConfig is the configuration for Consul service discovery.
|
// ConsulSDConfig is the configuration for Consul service discovery.
|
||||||
|
@ -343,6 +382,9 @@ type ConsulSDConfig struct {
|
||||||
Password string `yaml:"password"`
|
Password string `yaml:"password"`
|
||||||
// The list of services for which targets are discovered.
|
// The list of services for which targets are discovered.
|
||||||
Services []string `yaml:"services"`
|
Services []string `yaml:"services"`
|
||||||
|
|
||||||
|
// Catches all undefined fields and must be empty after parsing.
|
||||||
|
XXX map[string]interface{} `yaml:",inline"`
|
||||||
}
|
}
|
||||||
|
|
||||||
// UnmarshalYAML implements the yaml.Unmarshaler interface.
|
// UnmarshalYAML implements the yaml.Unmarshaler interface.
|
||||||
|
@ -359,7 +401,7 @@ func (c *ConsulSDConfig) UnmarshalYAML(unmarshal func(interface{}) error) error
|
||||||
if len(c.Services) == 0 {
|
if len(c.Services) == 0 {
|
||||||
return fmt.Errorf("Consul SD configuration requires at least one service name")
|
return fmt.Errorf("Consul SD configuration requires at least one service name")
|
||||||
}
|
}
|
||||||
return nil
|
return checkOverflow(c.XXX, "consul_sd_config")
|
||||||
}
|
}
|
||||||
|
|
||||||
// RelabelAction is the action to be performed on relabeling.
|
// RelabelAction is the action to be performed on relabeling.
|
||||||
|
@ -403,6 +445,9 @@ type RelabelConfig struct {
|
||||||
Replacement string `yaml:"replacement,omitempty"`
|
Replacement string `yaml:"replacement,omitempty"`
|
||||||
// Action is the action to be performed for the relabeling.
|
// Action is the action to be performed for the relabeling.
|
||||||
Action RelabelAction `yaml:"action,omitempty"`
|
Action RelabelAction `yaml:"action,omitempty"`
|
||||||
|
|
||||||
|
// Catches all undefined fields and must be empty after parsing.
|
||||||
|
XXX map[string]interface{} `yaml:",inline"`
|
||||||
}
|
}
|
||||||
|
|
||||||
// UnmarshalYAML implements the yaml.Unmarshaler interface.
|
// UnmarshalYAML implements the yaml.Unmarshaler interface.
|
||||||
|
@ -415,7 +460,7 @@ func (c *RelabelConfig) UnmarshalYAML(unmarshal func(interface{}) error) error {
|
||||||
if c.Regex == nil {
|
if c.Regex == nil {
|
||||||
return fmt.Errorf("relabel configuration requires a regular expression")
|
return fmt.Errorf("relabel configuration requires a regular expression")
|
||||||
}
|
}
|
||||||
return nil
|
return checkOverflow(c.XXX, "relabel_config")
|
||||||
}
|
}
|
||||||
|
|
||||||
// Regexp encapsulates a regexp.Regexp and makes it YAML marshallable.
|
// Regexp encapsulates a regexp.Regexp and makes it YAML marshallable.
|
||||||
|
|
|
@ -115,6 +115,24 @@ var expectedConf = &Config{
|
||||||
},
|
},
|
||||||
},
|
},
|
||||||
},
|
},
|
||||||
|
{
|
||||||
|
JobName: "service-y",
|
||||||
|
|
||||||
|
ScrapeInterval: Duration(15 * time.Second),
|
||||||
|
ScrapeTimeout: DefaultGlobalConfig.ScrapeTimeout,
|
||||||
|
|
||||||
|
MetricsPath: DefaultScrapeConfig.MetricsPath,
|
||||||
|
Scheme: DefaultScrapeConfig.Scheme,
|
||||||
|
|
||||||
|
ConsulSDConfigs: []*ConsulSDConfig{
|
||||||
|
{
|
||||||
|
Server: "localhost:1234",
|
||||||
|
Services: []string{"nginx", "cache", "mysql"},
|
||||||
|
TagSeparator: DefaultConsulSDConfig.TagSeparator,
|
||||||
|
Scheme: DefaultConsulSDConfig.Scheme,
|
||||||
|
},
|
||||||
|
},
|
||||||
|
},
|
||||||
},
|
},
|
||||||
original: "",
|
original: "",
|
||||||
}
|
}
|
||||||
|
@ -128,20 +146,20 @@ func TestLoadConfig(t *testing.T) {
|
||||||
|
|
||||||
c, err := LoadFromFile("testdata/conf.good.yml")
|
c, err := LoadFromFile("testdata/conf.good.yml")
|
||||||
if err != nil {
|
if err != nil {
|
||||||
t.Errorf("Error parsing %s: %s", "testdata/conf.good.yml", err)
|
t.Fatalf("Error parsing %s: %s", "testdata/conf.good.yml", err)
|
||||||
}
|
}
|
||||||
bgot, err := yaml.Marshal(c)
|
bgot, err := yaml.Marshal(c)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
t.Errorf("%s", err)
|
t.Fatalf("%s", err)
|
||||||
}
|
}
|
||||||
bexp, err := yaml.Marshal(expectedConf)
|
bexp, err := yaml.Marshal(expectedConf)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
t.Errorf("%s", err)
|
t.Fatalf("%s", err)
|
||||||
}
|
}
|
||||||
expectedConf.original = c.original
|
expectedConf.original = c.original
|
||||||
|
|
||||||
if !reflect.DeepEqual(c, expectedConf) {
|
if !reflect.DeepEqual(c, expectedConf) {
|
||||||
t.Errorf("%s: unexpected config result: \n\n%s\n expected\n\n%s", "testdata/conf.good.yml", bgot, bexp)
|
t.Fatalf("%s: unexpected config result: \n\n%s\n expected\n\n%s", "testdata/conf.good.yml", bgot, bexp)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -170,6 +188,9 @@ var expectedErrors = []struct {
|
||||||
}, {
|
}, {
|
||||||
filename: "rules.bad.yml",
|
filename: "rules.bad.yml",
|
||||||
errMsg: "invalid rule file path",
|
errMsg: "invalid rule file path",
|
||||||
|
}, {
|
||||||
|
filename: "unknown_attr.bad.yml",
|
||||||
|
errMsg: "unknown fields in scrape_config: consult_sd_configs",
|
||||||
},
|
},
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
108
config/testdata/conf.good.yml
vendored
108
config/testdata/conf.good.yml
vendored
|
@ -5,71 +5,75 @@ global:
|
||||||
# scrape_timeout is set to the global default (10s).
|
# scrape_timeout is set to the global default (10s).
|
||||||
|
|
||||||
labels:
|
labels:
|
||||||
monitor: codelab
|
monitor: codelab
|
||||||
foo: bar
|
foo: bar
|
||||||
|
|
||||||
rule_files:
|
rule_files:
|
||||||
- "first.rules"
|
- "first.rules"
|
||||||
- "second.rules"
|
- "second.rules"
|
||||||
- "my/*.rules"
|
- "my/*.rules"
|
||||||
|
|
||||||
scrape_configs:
|
scrape_configs:
|
||||||
- job_name: prometheus
|
- job_name: prometheus
|
||||||
|
|
||||||
# scrape_interval is defined by the configured global (15s).
|
# scrape_interval is defined by the configured global (15s).
|
||||||
# scrape_timeout is defined by the global default (10s).
|
# scrape_timeout is defined by the global default (10s).
|
||||||
|
|
||||||
# metrics_path defaults to '/metrics'
|
# metrics_path defaults to '/metrics'
|
||||||
# scheme defaults to 'http'.
|
# scheme defaults to 'http'.
|
||||||
|
|
||||||
|
file_sd_configs:
|
||||||
|
- names:
|
||||||
|
- foo/*.slow.json
|
||||||
|
- foo/*.slow.yml
|
||||||
|
- single/file.yml
|
||||||
|
refresh_interval: 10m
|
||||||
|
- names:
|
||||||
|
- bar/*.yaml
|
||||||
|
|
||||||
|
target_groups:
|
||||||
|
- targets: ['localhost:9090', 'localhost:9191']
|
||||||
labels:
|
labels:
|
||||||
foo: baz
|
my: label
|
||||||
|
your: label
|
||||||
|
|
||||||
file_sd_configs:
|
relabel_configs:
|
||||||
- names:
|
- source_labels: [job, __meta_dns_srv_name]
|
||||||
- foo/*.slow.json
|
regex: (.*)some-[regex]$
|
||||||
- foo/*.slow.yml
|
target_label: job
|
||||||
- single/file.yml
|
replacement: foo-${1}
|
||||||
refresh_interval: 10m
|
# action defaults to 'replace'
|
||||||
- names:
|
|
||||||
- bar/*.yaml
|
|
||||||
|
|
||||||
target_groups:
|
|
||||||
- targets: ['localhost:9090', 'localhost:9191']
|
|
||||||
labels:
|
|
||||||
my: label
|
|
||||||
your: label
|
|
||||||
|
|
||||||
relabel_configs:
|
|
||||||
- source_labels: [job, __meta_dns_srv_name]
|
|
||||||
regex: (.*)some-[regex]$
|
|
||||||
target_label: job
|
|
||||||
replacement: foo-${1}
|
|
||||||
# action defaults to 'replace'
|
|
||||||
|
|
||||||
|
|
||||||
- job_name: service-x
|
- job_name: service-x
|
||||||
|
|
||||||
basic_auth:
|
basic_auth:
|
||||||
username: admin
|
username: admin
|
||||||
password: password
|
password: password
|
||||||
|
|
||||||
scrape_interval: 50s
|
scrape_interval: 50s
|
||||||
scrape_timeout: 5s
|
scrape_timeout: 5s
|
||||||
|
|
||||||
metrics_path: /my_path
|
metrics_path: /my_path
|
||||||
scheme: https
|
scheme: https
|
||||||
|
|
||||||
dns_sd_configs:
|
dns_sd_configs:
|
||||||
- refresh_interval: 15s
|
- refresh_interval: 15s
|
||||||
names:
|
names:
|
||||||
- first.dns.address.domain.com
|
- first.dns.address.domain.com
|
||||||
- second.dns.address.domain.com
|
- second.dns.address.domain.com
|
||||||
- names:
|
- names:
|
||||||
- first.dns.address.domain.com
|
- first.dns.address.domain.com
|
||||||
# refresh_interval defaults to 30s.
|
# refresh_interval defaults to 30s.
|
||||||
|
|
||||||
relabel_configs:
|
relabel_configs:
|
||||||
- source_labels: [job]
|
- source_labels: [job]
|
||||||
regex: (.*)some-[regex]$
|
regex: (.*)some-[regex]$
|
||||||
action: drop
|
action: drop
|
||||||
|
|
||||||
|
|
||||||
|
- job_name: service-y
|
||||||
|
|
||||||
|
consul_sd_configs:
|
||||||
|
- server: 'localhost:1234'
|
||||||
|
services: ['nginx', 'cache', 'mysql']
|
20
config/testdata/unknown_attr.bad.yml
vendored
Normal file
20
config/testdata/unknown_attr.bad.yml
vendored
Normal file
|
@ -0,0 +1,20 @@
|
||||||
|
# my global config
|
||||||
|
global:
|
||||||
|
scrape_interval: 15s
|
||||||
|
evaluation_interval: 30s
|
||||||
|
# scrape_timeout is set to the global default (10s).
|
||||||
|
|
||||||
|
labels:
|
||||||
|
monitor: codelab
|
||||||
|
foo: bar
|
||||||
|
|
||||||
|
rule_files:
|
||||||
|
- "first.rules"
|
||||||
|
- "second.rules"
|
||||||
|
- "my/*.rules"
|
||||||
|
|
||||||
|
scrape_configs:
|
||||||
|
- job_name: prometheus
|
||||||
|
|
||||||
|
consult_sd_configs:
|
||||||
|
- server: 'localhost:1234'
|
Loading…
Reference in a new issue