From 5fbde88919eceb18dc5ebbc2696b3da237073af8 Mon Sep 17 00:00:00 2001 From: Fabian Reinartz Date: Thu, 7 May 2015 10:55:03 +0200 Subject: [PATCH] Switch config to YAML format. --- .../client_golang/model/labelname.go | 17 + Makefile | 11 +- config/Makefile | 22 - config/config.go | 544 ++++++++++-------- config/config.proto | 117 ---- config/config_test.go | 194 +++++-- config/fixtures/empty.conf.input | 0 config/fixtures/full.conf.input | 89 --- config/fixtures/invalid_job_name.conf.input | 3 - config/fixtures/invalid_label_name.conf.input | 10 - .../fixtures/invalid_proto_format.conf.input | 11 - .../invalid_scrape_interval.conf.input | 10 - config/fixtures/minimal.conf.input | 22 - config/fixtures/repeated_job_name.conf.input | 11 - config/fixtures/sample.conf.input | 57 -- config/fixtures/sd_targets.conf.input | 8 - config/generated/config.pb.go | 406 ------------- config/load.go | 53 -- config/load_test.go | 25 - config/testdata/conf.good.yml | 61 ++ config/testdata/jobname.bad.yml | 2 + config/testdata/jobname_dup.bad.yml | 5 + config/testdata/labelname.bad.yml | 3 + config/testdata/regex.bad.yml | 4 + main.go | 2 +- retrieval/relabel.go | 39 +- retrieval/relabel_test.go | 102 ++-- retrieval/target.go | 8 +- retrieval/target_test.go | 8 - retrieval/targetmanager.go | 46 +- retrieval/targetmanager_test.go | 139 +++-- rules/manager/manager.go | 2 +- 32 files changed, 712 insertions(+), 1319 deletions(-) delete mode 100644 config/Makefile delete mode 100644 config/config.proto delete mode 100644 config/fixtures/empty.conf.input delete mode 100644 config/fixtures/full.conf.input delete mode 100644 config/fixtures/invalid_job_name.conf.input delete mode 100644 config/fixtures/invalid_label_name.conf.input delete mode 100644 config/fixtures/invalid_proto_format.conf.input delete mode 100644 config/fixtures/invalid_scrape_interval.conf.input delete mode 100644 config/fixtures/minimal.conf.input delete mode 100644 config/fixtures/repeated_job_name.conf.input delete mode 100644 config/fixtures/sample.conf.input delete mode 100644 config/fixtures/sd_targets.conf.input delete mode 100644 config/generated/config.pb.go delete mode 100644 config/load.go delete mode 100644 config/load_test.go create mode 100644 config/testdata/conf.good.yml create mode 100644 config/testdata/jobname.bad.yml create mode 100644 config/testdata/jobname_dup.bad.yml create mode 100644 config/testdata/labelname.bad.yml create mode 100644 config/testdata/regex.bad.yml diff --git a/Godeps/_workspace/src/github.com/prometheus/client_golang/model/labelname.go b/Godeps/_workspace/src/github.com/prometheus/client_golang/model/labelname.go index 5ea4258aa..36770f70a 100644 --- a/Godeps/_workspace/src/github.com/prometheus/client_golang/model/labelname.go +++ b/Godeps/_workspace/src/github.com/prometheus/client_golang/model/labelname.go @@ -14,6 +14,8 @@ package model import ( + "fmt" + "regexp" "strings" ) @@ -58,10 +60,25 @@ const ( QuantileLabel = "quantile" ) +var labelNameRE = regexp.MustCompile("^[a-zA-Z_][a-zA-Z0-9_]*$") + // A LabelName is a key for a LabelSet or Metric. It has a value associated // therewith. type LabelName string +// UnmarshalYAML implements the yaml.Unmarshaller interface. +func (ln *LabelName) UnmarshalYAML(unmarshal func(interface{}) error) error { + var s string + if err := unmarshal(&s); err != nil { + return err + } + if !labelNameRE.MatchString(s) { + return fmt.Errorf("%q is not a valid label name", s) + } + *ln = LabelName(s) + return nil +} + // LabelNames is a sortable LabelName slice. In implements sort.Interface. type LabelNames []LabelName diff --git a/Makefile b/Makefile index f17aad623..bd732e049 100644 --- a/Makefile +++ b/Makefile @@ -26,7 +26,7 @@ advice: $(GOCC) binary: build -build: config tools web $(GOPATH) +build: tools web $(GOPATH) $(GO) build -o prometheus $(BUILDFLAGS) . docker: build @@ -49,7 +49,7 @@ tag: $(BUILD_PATH)/cache/$(GOPKG): $(CURL) -o $@ -L $(GOURL)/$(GOPKG) -benchmark: config dependencies tools web +benchmark: dependencies tools web $(GO) test $(GO_TEST_FLAGS) -test.run='NONE' -test.bench='.*' -test.benchmem ./... | tee benchmark.txt clean: @@ -62,9 +62,6 @@ clean: -find . -type f -name '*#' -exec rm '{}' ';' -find . -type f -name '.#*' -exec rm '{}' ';' -config: - $(MAKE) -C config - $(SELFLINK): $(GOPATH) ln -s $(MAKEFILE_DIR) $@ @@ -91,7 +88,7 @@ run: binary search_index: godoc -index -write_index -index_files='search_index' -test: config dependencies tools web +test: dependencies tools web $(GO) test $(GO_TEST_FLAGS) ./... tools: dependencies @@ -103,4 +100,4 @@ web: dependencies rules: dependencies $(MAKE) -C rules -.PHONY: advice binary build clean config dependencies documentation format race_condition_binary race_condition_run release run search_index tag tarball test tools +.PHONY: advice binary build clean dependencies documentation format race_condition_binary race_condition_run release run search_index tag tarball test tools diff --git a/config/Makefile b/config/Makefile deleted file mode 100644 index 1a71d02b9..000000000 --- a/config/Makefile +++ /dev/null @@ -1,22 +0,0 @@ -# Copyright 2013 The Prometheus Authors -# Licensed under the Apache License, Version 2.0 (the "License"); -# you may not use this file except in compliance with the License. -# You may obtain a copy of the License at -# -# http://www.apache.org/licenses/LICENSE-2.0 -# -# Unless required by applicable law or agreed to in writing, software -# distributed under the License is distributed on an "AS IS" BASIS, -# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. -# See the License for the specific language governing permissions and -# limitations under the License. - -all: generated/config.pb.go - -SUFFIXES: - -include ../Makefile.INCLUDE - -generated/config.pb.go: config.proto - go get github.com/golang/protobuf/protoc-gen-go - $(PROTOC) --proto_path=$(PREFIX)/include:. --go_out=generated/ config.proto diff --git a/config/config.go b/config/config.go index e8eafa67a..1c501b66f 100644 --- a/config/config.go +++ b/config/config.go @@ -1,269 +1,359 @@ -// Copyright 2013 The Prometheus Authors -// Licensed under the Apache License, Version 2.0 (the "License"); -// you may not use this file except in compliance with the License. -// You may obtain a copy of the License at -// -// http://www.apache.org/licenses/LICENSE-2.0 -// -// Unless required by applicable law or agreed to in writing, software -// distributed under the License is distributed on an "AS IS" BASIS, -// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. -// See the License for the specific language governing permissions and -// limitations under the License. - package config import ( - "errors" "fmt" + "io/ioutil" "regexp" "strings" "time" - "github.com/golang/protobuf/proto" + "gopkg.in/yaml.v2" clientmodel "github.com/prometheus/client_golang/model" "github.com/prometheus/prometheus/utility" - - pb "github.com/prometheus/prometheus/config/generated" ) -var ( - jobNameRE = regexp.MustCompile("^[a-zA-Z_][a-zA-Z0-9_-]*$") - labelNameRE = regexp.MustCompile("^[a-zA-Z_][a-zA-Z0-9_]*$") -) +var jobNameRE = regexp.MustCompile("^[a-zA-Z_][a-zA-Z0-9_-]*$") -// Config encapsulates the configuration of a Prometheus instance. It wraps the -// raw configuration protocol buffer to be able to add custom methods to it. -type Config struct { - // The protobuf containing the actual configuration values. - pb.PrometheusConfig -} - -// String returns an ASCII serialization of the loaded configuration protobuf. -func (c *Config) String() string { - return proto.MarshalTextString(&c.PrometheusConfig) -} - -// validateLabels validates whether label names have the correct format. -func validateLabels(labels *pb.LabelPairs) error { - if labels == nil { - return nil +// Load parses the YAML input s into a Config. +func Load(s string) (*Config, error) { + cfg := &Config{ + original: s, } - for _, label := range labels.Label { - if !labelNameRE.MatchString(label.GetName()) { - return fmt.Errorf("invalid label name '%s'", label.GetName()) - } - } - return nil -} - -// validateHosts validates whether a target group contains valid hosts. -func validateHosts(hosts []string) error { - if hosts == nil { - return nil - } - for _, host := range hosts { - // Make sure that this does not contain any paths or schemes. - // This ensures that old configurations error. - if strings.Contains(host, "/") { - return fmt.Errorf("invalid host '%s', no schemes or paths allowed", host) - } - } - return nil -} - -// Validate checks an entire parsed Config for the validity of its fields. -func (c *Config) Validate() error { - // Check the global configuration section for validity. - global := c.Global - if _, err := utility.StringToDuration(global.GetScrapeInterval()); err != nil { - return fmt.Errorf("invalid global scrape interval: %s", err) - } - if _, err := utility.StringToDuration(global.GetEvaluationInterval()); err != nil { - return fmt.Errorf("invalid rule evaluation interval: %s", err) - } - if err := validateLabels(global.Labels); err != nil { - return fmt.Errorf("invalid global labels: %s", err) - } - - // Check each scrape configuration for validity. - jobNames := map[string]struct{}{} - for _, sc := range c.ScrapeConfigs() { - name := sc.GetJobName() - - if _, ok := jobNames[name]; ok { - return fmt.Errorf("found multiple scrape configs configured with the same job name: %q", name) - } - jobNames[name] = struct{}{} - - if err := sc.Validate(); err != nil { - return fmt.Errorf("error in scrape config %q: %s", name, err) - } - } - - return nil -} - -// GlobalLabels returns the global labels as a LabelSet. -func (c *Config) GlobalLabels() clientmodel.LabelSet { - labels := clientmodel.LabelSet{} - if c.Global != nil && c.Global.Labels != nil { - for _, label := range c.Global.Labels.Label { - labels[clientmodel.LabelName(label.GetName())] = clientmodel.LabelValue(label.GetValue()) - } - } - return labels -} - -// ScrapeConfigs returns all scrape configurations. -func (c *Config) ScrapeConfigs() (cfgs []*ScrapeConfig) { - for _, sc := range c.GetScrapeConfig() { - cfgs = append(cfgs, &ScrapeConfig{*sc}) - } - return -} - -// stringToDuration converts a string to a duration and dies on invalid format. -func stringToDuration(intervalStr string) time.Duration { - duration, err := utility.StringToDuration(intervalStr) + err := yaml.Unmarshal([]byte(s), cfg) if err != nil { - panic(err) + return nil, err } - return duration + return cfg, nil } -// ScrapeInterval gets the default scrape interval for a Config. -func (c *Config) ScrapeInterval() time.Duration { - return stringToDuration(c.Global.GetScrapeInterval()) +// LoadFromFile parses the given YAML file into a Config. +func LoadFromFile(filename string) (*Config, error) { + content, err := ioutil.ReadFile(filename) + if err != nil { + return nil, err + } + return Load(string(content)) } -// EvaluationInterval gets the default evaluation interval for a Config. -func (c *Config) EvaluationInterval() time.Duration { - return stringToDuration(c.Global.GetEvaluationInterval()) +// The defaults applied before parsing the respective config sections. +var ( + // The default top-level configuration. + DefaultConfig = DefaultedConfig{ + GlobalConfig: &GlobalConfig{DefaultGlobalConfig}, + } + + // The default global configuration. + DefaultGlobalConfig = DefaultedGlobalConfig{ + ScrapeInterval: Duration(10 * time.Second), + ScrapeTimeout: Duration(10 * time.Second), + EvaluationInterval: Duration(1 * time.Minute), + } + + // Te default scrape configuration. + DefaultScrapeConfig = DefaultedScrapeConfig{ + // ScrapeTimeout and ScrapeInterval default to the + // configured globals. + MetricsPath: "/metrics", + Scheme: "http", + } + + // The default Relabel configuration. + DefaultRelabelConfig = DefaultedRelabelConfig{ + Action: RelabelReplace, + Separator: ";", + } + + // The default DNS SD configuration. + DefaultDNSConfig = DefaultedDNSConfig{ + RefreshInterval: Duration(30 * time.Second), + } +) + +// Config is the top-level configuration for Prometheus's config files. +type Config struct { + // DefaultedConfig contains the actual fields of Config. + DefaultedConfig `yaml:",inline"` + + // original is the input from which the config was parsed. + original string } -// ScrapeConfig encapsulates a protobuf scrape configuration. +func (c *Config) String() string { + if c.original != "" { + return c.original + } + b, err := yaml.Marshal(c) + if err != nil { + return fmt.Sprintf("", err) + } + return string(b) +} + +// UnmarshalYAML implements the yaml.Unmarshaller interface. +func (c *Config) UnmarshalYAML(unmarshal func(interface{}) error) error { + c.DefaultedConfig = DefaultConfig + if err := unmarshal(&c.DefaultedConfig); err != nil { + return err + } + // Do global overrides and validate unique names. + jobNames := map[string]struct{}{} + for _, scfg := range c.ScrapeConfigs { + if scfg.ScrapeInterval == 0 { + scfg.ScrapeInterval = c.GlobalConfig.ScrapeInterval + } + if scfg.ScrapeTimeout == 0 { + scfg.ScrapeTimeout = c.GlobalConfig.ScrapeTimeout + } + + if _, ok := jobNames[scfg.JobName]; ok { + return fmt.Errorf("found multiple scrape configs with job name %q", scfg.JobName) + } + jobNames[scfg.JobName] = struct{}{} + } + return nil +} + +// DefaultedConfig is a proxy type for Config. +type DefaultedConfig struct { + GlobalConfig *GlobalConfig `yaml:"global_config"` + RuleFiles []string `yaml:"rule_files,omitempty"` + ScrapeConfigs []*ScrapeConfig `yaml:"scrape_configs,omitempty"` +} + +// GlobalConfig configures values that used across other configuration +// objects. +type GlobalConfig struct { + // DefaultedGlobalConfig contains the actual fields for GlobalConfig. + DefaultedGlobalConfig `yaml:",inline"` +} + +// UnmarshalYAML implements the yaml.Unmarshaller 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"` + // The default timeout when scraping targets. + ScrapeTimeout Duration `yaml:"scrape_timeout"` + // How frequently to evaluate rules by default. + EvaluationInterval Duration `yaml:"evaluation_interval"` + + // The labels to add to any timeseries that this Prometheus instance scrapes. + Labels clientmodel.LabelSet `yaml:"labels,omitempty"` +} + +// ScrapeConfig configures a scraping unit for Prometheus. type ScrapeConfig struct { - pb.ScrapeConfig + // DefaultedScrapeConfig contains the actual fields for ScrapeConfig. + DefaultedScrapeConfig `yaml:",inline"` } -// ScrapeInterval gets the scrape interval for the scrape config. -func (c *ScrapeConfig) ScrapeInterval() time.Duration { - return stringToDuration(c.GetScrapeInterval()) -} - -// ScrapeTimeout gets the scrape timeout for the scrape config. -func (c *ScrapeConfig) ScrapeTimeout() time.Duration { - return stringToDuration(c.GetScrapeTimeout()) -} - -// Labels returns a label set for the targets that is implied by the scrape config. -func (c *ScrapeConfig) Labels() clientmodel.LabelSet { - return clientmodel.LabelSet{ - clientmodel.MetricsPathLabel: clientmodel.LabelValue(c.GetMetricsPath()), - clientmodel.JobLabel: clientmodel.LabelValue(c.GetJobName()), +// UnmarshalYAML implements the yaml.Unmarshaller interface. +func (c *ScrapeConfig) UnmarshalYAML(unmarshal func(interface{}) error) error { + c.DefaultedScrapeConfig = DefaultScrapeConfig + err := unmarshal(&c.DefaultedScrapeConfig) + if err != nil { + return err } -} - -// Validate checks the ScrapeConfig for the validity of its fields -func (c *ScrapeConfig) Validate() error { - name := c.GetJobName() - - if !jobNameRE.MatchString(name) { - return fmt.Errorf("invalid job name %q", name) - } - if _, err := utility.StringToDuration(c.GetScrapeInterval()); err != nil { - return fmt.Errorf("invalid scrape interval: %s", err) - } - if _, err := utility.StringToDuration(c.GetScrapeTimeout()); err != nil { - return fmt.Errorf("invalid scrape timeout: %s", err) - } - for _, tgroup := range c.GetTargetGroup() { - if err := validateLabels(tgroup.Labels); err != nil { - return fmt.Errorf("invalid labels: %s", err) - } - if err := validateHosts(tgroup.Target); err != nil { - return fmt.Errorf("invalid targets: %s", err) - } - } - for _, dnscfg := range c.DNSConfigs() { - if err := dnscfg.Validate(); err != nil { - return fmt.Errorf("invalid DNS config: %s", err) - } - } - for _, rlcfg := range c.RelabelConfigs() { - if err := rlcfg.Validate(); err != nil { - return fmt.Errorf("invalid relabelling config: %s", err) - } + if !jobNameRE.MatchString(c.JobName) { + return fmt.Errorf("%q is not a valid job name", c.JobName) } return nil } -// DNSConfigs returns the list of DNS service discovery configurations -// for the scrape config. -func (c *ScrapeConfig) DNSConfigs() []*DNSConfig { - var dnscfgs []*DNSConfig - for _, dc := range c.GetDnsConfig() { - dnscfgs = append(dnscfgs, &DNSConfig{*dc}) - } - return dnscfgs +// DefaultedScrapeConfig is a proxy type for ScrapeConfig. +type DefaultedScrapeConfig 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. + ScrapeInterval Duration `yaml:"scrape_interval"` + // The timeout for scraping targets of this config. + ScrapeTimeout Duration `yaml:"scrape_timeout"` + // The HTTP resource path on which to fetch metrics from targets. + MetricsPath string `yaml:"metrics_path"` + // The URL scheme with which to fetch metrics from targets. + Scheme string `yaml:"scheme"` + + // List of labeled target groups for this job. + TargetGroups []*TargetGroup `yaml:"target_groups,omitempty"` + // List of DNS service discovery configurations. + DNSConfigs []*DNSConfig `yaml:"dns_configs,omitempty"` + // List of relabel configurations. + RelabelConfigs []*RelabelConfig `yaml:"relabel_configs,omitempty"` } -// RelabelConfigs returns the relabel configs of the scrape config. -func (c *ScrapeConfig) RelabelConfigs() []*RelabelConfig { - var rlcfgs []*RelabelConfig - for _, rc := range c.GetRelabelConfig() { - rlcfgs = append(rlcfgs, &RelabelConfig{*rc}) - } - return rlcfgs -} - -// DNSConfig encapsulates the protobuf configuration object for DNS based -// service discovery. -type DNSConfig struct { - pb.DNSConfig -} - -// Validate checks the DNSConfig for the validity of its fields. -func (c *DNSConfig) Validate() error { - if _, err := utility.StringToDuration(c.GetRefreshInterval()); err != nil { - return fmt.Errorf("invalid refresh interval: %s", err) - } - return nil -} - -// RefreshInterval gets the the refresh interval for DNS service discovery. -func (c *DNSConfig) RefreshInterval() time.Duration { - return stringToDuration(c.GetRefreshInterval()) -} - -// RelabelConfig encapsulates the protobuf configuration object for relabeling. -type RelabelConfig struct { - pb.RelabelConfig -} - -// Validate checks the RelabelConfig for the validity of its fields. -func (c *RelabelConfig) Validate() error { - if len(c.GetSourceLabel()) == 0 { - return errors.New("at least one source label is required") - } - return nil -} - -// TargetGroup is derived from a protobuf TargetGroup and attaches a source to it -// that identifies the origin of the group. +// A labeled group of targets to scrape for a job. type TargetGroup struct { - // Source is an identifier that describes a group of targets. - Source string - // Labels is a set of labels that is common across all targets in the group. - Labels clientmodel.LabelSet // Targets is a list of targets identified by a label set. Each target is // uniquely identifiable in the group by its address label. - Targets []clientmodel.LabelSet + Targets []clientmodel.LabelSet `yaml:"targets,omitempty" json:"targets,omitempty"` + // Labels is a set of labels that is common across all targets in the group. + Labels clientmodel.LabelSet `yaml:"labels,omitempty" json:"labels,omitempty"` + + // Source is an identifier that describes a group of targets. + Source string `yaml:"-", json:"-"` } func (tg *TargetGroup) String() string { return tg.Source } + +// UnmarshalYAML implements the yaml.Unmarshaller interface. +func (tg *TargetGroup) UnmarshalYAML(unmarshal func(interface{}) error) error { + g := struct { + Targets []string `yaml:"targets"` + Labels clientmodel.LabelSet `yaml:"labels"` + }{} + if err := unmarshal(&g); err != nil { + return err + } + tg.Targets = make([]clientmodel.LabelSet, 0, len(g.Targets)) + for _, t := range g.Targets { + if strings.Contains(t, "/") { + return fmt.Errorf("%q is not a valid hostname", t) + } + tg.Targets = append(tg.Targets, clientmodel.LabelSet{ + clientmodel.AddressLabel: clientmodel.LabelValue(t), + }) + } + tg.Labels = g.Labels + return nil +} + +// DNSConfig is the configuration for DNS based service discovery. +type DNSConfig struct { + // DefaultedDNSConfig contains the actual fields for DNSConfig. + DefaultedDNSConfig `yaml:",inline"` +} + +// UnmarshalYAML implements the yaml.Unmarshaller interface. +func (c *DNSConfig) UnmarshalYAML(unmarshal func(interface{}) error) error { + c.DefaultedDNSConfig = DefaultDNSConfig + err := unmarshal(&c.DefaultedDNSConfig) + if err != nil { + return err + } + if len(c.Names) == 0 { + return fmt.Errorf("DNS config must contain at least one SRV server name") + } + return nil +} + +// DefaultedDNSConfig is a proxy type for DNSConfig. +type DefaultedDNSConfig struct { + Names []string `yaml:"names"` + RefreshInterval Duration `yaml:"refresh_interval"` +} + +// RelabelAction is the action to be performed on relabeling. +type RelabelAction string + +const ( + // Performs a regex replacement. + RelabelReplace RelabelAction = "replace" + // Drops targets for which the input does not match the regex. + RelabelKeep = "keep" + // Drops targets for which the input does match the regex. + RelabelDrop = "drop" +) + +// UnmarshalYAML implements the yaml.Unmarshaller interface. +func (a *RelabelAction) UnmarshalYAML(unmarshal func(interface{}) error) error { + var s string + if err := unmarshal(&s); err != nil { + return err + } + switch act := RelabelAction(strings.ToLower(s)); act { + case RelabelReplace, RelabelKeep, RelabelDrop: + *a = act + return nil + } + return fmt.Errorf("unknown relabel action %q", s) +} + +// 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.Unmarshaller 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"` + // Separator is the string between concatenated values from the source labels. + Separator string `yaml:"separator"` + // Regex against which the concatenation is matched. + Regex *Regexp `yaml:"regex"` + // The label to which the resulting string is written in a replacement. + TargetLabel clientmodel.LabelName `yaml:"target_label,omitempty"` + // Replacement is the regex replacement pattern to be used. + Replacement string `yaml:"replacement,omitempty"` + // Action is the action to be performed for the relabeling. + Action RelabelAction `yaml:"action"` +} + +// Regexp encapsulates a regexp.Regexp and makes it YAML marshallable. +type Regexp struct { + regexp.Regexp +} + +// UnmarshalYAML implements the yaml.Unmarshaller interface. +func (re *Regexp) UnmarshalYAML(unmarshal func(interface{}) error) error { + var s string + if err := unmarshal(&s); err != nil { + return err + } + regex, err := regexp.Compile(s) + if err != nil { + return err + } + re.Regexp = *regex + return nil +} + +// MarshalYAML implements the yaml.Marshaller interface. +func (re *Regexp) MarshalYAML() (interface{}, error) { + return re.String(), nil +} + +// Duration encapsulates a time.Duration and makes it YAML marshallable. +// +// TODO(fabxc): Since we have custom types for most things, including timestamps, +// we might want to move this into our model as well, eventually. +type Duration time.Duration + +// UnmarshalYAML implements the yaml.Unmarshaller interface. +func (d *Duration) UnmarshalYAML(unmarshal func(interface{}) error) error { + var s string + if err := unmarshal(&s); err != nil { + return err + } + dur, err := utility.StringToDuration(s) + if err != nil { + return err + } + *d = Duration(dur) + return nil +} + +// MarshalYAML implements the yaml.Marshaller interface. +func (d Duration) MarshalYAML() (interface{}, error) { + return utility.DurationToString(time.Duration(d)), nil +} diff --git a/config/config.proto b/config/config.proto deleted file mode 100644 index c0d534449..000000000 --- a/config/config.proto +++ /dev/null @@ -1,117 +0,0 @@ -// Copyright 2013 The Prometheus Authors -// Licensed under the Apache License, Version 2.0 (the "License"); -// you may not use this file except in compliance with the License. -// You may obtain a copy of the License at -// -// http://www.apache.org/licenses/LICENSE-2.0 -// -// Unless required by applicable law or agreed to in writing, software -// distributed under the License is distributed on an "AS IS" BASIS, -// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. -// See the License for the specific language governing permissions and -// limitations under the License. - -package io.prometheus; - -// A label/value pair suitable for attaching to timeseries. -message LabelPair { - // The name of the label. Must adhere to the regex "[a-zA-Z_][a-zA-Z0-9_]*". - optional string name = 1; - // The value of the label. May contain any characters. - optional string value = 2; -} - -// A set of label/value pairs. -message LabelPairs { - repeated LabelPair label = 1; -} - -// The global Prometheus configuration section. -message GlobalConfig { - // How frequently to scrape targets by default. Must be a valid Prometheus - // duration string in the form "[0-9]+[smhdwy]". - optional string scrape_interval = 1 [default = "1m"]; - // How frequently to evaluate rules by default. Must be a valid Prometheus - // duration string in the form "[0-9]+[smhdwy]". - optional string evaluation_interval = 2 [default = "1m"]; - // The labels to add to any timeseries that this Prometheus instance scrapes. - optional LabelPairs labels = 3; - // The list of file names of rule files to load. - repeated string rule_file = 4; -} - -// A labeled group of targets to scrape for a job. -message TargetGroup { - // The list of endpoints to scrape via HTTP. - repeated string target = 1; - // The labels to add to any timeseries scraped for this target group. - optional LabelPairs labels = 2; -} - -// The configuration for DNS based service discovery. -message DNSConfig { - // The list of DNS-SD service names pointing to SRV records - // containing endpoint information. - repeated string name = 1; - // Discovery refresh period when using DNS-SD to discover targets. Must be a - // valid Prometheus duration string in the form "[0-9]+[smhdwy]". - optional string refresh_interval = 2 [default = "30s"]; -} - -// The configuration for relabeling of target label sets. -message RelabelConfig { - // A list of labels from which values are taken and concatenated - // with the configured separator in order. - repeated string source_label = 1; - // Regex against which the concatenation is matched. - required string regex = 2; - // The label to which the resulting string is written in a replacement. - optional string target_label = 3; - // Replacement is the regex replacement pattern to be used. - optional string replacement = 4; - // Separator is the string between concatenated values from the source labels. - optional string separator = 5 [default = ";"]; - - // Action is the action to be performed for the relabeling. - enum Action { - REPLACE = 0; // Performs a regex replacement. - KEEP = 1; // Drops targets for which the input does not match the regex. - DROP = 2; // Drops targets for which the input does match the regex. - } - optional Action action = 6 [default = REPLACE]; -} - -// The configuration for a Prometheus job to scrape. -// -// The next field no. is 11. -message ScrapeConfig { - // The job name. Must adhere to the regex "[a-zA-Z_][a-zA-Z0-9_-]*". - required string job_name = 1; - // How frequently to scrape targets from this job. Overrides the global - // default. Must be a valid Prometheus duration string in the form - // "[0-9]+[smhdwy]". - optional string scrape_interval = 2; - // Per-target timeout when scraping this job. Must be a valid Prometheus - // duration string in the form "[0-9]+[smhdwy]". - optional string scrape_timeout = 7 [default = "10s"]; - // List of DNS service discovery configurations. - repeated DNSConfig dns_config = 9; - // List of labeled target groups for this job. - repeated TargetGroup target_group = 5; - // List of relabel configurations. - repeated RelabelConfig relabel_config = 10; - // The HTTP resource path on which to fetch metrics from targets. - optional string metrics_path = 6 [default = "/metrics"]; - // The URL scheme with which to fetch metrics from targets. - optional string scheme = 8 [default = "http"]; -} - -// The top-level Prometheus configuration. -message PrometheusConfig { - // Global Prometheus configuration options. If omitted, an empty global - // configuration with default values (see GlobalConfig definition) will be - // created. - optional GlobalConfig global = 1; - // The list of scrape configs. - repeated ScrapeConfig scrape_config = 3; -} diff --git a/config/config_test.go b/config/config_test.go index 80dfb3028..f4c1fa721 100644 --- a/config/config_test.go +++ b/config/config_test.go @@ -1,80 +1,152 @@ -// Copyright 2013 The Prometheus Authors -// Licensed under the Apache License, Version 2.0 (the "License"); -// you may not use this file except in compliance with the License. -// You may obtain a copy of the License at -// -// http://www.apache.org/licenses/LICENSE-2.0 -// -// Unless required by applicable law or agreed to in writing, software -// distributed under the License is distributed on an "AS IS" BASIS, -// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. -// See the License for the specific language governing permissions and -// limitations under the License. - package config import ( - "path" + "reflect" + "regexp" "strings" "testing" + "time" + + "gopkg.in/yaml.v2" + + clientmodel "github.com/prometheus/client_golang/model" ) -var fixturesPath = "fixtures" +var expectedConf = &Config{DefaultedConfig{ + GlobalConfig: &GlobalConfig{DefaultedGlobalConfig{ + ScrapeInterval: Duration(15 * time.Second), + ScrapeTimeout: DefaultGlobalConfig.ScrapeTimeout, + EvaluationInterval: Duration(30 * time.Second), -var configTests = []struct { - inputFile string - shouldFail bool - errContains string + Labels: clientmodel.LabelSet{ + "monitor": "codelab", + "foo": "bar", + }, + }}, + + RuleFiles: []string{ + "first.rules", + "second.rules", + }, + + ScrapeConfigs: []*ScrapeConfig{ + {DefaultedScrapeConfig{ + JobName: "prometheus", + + ScrapeInterval: Duration(15 * time.Second), + ScrapeTimeout: DefaultGlobalConfig.ScrapeTimeout, + + MetricsPath: DefaultScrapeConfig.MetricsPath, + Scheme: DefaultScrapeConfig.Scheme, + + TargetGroups: []*TargetGroup{ + { + Targets: []clientmodel.LabelSet{ + {clientmodel.AddressLabel: "localhost:9090"}, + {clientmodel.AddressLabel: "localhost:9191"}, + }, + Labels: clientmodel.LabelSet{ + "my": "label", + "your": "label", + }, + }, + }, + + 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), + ScrapeTimeout: Duration(5 * time.Second), + + MetricsPath: "/my_path", + Scheme: "http", + + DNSConfigs: []*DNSConfig{ + {DefaultedDNSConfig{ + Names: []string{ + "first.dns.address.domain.com", + "second.dns.address.domain.com", + }, + RefreshInterval: Duration(15 * time.Second), + }}, + {DefaultedDNSConfig{ + 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, + }}, + }, + }}, + }, +}, ""} + +func TestLoadConfig(t *testing.T) { + c, err := LoadFromFile("testdata/conf.good.yml") + if err != nil { + t.Errorf("Error parsing %s: %s", "testdata/conf.good.yml", err) + } + bgot, err := yaml.Marshal(c) + if err != nil { + t.Errorf("%s", err) + } + bexp, err := yaml.Marshal(expectedConf) + if err != nil { + t.Errorf("%s", err) + } + expectedConf.original = c.original + + 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) + } +} + +var expectedErrors = []struct { + filename string + errMsg string }{ { - inputFile: "minimal.conf.input", + filename: "jobname.bad.yml", + errMsg: `"prom^etheus" is not a valid job name`, }, { - inputFile: "sample.conf.input", + filename: "jobname_dup.bad.yml", + errMsg: `found multiple scrape configs with job name "prometheus"`, }, { - inputFile: "empty.conf.input", + filename: "labelname.bad.yml", + errMsg: `"not$allowed" is not a valid label name`, }, { - inputFile: "sd_targets.conf.input", - }, { - inputFile: "full.conf.input", - }, { - inputFile: "invalid_proto_format.conf.input", - shouldFail: true, - errContains: "unknown field name", - }, - { - inputFile: "invalid_scrape_interval.conf.input", - shouldFail: true, - errContains: "invalid global scrape interval", - }, - { - inputFile: "invalid_job_name.conf.input", - shouldFail: true, - errContains: "invalid job name", - }, - { - inputFile: "invalid_label_name.conf.input", - shouldFail: true, - errContains: "invalid label name", - }, - { - inputFile: "repeated_job_name.conf.input", - shouldFail: true, - errContains: "found multiple scrape configs configured with the same job name: \"testjob1\"", + filename: "regex.bad.yml", + errMsg: "error parsing regexp", }, } -func TestConfigs(t *testing.T) { - for i, configTest := range configTests { - _, err := LoadFromFile(path.Join(fixturesPath, configTest.inputFile)) - - if err != nil { - if !configTest.shouldFail { - t.Fatalf("%d. Error parsing config %v: %v", i, configTest.inputFile, err) - } else { - if !strings.Contains(err.Error(), configTest.errContains) { - t.Fatalf("%d. Expected error containing '%v', got: %v", i, configTest.errContains, err) - } - } +func TestBadConfigs(t *testing.T) { + for _, ee := range expectedErrors { + _, err := LoadFromFile("testdata/" + ee.filename) + if err == nil { + t.Errorf("Expected error parsing %s but got none", ee.filename) + } + if !strings.Contains(err.Error(), ee.errMsg) { + t.Errorf("Expected error for %s to contain %q but got: %s", ee.filename, ee.errMsg, err) } } } diff --git a/config/fixtures/empty.conf.input b/config/fixtures/empty.conf.input deleted file mode 100644 index e69de29bb..000000000 diff --git a/config/fixtures/full.conf.input b/config/fixtures/full.conf.input deleted file mode 100644 index 5e5b34092..000000000 --- a/config/fixtures/full.conf.input +++ /dev/null @@ -1,89 +0,0 @@ -global < - scrape_interval: "30s" - evaluation_interval: "30s" - labels: < - label: < - name: "monitor" - value: "test" - > - label: < - name: "more" - value: "test" - > - > - rule_file: "prometheus.rules" - rule_file: "prometheus.more.rules" -> - -scrape_config: < - job_name: "prometheus" - scrape_interval: "15s" - metrics_path: "/metrics" - scheme: "http" - - target_group: < - target: "localhost:9090" - > -> - -scrape_config: < - job_name: "myjob" - scrape_interval: "15s" - metrics_path: "/metrics" - scheme: "http" - - dns_config: < - name: "first.srv.name" - name: "second.srv.name" - refresh_interval: "1h" - > - - dns_config: < - name: "first2.srv.name" - name: "second2.srv.name" - refresh_interval: "1m" - > - - relabel_config: < - source_label: "l1" - source_label: "l2" - regex: "^foobar.*$" - target_label: "l3" - replacement: "static" - > - relabel_config: < - source_label: "l4" - regex: "^foobar.*$" - action: DROP - > - relabel_config: < - source_label: "l4" - regex: "^foobar.*$" - action: KEEP - > - - target_group: < - target: "localhost:9090" - target: "localhost:9091" - labels: < - label: < - name: "tg1" - value: "tg1" - > - > - > - target_group: < - target: "my.domain:9090" - target: "my.domain:9091" - labels: < - label: < - name: "tg2" - value: "tg2" - > - label: < - name: "tg2_1" - value: "tg2_1" - > - > - > -> diff --git a/config/fixtures/invalid_job_name.conf.input b/config/fixtures/invalid_job_name.conf.input deleted file mode 100644 index dcebbccb4..000000000 --- a/config/fixtures/invalid_job_name.conf.input +++ /dev/null @@ -1,3 +0,0 @@ -scrape_config: < - job_name: "1testjob" -> diff --git a/config/fixtures/invalid_label_name.conf.input b/config/fixtures/invalid_label_name.conf.input deleted file mode 100644 index f85538649..000000000 --- a/config/fixtures/invalid_label_name.conf.input +++ /dev/null @@ -1,10 +0,0 @@ -global < - scrape_interval: "30s" - evaluation_interval: "30s" - labels: < - label: < - name: "monitor-test" - value: "test" - > - > -> diff --git a/config/fixtures/invalid_proto_format.conf.input b/config/fixtures/invalid_proto_format.conf.input deleted file mode 100644 index ba311005b..000000000 --- a/config/fixtures/invalid_proto_format.conf.input +++ /dev/null @@ -1,11 +0,0 @@ -global < - scrape_interval: "30s" - evaluation_interval: "30s" - unknown_field: "foo" - labels: < - label: < - name: "monitor" - value: "test" - > - > -> diff --git a/config/fixtures/invalid_scrape_interval.conf.input b/config/fixtures/invalid_scrape_interval.conf.input deleted file mode 100644 index 537d50996..000000000 --- a/config/fixtures/invalid_scrape_interval.conf.input +++ /dev/null @@ -1,10 +0,0 @@ -global < - scrape_interval: "30" - evaluation_interval: "30s" - labels: < - label: < - name: "monitor" - value: "test" - > - > -> diff --git a/config/fixtures/minimal.conf.input b/config/fixtures/minimal.conf.input deleted file mode 100644 index 9a436411f..000000000 --- a/config/fixtures/minimal.conf.input +++ /dev/null @@ -1,22 +0,0 @@ -global < - scrape_interval: "30s" - evaluation_interval: "30s" - labels: < - label: < - name: "monitor" - value: "test" - > - > - rule_file: "prometheus.rules" -> - -scrape_config: < - job_name: "prometheus" - scrape_interval: "15s" - metrics_path: "/metrics" - scheme: "http" - - target_group: < - target: "localhost:9090" - > -> diff --git a/config/fixtures/repeated_job_name.conf.input b/config/fixtures/repeated_job_name.conf.input deleted file mode 100644 index 3ca4fa468..000000000 --- a/config/fixtures/repeated_job_name.conf.input +++ /dev/null @@ -1,11 +0,0 @@ -scrape_config: < - job_name: "testjob1" -> - -scrape_config: < - job_name: "testjob2" -> - -scrape_config: < - job_name: "testjob1" -> diff --git a/config/fixtures/sample.conf.input b/config/fixtures/sample.conf.input deleted file mode 100644 index 6bd42873f..000000000 --- a/config/fixtures/sample.conf.input +++ /dev/null @@ -1,57 +0,0 @@ -global < - scrape_interval: "30s" - evaluation_interval: "30s" - labels: < - label: < - name: "monitor" - value: "test" - > - > - rule_file: "prometheus.rules" -> - -scrape_config: < - job_name: "prometheus" - scrape_interval: "15s" - - target_group: < - target: "localhost:9090" - labels: < - label: < - name: "group" - value: "canary" - > - > - > -> - -scrape_config: < - job_name: "random" - scrape_interval: "30s" - - target_group: < - target: "random.com:8080" - target: "random.com:8081" - target: "random.com:8082" - target: "random.com:8083" - target: "random.com:8084" - - labels: < - label: < - name: "group" - value: "production" - > - > - > - target_group: < - target: "random.com:8085" - target: "random.com:8086" - - labels: < - label: < - name: "group" - value: "canary" - > - > - > -> diff --git a/config/fixtures/sd_targets.conf.input b/config/fixtures/sd_targets.conf.input deleted file mode 100644 index 2f9acd68e..000000000 --- a/config/fixtures/sd_targets.conf.input +++ /dev/null @@ -1,8 +0,0 @@ -scrape_config: < - job_name: "testjob" - dns_config: < - name: "sd_name" - name: "sd_name2" - refresh_interval: "15s" - > -> diff --git a/config/generated/config.pb.go b/config/generated/config.pb.go deleted file mode 100644 index 6898a9af8..000000000 --- a/config/generated/config.pb.go +++ /dev/null @@ -1,406 +0,0 @@ -// Code generated by protoc-gen-go. -// source: config.proto -// DO NOT EDIT! - -/* -Package io_prometheus is a generated protocol buffer package. - -It is generated from these files: - config.proto - -It has these top-level messages: - LabelPair - LabelPairs - GlobalConfig - TargetGroup - DNSConfig - RelabelConfig - ScrapeConfig - PrometheusConfig -*/ -package io_prometheus - -import proto "github.com/golang/protobuf/proto" -import math "math" - -// Reference imports to suppress errors if they are not otherwise used. -var _ = proto.Marshal -var _ = math.Inf - -// Action is the action to be performed for the relabeling. -type RelabelConfig_Action int32 - -const ( - RelabelConfig_REPLACE RelabelConfig_Action = 0 - RelabelConfig_KEEP RelabelConfig_Action = 1 - RelabelConfig_DROP RelabelConfig_Action = 2 -) - -var RelabelConfig_Action_name = map[int32]string{ - 0: "REPLACE", - 1: "KEEP", - 2: "DROP", -} -var RelabelConfig_Action_value = map[string]int32{ - "REPLACE": 0, - "KEEP": 1, - "DROP": 2, -} - -func (x RelabelConfig_Action) Enum() *RelabelConfig_Action { - p := new(RelabelConfig_Action) - *p = x - return p -} -func (x RelabelConfig_Action) String() string { - return proto.EnumName(RelabelConfig_Action_name, int32(x)) -} -func (x *RelabelConfig_Action) UnmarshalJSON(data []byte) error { - value, err := proto.UnmarshalJSONEnum(RelabelConfig_Action_value, data, "RelabelConfig_Action") - if err != nil { - return err - } - *x = RelabelConfig_Action(value) - return nil -} - -// A label/value pair suitable for attaching to timeseries. -type LabelPair struct { - // The name of the label. Must adhere to the regex "[a-zA-Z_][a-zA-Z0-9_]*". - Name *string `protobuf:"bytes,1,opt,name=name" json:"name,omitempty"` - // The value of the label. May contain any characters. - Value *string `protobuf:"bytes,2,opt,name=value" json:"value,omitempty"` - XXX_unrecognized []byte `json:"-"` -} - -func (m *LabelPair) Reset() { *m = LabelPair{} } -func (m *LabelPair) String() string { return proto.CompactTextString(m) } -func (*LabelPair) ProtoMessage() {} - -func (m *LabelPair) GetName() string { - if m != nil && m.Name != nil { - return *m.Name - } - return "" -} - -func (m *LabelPair) GetValue() string { - if m != nil && m.Value != nil { - return *m.Value - } - return "" -} - -// A set of label/value pairs. -type LabelPairs struct { - Label []*LabelPair `protobuf:"bytes,1,rep,name=label" json:"label,omitempty"` - XXX_unrecognized []byte `json:"-"` -} - -func (m *LabelPairs) Reset() { *m = LabelPairs{} } -func (m *LabelPairs) String() string { return proto.CompactTextString(m) } -func (*LabelPairs) ProtoMessage() {} - -func (m *LabelPairs) GetLabel() []*LabelPair { - if m != nil { - return m.Label - } - return nil -} - -// The global Prometheus configuration section. -type GlobalConfig struct { - // How frequently to scrape targets by default. Must be a valid Prometheus - // duration string in the form "[0-9]+[smhdwy]". - ScrapeInterval *string `protobuf:"bytes,1,opt,name=scrape_interval,def=1m" json:"scrape_interval,omitempty"` - // How frequently to evaluate rules by default. Must be a valid Prometheus - // duration string in the form "[0-9]+[smhdwy]". - EvaluationInterval *string `protobuf:"bytes,2,opt,name=evaluation_interval,def=1m" json:"evaluation_interval,omitempty"` - // The labels to add to any timeseries that this Prometheus instance scrapes. - Labels *LabelPairs `protobuf:"bytes,3,opt,name=labels" json:"labels,omitempty"` - // The list of file names of rule files to load. - RuleFile []string `protobuf:"bytes,4,rep,name=rule_file" json:"rule_file,omitempty"` - XXX_unrecognized []byte `json:"-"` -} - -func (m *GlobalConfig) Reset() { *m = GlobalConfig{} } -func (m *GlobalConfig) String() string { return proto.CompactTextString(m) } -func (*GlobalConfig) ProtoMessage() {} - -const Default_GlobalConfig_ScrapeInterval string = "1m" -const Default_GlobalConfig_EvaluationInterval string = "1m" - -func (m *GlobalConfig) GetScrapeInterval() string { - if m != nil && m.ScrapeInterval != nil { - return *m.ScrapeInterval - } - return Default_GlobalConfig_ScrapeInterval -} - -func (m *GlobalConfig) GetEvaluationInterval() string { - if m != nil && m.EvaluationInterval != nil { - return *m.EvaluationInterval - } - return Default_GlobalConfig_EvaluationInterval -} - -func (m *GlobalConfig) GetLabels() *LabelPairs { - if m != nil { - return m.Labels - } - return nil -} - -func (m *GlobalConfig) GetRuleFile() []string { - if m != nil { - return m.RuleFile - } - return nil -} - -// A labeled group of targets to scrape for a job. -type TargetGroup struct { - // The list of endpoints to scrape via HTTP. - Target []string `protobuf:"bytes,1,rep,name=target" json:"target,omitempty"` - // The labels to add to any timeseries scraped for this target group. - Labels *LabelPairs `protobuf:"bytes,2,opt,name=labels" json:"labels,omitempty"` - XXX_unrecognized []byte `json:"-"` -} - -func (m *TargetGroup) Reset() { *m = TargetGroup{} } -func (m *TargetGroup) String() string { return proto.CompactTextString(m) } -func (*TargetGroup) ProtoMessage() {} - -func (m *TargetGroup) GetTarget() []string { - if m != nil { - return m.Target - } - return nil -} - -func (m *TargetGroup) GetLabels() *LabelPairs { - if m != nil { - return m.Labels - } - return nil -} - -// The configuration for DNS based service discovery. -type DNSConfig struct { - // The list of DNS-SD service names pointing to SRV records - // containing endpoint information. - Name []string `protobuf:"bytes,1,rep,name=name" json:"name,omitempty"` - // Discovery refresh period when using DNS-SD to discover targets. Must be a - // valid Prometheus duration string in the form "[0-9]+[smhdwy]". - RefreshInterval *string `protobuf:"bytes,2,opt,name=refresh_interval,def=30s" json:"refresh_interval,omitempty"` - XXX_unrecognized []byte `json:"-"` -} - -func (m *DNSConfig) Reset() { *m = DNSConfig{} } -func (m *DNSConfig) String() string { return proto.CompactTextString(m) } -func (*DNSConfig) ProtoMessage() {} - -const Default_DNSConfig_RefreshInterval string = "30s" - -func (m *DNSConfig) GetName() []string { - if m != nil { - return m.Name - } - return nil -} - -func (m *DNSConfig) GetRefreshInterval() string { - if m != nil && m.RefreshInterval != nil { - return *m.RefreshInterval - } - return Default_DNSConfig_RefreshInterval -} - -// The configuration for relabeling of target label sets. -type RelabelConfig struct { - // A list of labels from which values are taken and concatenated - // with the configured separator in order. - SourceLabel []string `protobuf:"bytes,1,rep,name=source_label" json:"source_label,omitempty"` - // Regex against which the concatenation is matched. - Regex *string `protobuf:"bytes,2,req,name=regex" json:"regex,omitempty"` - // The label to which the resulting string is written in a replacement. - TargetLabel *string `protobuf:"bytes,3,opt,name=target_label" json:"target_label,omitempty"` - // Replacement is the regex replacement pattern to be used. - Replacement *string `protobuf:"bytes,4,opt,name=replacement" json:"replacement,omitempty"` - // Separator is the string between concatenated values from the source labels. - Separator *string `protobuf:"bytes,5,opt,name=separator,def=;" json:"separator,omitempty"` - Action *RelabelConfig_Action `protobuf:"varint,6,opt,name=action,enum=io.prometheus.RelabelConfig_Action,def=0" json:"action,omitempty"` - XXX_unrecognized []byte `json:"-"` -} - -func (m *RelabelConfig) Reset() { *m = RelabelConfig{} } -func (m *RelabelConfig) String() string { return proto.CompactTextString(m) } -func (*RelabelConfig) ProtoMessage() {} - -const Default_RelabelConfig_Separator string = ";" -const Default_RelabelConfig_Action RelabelConfig_Action = RelabelConfig_REPLACE - -func (m *RelabelConfig) GetSourceLabel() []string { - if m != nil { - return m.SourceLabel - } - return nil -} - -func (m *RelabelConfig) GetRegex() string { - if m != nil && m.Regex != nil { - return *m.Regex - } - return "" -} - -func (m *RelabelConfig) GetTargetLabel() string { - if m != nil && m.TargetLabel != nil { - return *m.TargetLabel - } - return "" -} - -func (m *RelabelConfig) GetReplacement() string { - if m != nil && m.Replacement != nil { - return *m.Replacement - } - return "" -} - -func (m *RelabelConfig) GetSeparator() string { - if m != nil && m.Separator != nil { - return *m.Separator - } - return Default_RelabelConfig_Separator -} - -func (m *RelabelConfig) GetAction() RelabelConfig_Action { - if m != nil && m.Action != nil { - return *m.Action - } - return Default_RelabelConfig_Action -} - -// The configuration for a Prometheus job to scrape. -// -// The next field no. is 11. -type ScrapeConfig struct { - // The job name. Must adhere to the regex "[a-zA-Z_][a-zA-Z0-9_-]*". - JobName *string `protobuf:"bytes,1,req,name=job_name" json:"job_name,omitempty"` - // How frequently to scrape targets from this job. Overrides the global - // default. Must be a valid Prometheus duration string in the form - // "[0-9]+[smhdwy]". - ScrapeInterval *string `protobuf:"bytes,2,opt,name=scrape_interval" json:"scrape_interval,omitempty"` - // Per-target timeout when scraping this job. Must be a valid Prometheus - // duration string in the form "[0-9]+[smhdwy]". - ScrapeTimeout *string `protobuf:"bytes,7,opt,name=scrape_timeout,def=10s" json:"scrape_timeout,omitempty"` - // List of DNS service discovery configurations. - DnsConfig []*DNSConfig `protobuf:"bytes,9,rep,name=dns_config" json:"dns_config,omitempty"` - // List of labeled target groups for this job. - TargetGroup []*TargetGroup `protobuf:"bytes,5,rep,name=target_group" json:"target_group,omitempty"` - // List of relabel configurations. - RelabelConfig []*RelabelConfig `protobuf:"bytes,10,rep,name=relabel_config" json:"relabel_config,omitempty"` - // The HTTP resource path on which to fetch metrics from targets. - MetricsPath *string `protobuf:"bytes,6,opt,name=metrics_path,def=/metrics" json:"metrics_path,omitempty"` - // The URL scheme with which to fetch metrics from targets. - Scheme *string `protobuf:"bytes,8,opt,name=scheme,def=http" json:"scheme,omitempty"` - XXX_unrecognized []byte `json:"-"` -} - -func (m *ScrapeConfig) Reset() { *m = ScrapeConfig{} } -func (m *ScrapeConfig) String() string { return proto.CompactTextString(m) } -func (*ScrapeConfig) ProtoMessage() {} - -const Default_ScrapeConfig_ScrapeTimeout string = "10s" -const Default_ScrapeConfig_MetricsPath string = "/metrics" -const Default_ScrapeConfig_Scheme string = "http" - -func (m *ScrapeConfig) GetJobName() string { - if m != nil && m.JobName != nil { - return *m.JobName - } - return "" -} - -func (m *ScrapeConfig) GetScrapeInterval() string { - if m != nil && m.ScrapeInterval != nil { - return *m.ScrapeInterval - } - return "" -} - -func (m *ScrapeConfig) GetScrapeTimeout() string { - if m != nil && m.ScrapeTimeout != nil { - return *m.ScrapeTimeout - } - return Default_ScrapeConfig_ScrapeTimeout -} - -func (m *ScrapeConfig) GetDnsConfig() []*DNSConfig { - if m != nil { - return m.DnsConfig - } - return nil -} - -func (m *ScrapeConfig) GetTargetGroup() []*TargetGroup { - if m != nil { - return m.TargetGroup - } - return nil -} - -func (m *ScrapeConfig) GetRelabelConfig() []*RelabelConfig { - if m != nil { - return m.RelabelConfig - } - return nil -} - -func (m *ScrapeConfig) GetMetricsPath() string { - if m != nil && m.MetricsPath != nil { - return *m.MetricsPath - } - return Default_ScrapeConfig_MetricsPath -} - -func (m *ScrapeConfig) GetScheme() string { - if m != nil && m.Scheme != nil { - return *m.Scheme - } - return Default_ScrapeConfig_Scheme -} - -// The top-level Prometheus configuration. -type PrometheusConfig struct { - // Global Prometheus configuration options. If omitted, an empty global - // configuration with default values (see GlobalConfig definition) will be - // created. - Global *GlobalConfig `protobuf:"bytes,1,opt,name=global" json:"global,omitempty"` - // The list of scrape configs. - ScrapeConfig []*ScrapeConfig `protobuf:"bytes,3,rep,name=scrape_config" json:"scrape_config,omitempty"` - XXX_unrecognized []byte `json:"-"` -} - -func (m *PrometheusConfig) Reset() { *m = PrometheusConfig{} } -func (m *PrometheusConfig) String() string { return proto.CompactTextString(m) } -func (*PrometheusConfig) ProtoMessage() {} - -func (m *PrometheusConfig) GetGlobal() *GlobalConfig { - if m != nil { - return m.Global - } - return nil -} - -func (m *PrometheusConfig) GetScrapeConfig() []*ScrapeConfig { - if m != nil { - return m.ScrapeConfig - } - return nil -} - -func init() { - proto.RegisterEnum("io.prometheus.RelabelConfig_Action", RelabelConfig_Action_name, RelabelConfig_Action_value) -} diff --git a/config/load.go b/config/load.go deleted file mode 100644 index 3ee7f8695..000000000 --- a/config/load.go +++ /dev/null @@ -1,53 +0,0 @@ -// Copyright 2013 The Prometheus Authors -// Licensed under the Apache License, Version 2.0 (the "License"); -// you may not use this file except in compliance with the License. -// You may obtain a copy of the License at -// -// http://www.apache.org/licenses/LICENSE-2.0 -// -// Unless required by applicable law or agreed to in writing, software -// distributed under the License is distributed on an "AS IS" BASIS, -// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. -// See the License for the specific language governing permissions and -// limitations under the License. - -package config - -import ( - "io/ioutil" - - "github.com/golang/protobuf/proto" - - pb "github.com/prometheus/prometheus/config/generated" -) - -// LoadFromString returns a config parsed from the provided string. -func LoadFromString(configStr string) (*Config, error) { - configProto := pb.PrometheusConfig{} - if err := proto.UnmarshalText(configStr, &configProto); err != nil { - return nil, err - } - if configProto.Global == nil { - configProto.Global = &pb.GlobalConfig{} - } - for _, scfg := range configProto.GetScrapeConfig() { - if scfg.ScrapeInterval == nil { - scfg.ScrapeInterval = proto.String(configProto.Global.GetScrapeInterval()) - } - } - - config := &Config{configProto} - err := config.Validate() - - return config, err -} - -// LoadFromFile returns a config parsed from the file of the provided name. -func LoadFromFile(fileName string) (*Config, error) { - configStr, err := ioutil.ReadFile(fileName) - if err != nil { - return nil, err - } - - return LoadFromString(string(configStr)) -} diff --git a/config/load_test.go b/config/load_test.go deleted file mode 100644 index 5e1aa423f..000000000 --- a/config/load_test.go +++ /dev/null @@ -1,25 +0,0 @@ -// Copyright 2013 The Prometheus Authors -// Licensed under the Apache License, Version 2.0 (the "License"); -// you may not use this file except in compliance with the License. -// You may obtain a copy of the License at -// -// http://www.apache.org/licenses/LICENSE-2.0 -// -// Unless required by applicable law or agreed to in writing, software -// distributed under the License is distributed on an "AS IS" BASIS, -// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. -// See the License for the specific language governing permissions and -// limitations under the License. - -package config - -import ( - "testing" -) - -func TestLoadFromFile(t *testing.T) { - _, err := LoadFromFile("file-does-not-exist.conf") - if err == nil { - t.Error("Error expected on non-existing config file path but got none") - } -} diff --git a/config/testdata/conf.good.yml b/config/testdata/conf.good.yml new file mode 100644 index 000000000..290d2b5cc --- /dev/null +++ b/config/testdata/conf.good.yml @@ -0,0 +1,61 @@ +# my global config +global_config: + 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" + +scrape_configs: + - job_name: prometheus + + # scrape_interval is defined by the configured global (15s). + # scrape_timeout is defined by the global default (10s). + + # metrics_path defaults to '/metrics' + # scheme defaults to 'http'. + + labels: + foo: baz + + 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 + + scrape_interval: 50s + scrape_timeout: 5s + + metrics_path: /my_path + # scheme defaults to 'http'. + + dns_configs: + - refresh_interval: 15s + names: + - first.dns.address.domain.com + - second.dns.address.domain.com + - names: + - first.dns.address.domain.com + # refresh_interval defaults to 30s. + + relabel_configs: + - source_labels: [job] + regex: (.*)some-[regex]$ + action: drop diff --git a/config/testdata/jobname.bad.yml b/config/testdata/jobname.bad.yml new file mode 100644 index 000000000..2d08e1f82 --- /dev/null +++ b/config/testdata/jobname.bad.yml @@ -0,0 +1,2 @@ +scrape_configs: + - job_name: prom^etheus diff --git a/config/testdata/jobname_dup.bad.yml b/config/testdata/jobname_dup.bad.yml new file mode 100644 index 000000000..0265493c3 --- /dev/null +++ b/config/testdata/jobname_dup.bad.yml @@ -0,0 +1,5 @@ +# Two scrape configs with the same job names are not allowed. +scrape_configs: + - job_name: prometheus + - job_name: service-x + - job_name: prometheus diff --git a/config/testdata/labelname.bad.yml b/config/testdata/labelname.bad.yml new file mode 100644 index 000000000..e940d58e7 --- /dev/null +++ b/config/testdata/labelname.bad.yml @@ -0,0 +1,3 @@ +global_config: + labels: + not$allowed: value diff --git a/config/testdata/regex.bad.yml b/config/testdata/regex.bad.yml new file mode 100644 index 000000000..4cfe792fa --- /dev/null +++ b/config/testdata/regex.bad.yml @@ -0,0 +1,4 @@ +scrape_configs: + - job_name: prometheus + relabel_configs: + - regex: abc(def diff --git a/main.go b/main.go index 83cceb2ec..eba792e32 100644 --- a/main.go +++ b/main.go @@ -161,7 +161,7 @@ func NewPrometheus() *prometheus { ruleManager := manager.NewRuleManager(&manager.RuleManagerOptions{ SampleAppender: sampleAppender, NotificationHandler: notificationHandler, - EvaluationInterval: conf.EvaluationInterval(), + EvaluationInterval: time.Duration(conf.GlobalConfig.EvaluationInterval), Storage: memStorage, PrometheusURL: web.MustBuildServerURL(*pathPrefix), PathPrefix: *pathPrefix, diff --git a/retrieval/relabel.go b/retrieval/relabel.go index e0ddb232d..337a1b67a 100644 --- a/retrieval/relabel.go +++ b/retrieval/relabel.go @@ -1,13 +1,12 @@ package retrieval import ( - "regexp" + "fmt" "strings" clientmodel "github.com/prometheus/client_golang/model" "github.com/prometheus/prometheus/config" - pb "github.com/prometheus/prometheus/config/generated" ) // Relabel returns a relabeled copy of the given label set. The relabel configurations @@ -31,40 +30,34 @@ func Relabel(labels clientmodel.LabelSet, cfgs ...*config.RelabelConfig) (client } func relabel(labels clientmodel.LabelSet, cfg *config.RelabelConfig) (clientmodel.LabelSet, error) { - pat, err := regexp.Compile(cfg.GetRegex()) - if err != nil { - return nil, err + values := make([]string, 0, len(cfg.SourceLabels)) + for _, ln := range cfg.SourceLabels { + values = append(values, string(labels[ln])) } + val := strings.Join(values, cfg.Separator) - values := make([]string, 0, len(cfg.GetSourceLabel())) - for _, name := range cfg.GetSourceLabel() { - values = append(values, string(labels[clientmodel.LabelName(name)])) - } - val := strings.Join(values, cfg.GetSeparator()) - - switch cfg.GetAction() { - case pb.RelabelConfig_DROP: - if pat.MatchString(val) { + switch cfg.Action { + case config.RelabelDrop: + if cfg.Regex.MatchString(val) { return nil, nil } - case pb.RelabelConfig_KEEP: - if !pat.MatchString(val) { + case config.RelabelKeep: + if !cfg.Regex.MatchString(val) { return nil, nil } - case pb.RelabelConfig_REPLACE: + case config.RelabelReplace: // If there is no match no replacement must take place. - if !pat.MatchString(val) { + if !cfg.Regex.MatchString(val) { break } - res := pat.ReplaceAllString(val, cfg.GetReplacement()) - ln := clientmodel.LabelName(cfg.GetTargetLabel()) + res := cfg.Regex.ReplaceAllString(val, cfg.Replacement) if res == "" { - delete(labels, ln) + delete(labels, cfg.TargetLabel) } else { - labels[ln] = clientmodel.LabelValue(res) + labels[cfg.TargetLabel] = clientmodel.LabelValue(res) } default: - panic("retrieval.relabel: unknown relabel action type") + panic(fmt.Errorf("retrieval.relabel: unknown relabel action type %q", cfg.Action)) } return labels, nil } diff --git a/retrieval/relabel_test.go b/retrieval/relabel_test.go index 0bdfe4315..70398a54f 100644 --- a/retrieval/relabel_test.go +++ b/retrieval/relabel_test.go @@ -2,20 +2,18 @@ package retrieval import ( "reflect" + "regexp" "testing" - "github.com/golang/protobuf/proto" - clientmodel "github.com/prometheus/client_golang/model" "github.com/prometheus/prometheus/config" - pb "github.com/prometheus/prometheus/config/generated" ) func TestRelabel(t *testing.T) { tests := []struct { input clientmodel.LabelSet - relabel []pb.RelabelConfig + relabel []config.DefaultedRelabelConfig output clientmodel.LabelSet }{ { @@ -24,14 +22,14 @@ func TestRelabel(t *testing.T) { "b": "bar", "c": "baz", }, - relabel: []pb.RelabelConfig{ + relabel: []config.DefaultedRelabelConfig{ { - SourceLabel: []string{"a"}, - Regex: proto.String("f(.*)"), - TargetLabel: proto.String("d"), - Separator: proto.String(";"), - Replacement: proto.String("ch${1}-ch${1}"), - Action: pb.RelabelConfig_REPLACE.Enum(), + SourceLabels: clientmodel.LabelNames{"a"}, + Regex: &config.Regexp{*regexp.MustCompile("f(.*)")}, + TargetLabel: clientmodel.LabelName("d"), + Separator: ";", + Replacement: "ch${1}-ch${1}", + Action: config.RelabelReplace, }, }, output: clientmodel.LabelSet{ @@ -47,21 +45,22 @@ func TestRelabel(t *testing.T) { "b": "bar", "c": "baz", }, - relabel: []pb.RelabelConfig{ + relabel: []config.DefaultedRelabelConfig{ { - SourceLabel: []string{"a", "b"}, - Regex: proto.String("^f(.*);(.*)r$"), - TargetLabel: proto.String("a"), - Separator: proto.String(";"), - Replacement: proto.String("b${1}${2}m"), // boobam + SourceLabels: clientmodel.LabelNames{"a", "b"}, + Regex: &config.Regexp{*regexp.MustCompile("^f(.*);(.*)r$")}, + TargetLabel: clientmodel.LabelName("a"), + Separator: ";", + Replacement: "b${1}${2}m", // boobam + Action: config.RelabelReplace, }, { - SourceLabel: []string{"c", "a"}, - Regex: proto.String("(b).*b(.*)ba(.*)"), - TargetLabel: proto.String("d"), - Separator: proto.String(";"), - Replacement: proto.String("$1$2$2$3"), - Action: pb.RelabelConfig_REPLACE.Enum(), + SourceLabels: clientmodel.LabelNames{"c", "a"}, + Regex: &config.Regexp{*regexp.MustCompile("(b).*b(.*)ba(.*)")}, + TargetLabel: clientmodel.LabelName("d"), + Separator: ";", + Replacement: "$1$2$2$3", + Action: config.RelabelReplace, }, }, output: clientmodel.LabelSet{ @@ -75,18 +74,18 @@ func TestRelabel(t *testing.T) { input: clientmodel.LabelSet{ "a": "foo", }, - relabel: []pb.RelabelConfig{ + relabel: []config.DefaultedRelabelConfig{ { - SourceLabel: []string{"a"}, - Regex: proto.String("o$"), - Action: pb.RelabelConfig_DROP.Enum(), + SourceLabels: clientmodel.LabelNames{"a"}, + Regex: &config.Regexp{*regexp.MustCompile("o$")}, + Action: config.RelabelDrop, }, { - SourceLabel: []string{"a"}, - Regex: proto.String("f(.*)"), - TargetLabel: proto.String("d"), - Separator: proto.String(";"), - Replacement: proto.String("ch$1-ch$1"), - Action: pb.RelabelConfig_REPLACE.Enum(), + SourceLabels: clientmodel.LabelNames{"a"}, + Regex: &config.Regexp{*regexp.MustCompile("f(.*)")}, + TargetLabel: clientmodel.LabelName("d"), + Separator: ";", + Replacement: "ch$1-ch$1", + Action: config.RelabelReplace, }, }, output: nil, @@ -95,11 +94,11 @@ func TestRelabel(t *testing.T) { input: clientmodel.LabelSet{ "a": "foo", }, - relabel: []pb.RelabelConfig{ + relabel: []config.DefaultedRelabelConfig{ { - SourceLabel: []string{"a"}, - Regex: proto.String("no-match"), - Action: pb.RelabelConfig_DROP.Enum(), + SourceLabels: clientmodel.LabelNames{"a"}, + Regex: &config.Regexp{*regexp.MustCompile("no-match")}, + Action: config.RelabelDrop, }, }, output: clientmodel.LabelSet{ @@ -110,11 +109,11 @@ func TestRelabel(t *testing.T) { input: clientmodel.LabelSet{ "a": "foo", }, - relabel: []pb.RelabelConfig{ + relabel: []config.DefaultedRelabelConfig{ { - SourceLabel: []string{"a"}, - Regex: proto.String("no-match"), - Action: pb.RelabelConfig_KEEP.Enum(), + SourceLabels: clientmodel.LabelNames{"a"}, + Regex: &config.Regexp{*regexp.MustCompile("no-match")}, + Action: config.RelabelKeep, }, }, output: nil, @@ -123,11 +122,11 @@ func TestRelabel(t *testing.T) { input: clientmodel.LabelSet{ "a": "foo", }, - relabel: []pb.RelabelConfig{ + relabel: []config.DefaultedRelabelConfig{ { - SourceLabel: []string{"a"}, - Regex: proto.String("^f"), - Action: pb.RelabelConfig_KEEP.Enum(), + SourceLabels: clientmodel.LabelNames{"a"}, + Regex: &config.Regexp{*regexp.MustCompile("^f")}, + Action: config.RelabelKeep, }, }, output: clientmodel.LabelSet{ @@ -139,13 +138,13 @@ func TestRelabel(t *testing.T) { input: clientmodel.LabelSet{ "a": "boo", }, - relabel: []pb.RelabelConfig{ + relabel: []config.DefaultedRelabelConfig{ { - SourceLabel: []string{"a"}, - Regex: proto.String("^f"), - Action: pb.RelabelConfig_REPLACE.Enum(), - TargetLabel: proto.String("b"), - Replacement: proto.String("bar"), + SourceLabels: clientmodel.LabelNames{"a"}, + Regex: &config.Regexp{*regexp.MustCompile("^f")}, + TargetLabel: clientmodel.LabelName("b"), + Replacement: "bar", + Action: config.RelabelReplace, }, }, output: clientmodel.LabelSet{ @@ -157,7 +156,6 @@ func TestRelabel(t *testing.T) { for i, test := range tests { var relabel []*config.RelabelConfig for _, rl := range test.relabel { - proto.SetDefaults(&rl) relabel = append(relabel, &config.RelabelConfig{rl}) } res, err := Relabel(test.input, relabel...) diff --git a/retrieval/target.go b/retrieval/target.go index cdd3acdca..bd1db8dc6 100644 --- a/retrieval/target.go +++ b/retrieval/target.go @@ -190,12 +190,12 @@ func (t *target) Update(cfg *config.ScrapeConfig, baseLabels clientmodel.LabelSe t.Lock() defer t.Unlock() - t.url.Scheme = cfg.GetScheme() + t.url.Scheme = cfg.Scheme t.url.Path = string(baseLabels[clientmodel.MetricsPathLabel]) - t.scrapeInterval = cfg.ScrapeInterval() - t.deadline = cfg.ScrapeTimeout() - t.httpClient = utility.NewDeadlineClient(cfg.ScrapeTimeout()) + t.scrapeInterval = time.Duration(cfg.ScrapeInterval) + t.deadline = time.Duration(cfg.ScrapeTimeout) + t.httpClient = utility.NewDeadlineClient(time.Duration(cfg.ScrapeTimeout)) t.baseLabels = clientmodel.LabelSet{} // All remaining internal labels will not be part of the label set. diff --git a/retrieval/target_test.go b/retrieval/target_test.go index 20b0fcee3..062d27568 100644 --- a/retrieval/target_test.go +++ b/retrieval/target_test.go @@ -26,8 +26,6 @@ import ( clientmodel "github.com/prometheus/client_golang/model" - "github.com/golang/protobuf/proto" - "github.com/prometheus/prometheus/config" "github.com/prometheus/prometheus/utility" ) @@ -91,9 +89,6 @@ func TestTargetScrapeWithFullChannel(t *testing.T) { } func TestTargetRecordScrapeHealth(t *testing.T) { - scfg := &config.ScrapeConfig{} - proto.SetDefaults(&scfg.ScrapeConfig) - testTarget := newTestTarget("example.url", 0, clientmodel.LabelSet{clientmodel.JobLabel: "testjob"}) now := clientmodel.Now() @@ -150,9 +145,6 @@ func TestTargetScrapeTimeout(t *testing.T) { ) defer server.Close() - scfg := &config.ScrapeConfig{} - proto.SetDefaults(&scfg.ScrapeConfig) - var testTarget Target = newTestTarget(server.URL, 10*time.Millisecond, clientmodel.LabelSet{}) appender := nopAppender{} diff --git a/retrieval/targetmanager.go b/retrieval/targetmanager.go index 6e9f29f49..4cf253c3e 100644 --- a/retrieval/targetmanager.go +++ b/retrieval/targetmanager.go @@ -17,13 +17,13 @@ import ( "fmt" "strings" "sync" + "time" "github.com/golang/glog" clientmodel "github.com/prometheus/client_golang/model" "github.com/prometheus/prometheus/config" - pb "github.com/prometheus/prometheus/config/generated" "github.com/prometheus/prometheus/retrieval/discovery" "github.com/prometheus/prometheus/storage" ) @@ -124,7 +124,7 @@ func (tm *TargetManager) handleTargetUpdates(cfg *config.ScrapeConfig, ch <-chan // Thus, oscilliating label sets for targets with the same source, // but providers from different configs, are prevented. func fullSource(cfg *config.ScrapeConfig, src string) string { - return cfg.GetJobName() + ":" + src + return cfg.JobName + ":" + src } // Stop all background processing. @@ -289,7 +289,7 @@ func (tm *TargetManager) applyConfig(cfg *config.Config) error { // Only apply changes if everything was successful. providers := map[*config.ScrapeConfig][]TargetProvider{} - for _, scfg := range cfg.ScrapeConfigs() { + for _, scfg := range cfg.ScrapeConfigs { provs, err := ProvidersFromConfig(scfg) if err != nil { return err @@ -299,7 +299,7 @@ func (tm *TargetManager) applyConfig(cfg *config.Config) error { tm.m.Lock() defer tm.m.Unlock() - tm.globalLabels = cfg.GlobalLabels() + tm.globalLabels = cfg.GlobalConfig.Labels tm.providers = providers return nil } @@ -315,7 +315,10 @@ func (tm *TargetManager) targetsFromGroup(tg *config.TargetGroup, cfg *config.Sc // set already. Apply the labelsets in order of decreasing precedence. labelsets := []clientmodel.LabelSet{ tg.Labels, - cfg.Labels(), + clientmodel.LabelSet{ + clientmodel.MetricsPathLabel: clientmodel.LabelValue(cfg.MetricsPath), + clientmodel.JobLabel: clientmodel.LabelValue(cfg.JobName), + }, tm.globalLabels, } for _, lset := range labelsets { @@ -330,7 +333,7 @@ func (tm *TargetManager) targetsFromGroup(tg *config.TargetGroup, cfg *config.Sc return nil, fmt.Errorf("instance %d in target group %s has no address", i, tg) } - labels, err := Relabel(labels, cfg.RelabelConfigs()...) + labels, err := Relabel(labels, cfg.RelabelConfigs...) if err != nil { return nil, fmt.Errorf("error while relabelling instance %d in target group %s: %s", i, tg, err) } @@ -357,13 +360,12 @@ func (tm *TargetManager) targetsFromGroup(tg *config.TargetGroup, cfg *config.Sc func ProvidersFromConfig(cfg *config.ScrapeConfig) ([]TargetProvider, error) { var providers []TargetProvider - for _, dnscfg := range cfg.DNSConfigs() { - dnsSD := discovery.NewDNSDiscovery(dnscfg.GetName(), dnscfg.RefreshInterval()) + for _, dnscfg := range cfg.DNSConfigs { + dnsSD := discovery.NewDNSDiscovery(dnscfg.Names, time.Duration(dnscfg.RefreshInterval)) providers = append(providers, dnsSD) } - if tgs := cfg.GetTargetGroup(); tgs != nil { - static := NewStaticProvider(tgs) - providers = append(providers, static) + if len(cfg.TargetGroups) > 0 { + providers = append(providers, NewStaticProvider(cfg.TargetGroups)) } return providers, nil } @@ -375,25 +377,13 @@ type StaticProvider struct { // NewStaticProvider returns a StaticProvider configured with the given // target groups. -func NewStaticProvider(groups []*pb.TargetGroup) *StaticProvider { - prov := &StaticProvider{} - +func NewStaticProvider(groups []*config.TargetGroup) *StaticProvider { for i, tg := range groups { - g := &config.TargetGroup{ - Source: fmt.Sprintf("static:%d", i), - Labels: clientmodel.LabelSet{}, - } - for _, pair := range tg.GetLabels().GetLabel() { - g.Labels[clientmodel.LabelName(pair.GetName())] = clientmodel.LabelValue(pair.GetValue()) - } - for _, t := range tg.GetTarget() { - g.Targets = append(g.Targets, clientmodel.LabelSet{ - clientmodel.AddressLabel: clientmodel.LabelValue(t), - }) - } - prov.TargetGroups = append(prov.TargetGroups, g) + tg.Source = fmt.Sprintf("static:%d", i) + } + return &StaticProvider{ + TargetGroups: groups, } - return prov } // Run implements the TargetProvider interface. diff --git a/retrieval/targetmanager_test.go b/retrieval/targetmanager_test.go index 7aa090314..6becfb221 100644 --- a/retrieval/targetmanager_test.go +++ b/retrieval/targetmanager_test.go @@ -15,25 +15,26 @@ package retrieval import ( "reflect" + "regexp" "testing" "time" - "github.com/golang/protobuf/proto" - clientmodel "github.com/prometheus/client_golang/model" "github.com/prometheus/prometheus/config" - pb "github.com/prometheus/prometheus/config/generated" ) func TestTargetManagerChan(t *testing.T) { - testJob1 := &config.ScrapeConfig{pb.ScrapeConfig{ - JobName: proto.String("test_job1"), - ScrapeInterval: proto.String("1m"), - TargetGroup: []*pb.TargetGroup{ - {Target: []string{"example.org:80", "example.com:80"}}, + testJob1 := &config.ScrapeConfig{config.DefaultedScrapeConfig{ + JobName: "test_job1", + ScrapeInterval: config.Duration(1 * time.Minute), + TargetGroups: []*config.TargetGroup{{ + Targets: []clientmodel.LabelSet{ + {clientmodel.AddressLabel: "example.org:80"}, + {clientmodel.AddressLabel: "example.com:80"}, + }, }}, - } + }} prov1 := &fakeTargetProvider{ sources: []string{"src1", "src2"}, update: make(chan *config.TargetGroup), @@ -153,63 +154,76 @@ func TestTargetManagerChan(t *testing.T) { } func TestTargetManagerConfigUpdate(t *testing.T) { - testJob1 := &pb.ScrapeConfig{ - JobName: proto.String("test_job1"), - ScrapeInterval: proto.String("1m"), - TargetGroup: []*pb.TargetGroup{ - {Target: []string{"example.org:80", "example.com:80"}}, - }, - } - testJob2 := &pb.ScrapeConfig{ - JobName: proto.String("test_job2"), - ScrapeInterval: proto.String("1m"), - TargetGroup: []*pb.TargetGroup{ - { - Target: []string{"example.org:8080", "example.com:8081"}, - Labels: &pb.LabelPairs{Label: []*pb.LabelPair{ - {Name: proto.String("foo"), Value: proto.String("bar")}, - {Name: proto.String("boom"), Value: proto.String("box")}, - }}, + testJob1 := &config.ScrapeConfig{config.DefaultedScrapeConfig{ + JobName: "test_job1", + ScrapeInterval: config.Duration(1 * time.Minute), + TargetGroups: []*config.TargetGroup{{ + Targets: []clientmodel.LabelSet{ + {clientmodel.AddressLabel: "example.org:80"}, + {clientmodel.AddressLabel: "example.com:80"}, }, - {Target: []string{"test.com:1234"}}, + }}, + }} + testJob2 := &config.ScrapeConfig{config.DefaultedScrapeConfig{ + JobName: "test_job2", + ScrapeInterval: config.Duration(1 * time.Minute), + TargetGroups: []*config.TargetGroup{ { - Target: []string{"test.com:1235"}, - Labels: &pb.LabelPairs{Label: []*pb.LabelPair{ - {Name: proto.String("instance"), Value: proto.String("fixed")}, - }}, + Targets: []clientmodel.LabelSet{ + {clientmodel.AddressLabel: "example.org:8080"}, + {clientmodel.AddressLabel: "example.com:8081"}, + }, + Labels: clientmodel.LabelSet{ + "foo": "bar", + "boom": "box", + }, + }, + { + Targets: []clientmodel.LabelSet{ + {clientmodel.AddressLabel: "test.com:1234"}, + }, + }, + { + Targets: []clientmodel.LabelSet{ + {clientmodel.AddressLabel: "test.com:1235"}, + }, + Labels: clientmodel.LabelSet{"instance": "fixed"}, }, }, - RelabelConfig: []*pb.RelabelConfig{ - { - SourceLabel: []string{string(clientmodel.AddressLabel)}, - Regex: proto.String(`^test\.(.*?):(.*)`), - Replacement: proto.String("foo.${1}:${2}"), - TargetLabel: proto.String(string(clientmodel.AddressLabel)), - }, { + 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. - SourceLabel: []string{string(clientmodel.AddressLabel), "boom", "foo"}, - Regex: proto.String("^example.*?-b([a-z-]+)r$"), - TargetLabel: proto.String("new"), - Replacement: proto.String("$1"), - Separator: proto.String("-"), - }, { + SourceLabels: clientmodel.LabelNames{clientmodel.AddressLabel, "boom", "foo"}, + Regex: &config.Regexp{*regexp.MustCompile("^example.*?-b([a-z-]+)r$")}, + TargetLabel: "new", + Replacement: "$1", + Separator: "-", + Action: config.RelabelReplace, + }}, + {config.DefaultedRelabelConfig{ // Drop an existing label. - SourceLabel: []string{"boom"}, - Regex: proto.String(".*"), - TargetLabel: proto.String("boom"), - Replacement: proto.String(""), - }, + SourceLabels: clientmodel.LabelNames{"boom"}, + Regex: &config.Regexp{*regexp.MustCompile(".*")}, + TargetLabel: "boom", + Replacement: "", + Action: config.RelabelReplace, + }}, }, - } - proto.SetDefaults(testJob1) - proto.SetDefaults(testJob2) + }} sequence := []struct { - scrapeConfigs []*pb.ScrapeConfig + scrapeConfigs []*config.ScrapeConfig expected map[string][]clientmodel.LabelSet }{ { - scrapeConfigs: []*pb.ScrapeConfig{testJob1}, + scrapeConfigs: []*config.ScrapeConfig{testJob1}, expected: map[string][]clientmodel.LabelSet{ "test_job1:static:0": { {clientmodel.JobLabel: "test_job1", clientmodel.InstanceLabel: "example.org:80"}, @@ -217,7 +231,7 @@ func TestTargetManagerConfigUpdate(t *testing.T) { }, }, }, { - scrapeConfigs: []*pb.ScrapeConfig{testJob1}, + scrapeConfigs: []*config.ScrapeConfig{testJob1}, expected: map[string][]clientmodel.LabelSet{ "test_job1:static:0": { {clientmodel.JobLabel: "test_job1", clientmodel.InstanceLabel: "example.org:80"}, @@ -225,7 +239,7 @@ func TestTargetManagerConfigUpdate(t *testing.T) { }, }, }, { - scrapeConfigs: []*pb.ScrapeConfig{testJob1, testJob2}, + scrapeConfigs: []*config.ScrapeConfig{testJob1, testJob2}, expected: map[string][]clientmodel.LabelSet{ "test_job1:static:0": { {clientmodel.JobLabel: "test_job1", clientmodel.InstanceLabel: "example.org:80"}, @@ -243,10 +257,10 @@ func TestTargetManagerConfigUpdate(t *testing.T) { }, }, }, { - scrapeConfigs: []*pb.ScrapeConfig{}, + scrapeConfigs: []*config.ScrapeConfig{}, expected: map[string][]clientmodel.LabelSet{}, }, { - scrapeConfigs: []*pb.ScrapeConfig{testJob2}, + scrapeConfigs: []*config.ScrapeConfig{testJob2}, expected: map[string][]clientmodel.LabelSet{ "test_job2:static:0": { {clientmodel.JobLabel: "test_job2", clientmodel.InstanceLabel: "example.org:8080", "foo": "bar", "new": "ox-ba"}, @@ -261,8 +275,9 @@ func TestTargetManagerConfigUpdate(t *testing.T) { }, }, } + conf := &config.Config{DefaultedConfig: config.DefaultConfig} - targetManager, err := NewTargetManager(&config.Config{}, nopAppender{}) + targetManager, err := NewTargetManager(conf, nopAppender{}) if err != nil { t.Fatal(err) } @@ -270,10 +285,8 @@ func TestTargetManagerConfigUpdate(t *testing.T) { defer targetManager.Stop() for i, step := range sequence { - cfg := pb.PrometheusConfig{ - ScrapeConfig: step.scrapeConfigs, - } - err := targetManager.ApplyConfig(&config.Config{cfg}) + conf.ScrapeConfigs = step.scrapeConfigs + err := targetManager.ApplyConfig(conf) if err != nil { t.Fatal(err) } diff --git a/rules/manager/manager.go b/rules/manager/manager.go index 1e7e070f4..bd50d45d6 100644 --- a/rules/manager/manager.go +++ b/rules/manager/manager.go @@ -268,7 +268,7 @@ func (m *ruleManager) runIteration() { } func (m *ruleManager) AddRulesFromConfig(config *config.Config) error { - for _, ruleFile := range config.Global.RuleFile { + for _, ruleFile := range config.RuleFiles { newRules, err := rules.LoadRulesFromFile(ruleFile) if err != nil { return fmt.Errorf("%s: %s", ruleFile, err)