From 0af1cff8af871389a5967ebab07295ee6c354127 Mon Sep 17 00:00:00 2001 From: Fabian Reinartz Date: Thu, 4 Jun 2015 17:03:12 +0200 Subject: [PATCH] config: simplify default config handling. --- config/config.go | 163 +++++++++++++------------------- config/config_test.go | 41 ++++---- retrieval/relabel_test.go | 22 ++--- retrieval/targetmanager_test.go | 27 +++--- 4 files changed, 110 insertions(+), 143 deletions(-) diff --git a/config/config.go b/config/config.go index 224aebcd4..c94eda712 100644 --- a/config/config.go +++ b/config/config.go @@ -45,19 +45,19 @@ func LoadFromFile(filename string) (*Config, error) { // The defaults applied before parsing the respective config sections. var ( // The default top-level configuration. - DefaultConfig = DefaultedConfig{ - GlobalConfig: &GlobalConfig{DefaultGlobalConfig}, + DefaultConfig = Config{ + GlobalConfig: &DefaultGlobalConfig, } // The default global configuration. - DefaultGlobalConfig = DefaultedGlobalConfig{ + DefaultGlobalConfig = GlobalConfig{ ScrapeInterval: Duration(1 * time.Minute), ScrapeTimeout: Duration(10 * time.Second), EvaluationInterval: Duration(1 * time.Minute), } // Te default scrape configuration. - DefaultScrapeConfig = DefaultedScrapeConfig{ + DefaultScrapeConfig = ScrapeConfig{ // ScrapeTimeout and ScrapeInterval default to the // configured globals. MetricsPath: "/metrics", @@ -65,23 +65,23 @@ var ( } // The default Relabel configuration. - DefaultRelabelConfig = DefaultedRelabelConfig{ + DefaultRelabelConfig = RelabelConfig{ Action: RelabelReplace, Separator: ";", } // The default DNS SD configuration. - DefaultDNSSDConfig = DefaultedDNSSDConfig{ + DefaultDNSSDConfig = DNSSDConfig{ RefreshInterval: Duration(30 * time.Second), } // The default file SD configuration. - DefaultFileSDConfig = DefaultedFileSDConfig{ + DefaultFileSDConfig = FileSDConfig{ RefreshInterval: Duration(30 * time.Second), } // The default Consul SD configuration. - DefaultConsulSDConfig = DefaultedConsulSDConfig{ + DefaultConsulSDConfig = ConsulSDConfig{ TagSeparator: ",", Scheme: "http", } @@ -89,8 +89,9 @@ var ( // Config is the top-level configuration for Prometheus's config files. type Config struct { - // DefaultedConfig contains the actual fields of Config. - DefaultedConfig `yaml:",inline"` + GlobalConfig *GlobalConfig `yaml:"global"` + RuleFiles []string `yaml:"rule_files,omitempty"` + ScrapeConfigs []*ScrapeConfig `yaml:"scrape_configs,omitempty"` // original is the input from which the config was parsed. original string @@ -109,8 +110,12 @@ func (c Config) String() string { // UnmarshalYAML implements the yaml.Unmarshaler interface. func (c *Config) UnmarshalYAML(unmarshal func(interface{}) error) error { - c.DefaultedConfig = DefaultConfig - if err := unmarshal(&c.DefaultedConfig); err != nil { + *c = DefaultConfig + // We want to set c to the defaults and then overwrite it with the input. + // To make unmarshal fill the plain data struct rather than calling UnmarshalYAML + // again, we have to hide it using a type indirection. + type plain Config + if err := unmarshal((*plain)(c)); err != nil { return err } for _, rf := range c.RuleFiles { @@ -136,31 +141,9 @@ func (c *Config) UnmarshalYAML(unmarshal func(interface{}) error) error { return nil } -// DefaultedConfig is a proxy type for Config. -type DefaultedConfig struct { - GlobalConfig *GlobalConfig `yaml:"global"` - RuleFiles []string `yaml:"rule_files,omitempty"` - ScrapeConfigs []*ScrapeConfig `yaml:"scrape_configs,omitempty"` -} - // GlobalConfig configures values that are used across other configuration // objects. type GlobalConfig struct { - // DefaultedGlobalConfig contains the actual fields for GlobalConfig. - DefaultedGlobalConfig `yaml:",inline"` -} - -// UnmarshalYAML implements the yaml.Unmarshaler interface. -func (c *GlobalConfig) UnmarshalYAML(unmarshal func(interface{}) error) error { - c.DefaultedGlobalConfig = DefaultGlobalConfig - if err := unmarshal(&c.DefaultedGlobalConfig); err != nil { - return err - } - return nil -} - -// DefaultedGlobalConfig is a proxy type for GlobalConfig. -type DefaultedGlobalConfig struct { // How frequently to scrape targets by default. ScrapeInterval Duration `yaml:"scrape_interval,omitempty"` // The default timeout when scraping targets. @@ -172,27 +155,18 @@ type DefaultedGlobalConfig struct { Labels clientmodel.LabelSet `yaml:"labels,omitempty"` } -// ScrapeConfig configures a scraping unit for Prometheus. -type ScrapeConfig struct { - // DefaultedScrapeConfig contains the actual fields for ScrapeConfig. - DefaultedScrapeConfig `yaml:",inline"` -} - // UnmarshalYAML implements the yaml.Unmarshaler interface. -func (c *ScrapeConfig) UnmarshalYAML(unmarshal func(interface{}) error) error { - c.DefaultedScrapeConfig = DefaultScrapeConfig - err := unmarshal(&c.DefaultedScrapeConfig) - if err != nil { +func (c *GlobalConfig) UnmarshalYAML(unmarshal func(interface{}) error) error { + *c = DefaultGlobalConfig + type plain GlobalConfig + if err := unmarshal((*plain)(c)); err != nil { return err } - if !patJobName.MatchString(c.JobName) { - return fmt.Errorf("%q is not a valid job name", c.JobName) - } return nil } -// DefaultedScrapeConfig is a proxy type for ScrapeConfig. -type DefaultedScrapeConfig struct { +// ScrapeConfig configures a scraping unit for Prometheus. +type ScrapeConfig struct { // The job name to which the job label is set by default. JobName string `yaml:"job_name"` // How frequently to scrape the targets of this scrape config. @@ -218,6 +192,20 @@ type DefaultedScrapeConfig struct { RelabelConfigs []*RelabelConfig `yaml:"relabel_configs,omitempty"` } +// UnmarshalYAML implements the yaml.Unmarshaler interface. +func (c *ScrapeConfig) UnmarshalYAML(unmarshal func(interface{}) error) error { + *c = DefaultScrapeConfig + type plain ScrapeConfig + err := unmarshal((*plain)(c)) + if err != nil { + return err + } + if !patJobName.MatchString(c.JobName) { + return fmt.Errorf("%q is not a valid job name", c.JobName) + } + return nil +} + // BasicAuth contains basic HTTP authentication credentials. type BasicAuth struct { Username string `yaml:"username"` @@ -301,14 +289,15 @@ func (tg *TargetGroup) UnmarshalJSON(b []byte) error { // DNSSDConfig is the configuration for DNS based service discovery. type DNSSDConfig struct { - // DefaultedDNSSDConfig contains the actual fields for DNSSDConfig. - DefaultedDNSSDConfig `yaml:",inline"` + Names []string `yaml:"names"` + RefreshInterval Duration `yaml:"refresh_interval,omitempty"` } // UnmarshalYAML implements the yaml.Unmarshaler interface. func (c *DNSSDConfig) UnmarshalYAML(unmarshal func(interface{}) error) error { - c.DefaultedDNSSDConfig = DefaultDNSSDConfig - err := unmarshal(&c.DefaultedDNSSDConfig) + *c = DefaultDNSSDConfig + type plain DNSSDConfig + err := unmarshal((*plain)(c)) if err != nil { return err } @@ -318,22 +307,17 @@ func (c *DNSSDConfig) UnmarshalYAML(unmarshal func(interface{}) error) error { return nil } -// DefaultedDNSSDConfig is a proxy type for DNSSDConfig. -type DefaultedDNSSDConfig struct { - Names []string `yaml:"names"` - RefreshInterval Duration `yaml:"refresh_interval,omitempty"` -} - // FileSDConfig is the configuration for file based discovery. type FileSDConfig struct { - // DefaultedFileSDConfig contains the actual fields for FileSDConfig. - DefaultedFileSDConfig `yaml:",inline"` + Names []string `yaml:"names"` + RefreshInterval Duration `yaml:"refresh_interval,omitempty"` } // UnmarshalYAML implements the yaml.Unmarshaler interface. func (c *FileSDConfig) UnmarshalYAML(unmarshal func(interface{}) error) error { - c.DefaultedFileSDConfig = DefaultFileSDConfig - err := unmarshal(&c.DefaultedFileSDConfig) + *c = DefaultFileSDConfig + type plain FileSDConfig + err := unmarshal((*plain)(c)) if err != nil { return err } @@ -348,22 +332,24 @@ func (c *FileSDConfig) UnmarshalYAML(unmarshal func(interface{}) error) error { return nil } -// DefaultedFileSDConfig is a proxy type for FileSDConfig. -type DefaultedFileSDConfig struct { - Names []string `yaml:"names"` - RefreshInterval Duration `yaml:"refresh_interval,omitempty"` -} - // ConsulSDConfig is the configuration for Consul service discovery. type ConsulSDConfig struct { - // DefaultedConsulSDConfig contains the actual fields for ConsulSDConfig. - DefaultedConsulSDConfig `yaml:",inline"` + Server string `yaml:"server"` + Token string `yaml:"token"` + Datacenter string `yaml:"datacenter"` + TagSeparator string `yaml:"tag_separator"` + Scheme string `yaml:"scheme"` + Username string `yaml:"username"` + Password string `yaml:"password"` + // The list of services for which targets are discovered. + Services []string `yaml:"services"` } // UnmarshalYAML implements the yaml.Unmarshaler interface. func (c *ConsulSDConfig) UnmarshalYAML(unmarshal func(interface{}) error) error { - c.DefaultedConsulSDConfig = DefaultConsulSDConfig - err := unmarshal(&c.DefaultedConsulSDConfig) + *c = DefaultConsulSDConfig + type plain ConsulSDConfig + err := unmarshal((*plain)(c)) if err != nil { return err } @@ -376,18 +362,6 @@ func (c *ConsulSDConfig) UnmarshalYAML(unmarshal func(interface{}) error) error return nil } -// DefaultedConsulSDConfig is a proxy type for ConsulSDConfig. -type DefaultedConsulSDConfig struct { - Server string `yaml:"server"` - Token string `yaml:"token"` - Datacenter string `yaml:"datacenter"` - TagSeparator string `yaml:"tag_separator"` - Scheme string `yaml:"scheme"` - Username string `yaml:"username"` - Password string `yaml:"password"` - Services []string `yaml:"services"` -} - // RelabelAction is the action to be performed on relabeling. type RelabelAction string @@ -416,18 +390,6 @@ func (a *RelabelAction) UnmarshalYAML(unmarshal func(interface{}) error) error { // RelabelConfig is the configuration for relabeling of target label sets. type RelabelConfig struct { - // DefaultedRelabelConfig contains the actual fields for RelabelConfig. - DefaultedRelabelConfig `yaml:",inline"` -} - -// UnmarshalYAML implements the yaml.Unmarshaler interface. -func (c *RelabelConfig) UnmarshalYAML(unmarshal func(interface{}) error) error { - c.DefaultedRelabelConfig = DefaultRelabelConfig - return unmarshal(&c.DefaultedRelabelConfig) -} - -// DefaultedRelabelConfig is a proxy type for RelabelConfig. -type DefaultedRelabelConfig struct { // A list of labels from which values are taken and concatenated // with the configured separator in order. SourceLabels clientmodel.LabelNames `yaml:"source_labels,flow"` @@ -443,6 +405,13 @@ type DefaultedRelabelConfig struct { Action RelabelAction `yaml:"action,omitempty"` } +// UnmarshalYAML implements the yaml.Unmarshaler interface. +func (c *RelabelConfig) UnmarshalYAML(unmarshal func(interface{}) error) error { + *c = DefaultRelabelConfig + type plain RelabelConfig + return unmarshal((*plain)(c)) +} + // Regexp encapsulates a regexp.Regexp and makes it YAML marshallable. type Regexp struct { regexp.Regexp diff --git a/config/config_test.go b/config/config_test.go index 61aeb7f84..13a7ee54a 100644 --- a/config/config_test.go +++ b/config/config_test.go @@ -12,8 +12,8 @@ import ( clientmodel "github.com/prometheus/client_golang/model" ) -var expectedConf = &Config{DefaultedConfig{ - GlobalConfig: &GlobalConfig{DefaultedGlobalConfig{ +var expectedConf = &Config{ + GlobalConfig: &GlobalConfig{ ScrapeInterval: Duration(15 * time.Second), ScrapeTimeout: DefaultGlobalConfig.ScrapeTimeout, EvaluationInterval: Duration(30 * time.Second), @@ -22,7 +22,7 @@ var expectedConf = &Config{DefaultedConfig{ "monitor": "codelab", "foo": "bar", }, - }}, + }, RuleFiles: []string{ "first.rules", @@ -31,7 +31,7 @@ var expectedConf = &Config{DefaultedConfig{ }, ScrapeConfigs: []*ScrapeConfig{ - {DefaultedScrapeConfig{ + { JobName: "prometheus", ScrapeInterval: Duration(15 * time.Second), @@ -54,28 +54,28 @@ var expectedConf = &Config{DefaultedConfig{ }, FileSDConfigs: []*FileSDConfig{ - {DefaultedFileSDConfig{ + { Names: []string{"foo/*.slow.json", "foo/*.slow.yml", "single/file.yml"}, RefreshInterval: Duration(10 * time.Minute), - }}, - {DefaultedFileSDConfig{ + }, + { Names: []string{"bar/*.yaml"}, RefreshInterval: Duration(30 * time.Second), - }}, + }, }, RelabelConfigs: []*RelabelConfig{ - {DefaultedRelabelConfig{ + { SourceLabels: clientmodel.LabelNames{"job", "__meta_dns_srv_name"}, TargetLabel: "job", Separator: ";", Regex: &Regexp{*regexp.MustCompile("(.*)some-[regex]$")}, Replacement: "foo-${1}", Action: RelabelReplace, - }}, + }, }, - }}, - {DefaultedScrapeConfig{ + }, + { JobName: "service-x", ScrapeInterval: Duration(50 * time.Second), @@ -89,32 +89,33 @@ var expectedConf = &Config{DefaultedConfig{ Scheme: "https", DNSSDConfigs: []*DNSSDConfig{ - {DefaultedDNSSDConfig{ + { Names: []string{ "first.dns.address.domain.com", "second.dns.address.domain.com", }, RefreshInterval: Duration(15 * time.Second), - }}, - {DefaultedDNSSDConfig{ + }, + { Names: []string{ "first.dns.address.domain.com", }, RefreshInterval: Duration(30 * time.Second), - }}, + }, }, RelabelConfigs: []*RelabelConfig{ - {DefaultedRelabelConfig{ + { SourceLabels: clientmodel.LabelNames{"job"}, Regex: &Regexp{*regexp.MustCompile("(.*)some-[regex]$")}, Separator: ";", Action: RelabelDrop, - }}, + }, }, - }}, + }, }, -}, ""} + original: "", +} func TestLoadConfig(t *testing.T) { c, err := LoadFromFile("testdata/conf.good.yml") diff --git a/retrieval/relabel_test.go b/retrieval/relabel_test.go index 70398a54f..071f8f1f9 100644 --- a/retrieval/relabel_test.go +++ b/retrieval/relabel_test.go @@ -13,7 +13,7 @@ import ( func TestRelabel(t *testing.T) { tests := []struct { input clientmodel.LabelSet - relabel []config.DefaultedRelabelConfig + relabel []*config.RelabelConfig output clientmodel.LabelSet }{ { @@ -22,7 +22,7 @@ func TestRelabel(t *testing.T) { "b": "bar", "c": "baz", }, - relabel: []config.DefaultedRelabelConfig{ + relabel: []*config.RelabelConfig{ { SourceLabels: clientmodel.LabelNames{"a"}, Regex: &config.Regexp{*regexp.MustCompile("f(.*)")}, @@ -45,7 +45,7 @@ func TestRelabel(t *testing.T) { "b": "bar", "c": "baz", }, - relabel: []config.DefaultedRelabelConfig{ + relabel: []*config.RelabelConfig{ { SourceLabels: clientmodel.LabelNames{"a", "b"}, Regex: &config.Regexp{*regexp.MustCompile("^f(.*);(.*)r$")}, @@ -74,7 +74,7 @@ func TestRelabel(t *testing.T) { input: clientmodel.LabelSet{ "a": "foo", }, - relabel: []config.DefaultedRelabelConfig{ + relabel: []*config.RelabelConfig{ { SourceLabels: clientmodel.LabelNames{"a"}, Regex: &config.Regexp{*regexp.MustCompile("o$")}, @@ -94,7 +94,7 @@ func TestRelabel(t *testing.T) { input: clientmodel.LabelSet{ "a": "foo", }, - relabel: []config.DefaultedRelabelConfig{ + relabel: []*config.RelabelConfig{ { SourceLabels: clientmodel.LabelNames{"a"}, Regex: &config.Regexp{*regexp.MustCompile("no-match")}, @@ -109,7 +109,7 @@ func TestRelabel(t *testing.T) { input: clientmodel.LabelSet{ "a": "foo", }, - relabel: []config.DefaultedRelabelConfig{ + relabel: []*config.RelabelConfig{ { SourceLabels: clientmodel.LabelNames{"a"}, Regex: &config.Regexp{*regexp.MustCompile("no-match")}, @@ -122,7 +122,7 @@ func TestRelabel(t *testing.T) { input: clientmodel.LabelSet{ "a": "foo", }, - relabel: []config.DefaultedRelabelConfig{ + relabel: []*config.RelabelConfig{ { SourceLabels: clientmodel.LabelNames{"a"}, Regex: &config.Regexp{*regexp.MustCompile("^f")}, @@ -138,7 +138,7 @@ func TestRelabel(t *testing.T) { input: clientmodel.LabelSet{ "a": "boo", }, - relabel: []config.DefaultedRelabelConfig{ + relabel: []*config.RelabelConfig{ { SourceLabels: clientmodel.LabelNames{"a"}, Regex: &config.Regexp{*regexp.MustCompile("^f")}, @@ -154,11 +154,7 @@ func TestRelabel(t *testing.T) { } for i, test := range tests { - var relabel []*config.RelabelConfig - for _, rl := range test.relabel { - relabel = append(relabel, &config.RelabelConfig{rl}) - } - res, err := Relabel(test.input, relabel...) + res, err := Relabel(test.input, test.relabel...) if err != nil { t.Errorf("Test %d: error relabeling: %s", i+1, err) } diff --git a/retrieval/targetmanager_test.go b/retrieval/targetmanager_test.go index 9cb30783d..886364b5c 100644 --- a/retrieval/targetmanager_test.go +++ b/retrieval/targetmanager_test.go @@ -25,7 +25,7 @@ import ( ) func TestTargetManagerChan(t *testing.T) { - testJob1 := &config.ScrapeConfig{config.DefaultedScrapeConfig{ + testJob1 := &config.ScrapeConfig{ JobName: "test_job1", ScrapeInterval: config.Duration(1 * time.Minute), TargetGroups: []*config.TargetGroup{{ @@ -34,7 +34,7 @@ func TestTargetManagerChan(t *testing.T) { {clientmodel.AddressLabel: "example.com:80"}, }, }}, - }} + } prov1 := &fakeTargetProvider{ sources: []string{"src1", "src2"}, update: make(chan *config.TargetGroup), @@ -154,7 +154,7 @@ func TestTargetManagerChan(t *testing.T) { } func TestTargetManagerConfigUpdate(t *testing.T) { - testJob1 := &config.ScrapeConfig{config.DefaultedScrapeConfig{ + testJob1 := &config.ScrapeConfig{ JobName: "test_job1", ScrapeInterval: config.Duration(1 * time.Minute), TargetGroups: []*config.TargetGroup{{ @@ -163,8 +163,8 @@ func TestTargetManagerConfigUpdate(t *testing.T) { {clientmodel.AddressLabel: "example.com:80"}, }, }}, - }} - testJob2 := &config.ScrapeConfig{config.DefaultedScrapeConfig{ + } + testJob2 := &config.ScrapeConfig{ JobName: "test_job2", ScrapeInterval: config.Duration(1 * time.Minute), TargetGroups: []*config.TargetGroup{ @@ -191,14 +191,14 @@ func TestTargetManagerConfigUpdate(t *testing.T) { }, }, RelabelConfigs: []*config.RelabelConfig{ - {config.DefaultedRelabelConfig{ + { SourceLabels: clientmodel.LabelNames{clientmodel.AddressLabel}, Regex: &config.Regexp{*regexp.MustCompile(`^test\.(.*?):(.*)`)}, Replacement: "foo.${1}:${2}", TargetLabel: clientmodel.AddressLabel, Action: config.RelabelReplace, - }}, - {config.DefaultedRelabelConfig{ + }, + { // Add a new label for example.* targets. SourceLabels: clientmodel.LabelNames{clientmodel.AddressLabel, "boom", "foo"}, Regex: &config.Regexp{*regexp.MustCompile("^example.*?-b([a-z-]+)r$")}, @@ -206,17 +206,17 @@ func TestTargetManagerConfigUpdate(t *testing.T) { Replacement: "$1", Separator: "-", Action: config.RelabelReplace, - }}, - {config.DefaultedRelabelConfig{ + }, + { // Drop an existing label. SourceLabels: clientmodel.LabelNames{"boom"}, Regex: &config.Regexp{*regexp.MustCompile(".*")}, TargetLabel: "boom", Replacement: "", Action: config.RelabelReplace, - }}, + }, }, - }} + } sequence := []struct { scrapeConfigs []*config.ScrapeConfig @@ -275,7 +275,8 @@ func TestTargetManagerConfigUpdate(t *testing.T) { }, }, } - conf := &config.Config{DefaultedConfig: config.DefaultConfig} + conf := &config.Config{} + *conf = config.DefaultConfig targetManager := NewTargetManager(nopAppender{}) targetManager.ApplyConfig(conf)