diff --git a/config/config.go b/config/config.go index cd603e5f9a..2e941c426e 100644 --- a/config/config.go +++ b/config/config.go @@ -398,9 +398,28 @@ func (c *ScrapeConfig) UnmarshalYAML(unmarshal func(interface{}) error) error { if c.BasicAuth != nil && (len(c.BearerToken) > 0 || len(c.BearerTokenFile) > 0) { return fmt.Errorf("at most one of basic_auth, bearer_token & bearer_token_file must be configured") } + // Check for users putting URLs in target groups. + if len(c.RelabelConfigs) == 0 { + for _, tg := range c.TargetGroups { + for _, t := range tg.Targets { + if err = CheckTargetAddress(t[model.AddressLabel]); err != nil { + return err + } + } + } + } return checkOverflow(c.XXX, "scrape_config") } +// CheckTargetAddress checks if target address is valid. +func CheckTargetAddress(address model.LabelValue) error { + // For now check for a URL, we may want to expand this later. + if strings.Contains(string(address), "/") { + return fmt.Errorf("%q is not a valid hostname", address) + } + return nil +} + // BasicAuth contains basic HTTP authentication credentials. type BasicAuth struct { Username string `yaml:"username"` @@ -457,9 +476,6 @@ func (tg *TargetGroup) UnmarshalYAML(unmarshal func(interface{}) error) error { } tg.Targets = make([]model.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, model.LabelSet{ model.AddressLabel: model.LabelValue(t), }) diff --git a/config/config_test.go b/config/config_test.go index b1d19f27b9..853e65f029 100644 --- a/config/config_test.go +++ b/config/config_test.go @@ -335,6 +335,9 @@ var expectedErrors = []struct { }, { filename: "marathon_no_servers.bad.yml", errMsg: "Marathon SD config must contain at least one Marathon server", + }, { + filename: "url_in_targetgroup.bad.yml", + errMsg: "\"http://bad\" is not a valid hostname", }, } diff --git a/config/testdata/url_in_targetgroup.bad.yml b/config/testdata/url_in_targetgroup.bad.yml new file mode 100644 index 0000000000..48a1845990 --- /dev/null +++ b/config/testdata/url_in_targetgroup.bad.yml @@ -0,0 +1,5 @@ +scrape_configs: +- job_name: prometheus + target_groups: + - targets: + - http://bad diff --git a/retrieval/targetmanager.go b/retrieval/targetmanager.go index f301b9a1b2..fb98589133 100644 --- a/retrieval/targetmanager.go +++ b/retrieval/targetmanager.go @@ -496,6 +496,9 @@ func (tm *TargetManager) targetsFromGroup(tg *config.TargetGroup, cfg *config.Sc if labels == nil { continue } + if err = config.CheckTargetAddress(labels[model.AddressLabel]); err != nil { + return nil, err + } for ln := range labels { // Meta labels are deleted after relabelling. Other internal labels propagate to diff --git a/retrieval/targetmanager_test.go b/retrieval/targetmanager_test.go index 3f605f7693..654083d3e9 100644 --- a/retrieval/targetmanager_test.go +++ b/retrieval/targetmanager_test.go @@ -278,6 +278,25 @@ func TestTargetManagerConfigUpdate(t *testing.T) { }, }, } + // Test that targets without host:port addresses are dropped. + testJob3 := &config.ScrapeConfig{ + JobName: "test_job1", + ScrapeInterval: config.Duration(1 * time.Minute), + TargetGroups: []*config.TargetGroup{{ + Targets: []model.LabelSet{ + {model.AddressLabel: "example.net:80"}, + }, + }}, + RelabelConfigs: []*config.RelabelConfig{ + { + SourceLabels: model.LabelNames{model.AddressLabel}, + Regex: config.MustNewRegexp("(.*)"), + TargetLabel: "__address__", + Replacement: "http://$1", + Action: config.RelabelReplace, + }, + }, + } sequence := []struct { scrapeConfigs []*config.ScrapeConfig @@ -348,6 +367,9 @@ func TestTargetManagerConfigUpdate(t *testing.T) { model.SchemeLabel: "", model.MetricsPathLabel: "", model.AddressLabel: "foo.com:1235"}, }, }, + }, { + scrapeConfigs: []*config.ScrapeConfig{testJob3}, + expected: map[string][]model.LabelSet{}, }, } conf := &config.Config{}