2015-08-20 04:03:56 -07:00
|
|
|
// Copyright 2015 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.
|
|
|
|
|
2013-02-13 16:04:07 -08:00
|
|
|
package config
|
|
|
|
|
|
|
|
import (
|
2015-06-06 00:55:22 -07:00
|
|
|
"encoding/json"
|
|
|
|
"io/ioutil"
|
2015-09-03 02:47:09 -07:00
|
|
|
"net/url"
|
2015-05-07 01:55:03 -07:00
|
|
|
"reflect"
|
2013-02-13 16:04:07 -08:00
|
|
|
"strings"
|
|
|
|
"testing"
|
2015-05-07 01:55:03 -07:00
|
|
|
"time"
|
|
|
|
|
2015-08-20 08:18:46 -07:00
|
|
|
"github.com/prometheus/common/model"
|
2015-08-22 00:42:45 -07:00
|
|
|
"gopkg.in/yaml.v2"
|
2013-02-13 16:04:07 -08:00
|
|
|
)
|
|
|
|
|
2015-06-04 08:03:12 -07:00
|
|
|
var expectedConf = &Config{
|
2015-06-07 08:40:22 -07:00
|
|
|
GlobalConfig: GlobalConfig{
|
2015-05-07 01:55:03 -07:00
|
|
|
ScrapeInterval: Duration(15 * time.Second),
|
|
|
|
ScrapeTimeout: DefaultGlobalConfig.ScrapeTimeout,
|
|
|
|
EvaluationInterval: Duration(30 * time.Second),
|
|
|
|
|
2015-09-29 08:51:03 -07:00
|
|
|
ExternalLabels: model.LabelSet{
|
2015-05-07 01:55:03 -07:00
|
|
|
"monitor": "codelab",
|
|
|
|
"foo": "bar",
|
|
|
|
},
|
2015-06-04 08:03:12 -07:00
|
|
|
},
|
2015-05-07 01:55:03 -07:00
|
|
|
|
|
|
|
RuleFiles: []string{
|
2015-08-05 09:04:34 -07:00
|
|
|
"testdata/first.rules",
|
|
|
|
"/absolute/second.rules",
|
|
|
|
"testdata/my/*.rules",
|
2015-05-07 01:55:03 -07:00
|
|
|
},
|
|
|
|
|
|
|
|
ScrapeConfigs: []*ScrapeConfig{
|
2015-06-04 08:03:12 -07:00
|
|
|
{
|
2015-05-07 01:55:03 -07:00
|
|
|
JobName: "prometheus",
|
|
|
|
|
2015-06-22 13:35:19 -07:00
|
|
|
HonorLabels: true,
|
2015-05-07 01:55:03 -07:00
|
|
|
ScrapeInterval: Duration(15 * time.Second),
|
|
|
|
ScrapeTimeout: DefaultGlobalConfig.ScrapeTimeout,
|
|
|
|
|
|
|
|
MetricsPath: DefaultScrapeConfig.MetricsPath,
|
|
|
|
Scheme: DefaultScrapeConfig.Scheme,
|
|
|
|
|
2015-08-05 09:04:34 -07:00
|
|
|
BearerTokenFile: "testdata/valid_token_file",
|
|
|
|
|
2015-05-07 01:55:03 -07:00
|
|
|
TargetGroups: []*TargetGroup{
|
|
|
|
{
|
2015-08-20 08:18:46 -07:00
|
|
|
Targets: []model.LabelSet{
|
|
|
|
{model.AddressLabel: "localhost:9090"},
|
|
|
|
{model.AddressLabel: "localhost:9191"},
|
2015-05-07 01:55:03 -07:00
|
|
|
},
|
2015-08-20 08:18:46 -07:00
|
|
|
Labels: model.LabelSet{
|
2015-05-07 01:55:03 -07:00
|
|
|
"my": "label",
|
|
|
|
"your": "label",
|
|
|
|
},
|
|
|
|
},
|
|
|
|
},
|
|
|
|
|
2015-05-13 02:28:04 -07:00
|
|
|
FileSDConfigs: []*FileSDConfig{
|
2015-06-04 08:03:12 -07:00
|
|
|
{
|
2015-05-13 03:03:31 -07:00
|
|
|
Names: []string{"foo/*.slow.json", "foo/*.slow.yml", "single/file.yml"},
|
2015-05-13 02:28:04 -07:00
|
|
|
RefreshInterval: Duration(10 * time.Minute),
|
2015-06-04 08:03:12 -07:00
|
|
|
},
|
|
|
|
{
|
2015-05-13 02:28:04 -07:00
|
|
|
Names: []string{"bar/*.yaml"},
|
2015-08-16 05:56:26 -07:00
|
|
|
RefreshInterval: Duration(5 * time.Minute),
|
2015-06-04 08:03:12 -07:00
|
|
|
},
|
2015-05-13 02:28:04 -07:00
|
|
|
},
|
|
|
|
|
2015-05-07 01:55:03 -07:00
|
|
|
RelabelConfigs: []*RelabelConfig{
|
2015-06-04 08:03:12 -07:00
|
|
|
{
|
2015-08-20 08:18:46 -07:00
|
|
|
SourceLabels: model.LabelNames{"job", "__meta_dns_srv_name"},
|
2015-05-07 01:55:03 -07:00
|
|
|
TargetLabel: "job",
|
|
|
|
Separator: ";",
|
2015-09-01 06:05:14 -07:00
|
|
|
Regex: MustNewRegexp("(.*)some-[regex]"),
|
2015-05-07 01:55:03 -07:00
|
|
|
Replacement: "foo-${1}",
|
|
|
|
Action: RelabelReplace,
|
2015-06-04 08:03:12 -07:00
|
|
|
},
|
2015-05-07 01:55:03 -07:00
|
|
|
},
|
2015-06-04 08:03:12 -07:00
|
|
|
},
|
|
|
|
{
|
2015-05-07 01:55:03 -07:00
|
|
|
JobName: "service-x",
|
|
|
|
|
|
|
|
ScrapeInterval: Duration(50 * time.Second),
|
|
|
|
ScrapeTimeout: Duration(5 * time.Second),
|
|
|
|
|
2015-05-15 03:47:50 -07:00
|
|
|
BasicAuth: &BasicAuth{
|
2015-07-06 05:25:20 -07:00
|
|
|
Username: "admin_name",
|
|
|
|
Password: "admin_password",
|
2015-05-15 03:47:50 -07:00
|
|
|
},
|
2015-05-07 01:55:03 -07:00
|
|
|
MetricsPath: "/my_path",
|
2015-05-15 03:47:50 -07:00
|
|
|
Scheme: "https",
|
2015-05-07 01:55:03 -07:00
|
|
|
|
2015-05-07 07:47:18 -07:00
|
|
|
DNSSDConfigs: []*DNSSDConfig{
|
2015-06-04 08:03:12 -07:00
|
|
|
{
|
2015-05-07 01:55:03 -07:00
|
|
|
Names: []string{
|
|
|
|
"first.dns.address.domain.com",
|
|
|
|
"second.dns.address.domain.com",
|
|
|
|
},
|
|
|
|
RefreshInterval: Duration(15 * time.Second),
|
2015-07-30 01:56:48 -07:00
|
|
|
Type: "SRV",
|
2015-06-04 08:03:12 -07:00
|
|
|
},
|
|
|
|
{
|
2015-05-07 01:55:03 -07:00
|
|
|
Names: []string{
|
|
|
|
"first.dns.address.domain.com",
|
|
|
|
},
|
|
|
|
RefreshInterval: Duration(30 * time.Second),
|
2015-07-30 01:56:48 -07:00
|
|
|
Type: "SRV",
|
2015-06-04 08:03:12 -07:00
|
|
|
},
|
2015-05-07 01:55:03 -07:00
|
|
|
},
|
|
|
|
|
|
|
|
RelabelConfigs: []*RelabelConfig{
|
2015-06-04 08:03:12 -07:00
|
|
|
{
|
2015-08-20 08:18:46 -07:00
|
|
|
SourceLabels: model.LabelNames{"job"},
|
2015-09-01 06:05:14 -07:00
|
|
|
Regex: MustNewRegexp("(.*)some-[regex]"),
|
2015-05-07 01:55:03 -07:00
|
|
|
Separator: ";",
|
|
|
|
Action: RelabelDrop,
|
2015-06-04 08:03:12 -07:00
|
|
|
},
|
2015-06-24 00:07:17 -07:00
|
|
|
{
|
2015-08-20 08:18:46 -07:00
|
|
|
SourceLabels: model.LabelNames{"__address__"},
|
2015-08-13 02:39:21 -07:00
|
|
|
TargetLabel: "__tmp_hash",
|
2015-06-24 00:07:17 -07:00
|
|
|
Modulus: 8,
|
|
|
|
Separator: ";",
|
|
|
|
Action: RelabelHashMod,
|
|
|
|
},
|
|
|
|
{
|
2015-08-20 08:18:46 -07:00
|
|
|
SourceLabels: model.LabelNames{"__tmp_hash"},
|
2015-09-01 06:05:14 -07:00
|
|
|
Regex: MustNewRegexp("1"),
|
2015-06-24 00:07:17 -07:00
|
|
|
Separator: ";",
|
|
|
|
Action: RelabelKeep,
|
|
|
|
},
|
2015-09-21 12:41:19 -07:00
|
|
|
{
|
|
|
|
Regex: MustNewRegexp("1"),
|
|
|
|
Separator: ";",
|
|
|
|
Action: RelabelLabelMap,
|
|
|
|
},
|
2015-05-07 01:55:03 -07:00
|
|
|
},
|
2015-06-12 14:16:13 -07:00
|
|
|
MetricRelabelConfigs: []*RelabelConfig{
|
|
|
|
{
|
2015-08-20 08:18:46 -07:00
|
|
|
SourceLabels: model.LabelNames{"__name__"},
|
2015-09-01 06:05:14 -07:00
|
|
|
Regex: MustNewRegexp("expensive_metric.*"),
|
2015-06-12 14:16:13 -07:00
|
|
|
Separator: ";",
|
|
|
|
Action: RelabelDrop,
|
|
|
|
},
|
|
|
|
},
|
2015-06-04 08:03:12 -07:00
|
|
|
},
|
2015-06-12 04:39:12 -07:00
|
|
|
{
|
|
|
|
JobName: "service-y",
|
|
|
|
|
|
|
|
ScrapeInterval: Duration(15 * time.Second),
|
|
|
|
ScrapeTimeout: DefaultGlobalConfig.ScrapeTimeout,
|
|
|
|
|
|
|
|
MetricsPath: DefaultScrapeConfig.MetricsPath,
|
|
|
|
Scheme: DefaultScrapeConfig.Scheme,
|
|
|
|
|
|
|
|
ConsulSDConfigs: []*ConsulSDConfig{
|
|
|
|
{
|
|
|
|
Server: "localhost:1234",
|
|
|
|
Services: []string{"nginx", "cache", "mysql"},
|
|
|
|
TagSeparator: DefaultConsulSDConfig.TagSeparator,
|
|
|
|
Scheme: DefaultConsulSDConfig.Scheme,
|
|
|
|
},
|
|
|
|
},
|
|
|
|
},
|
2015-07-22 08:48:22 -07:00
|
|
|
{
|
|
|
|
JobName: "service-z",
|
|
|
|
|
|
|
|
ScrapeInterval: Duration(15 * time.Second),
|
|
|
|
ScrapeTimeout: Duration(10 * time.Second),
|
|
|
|
|
|
|
|
MetricsPath: "/metrics",
|
|
|
|
Scheme: "http",
|
|
|
|
|
2015-09-06 16:07:44 -07:00
|
|
|
TLSConfig: TLSConfig{
|
|
|
|
CertFile: "testdata/valid_cert_file",
|
|
|
|
KeyFile: "testdata/valid_key_file",
|
2015-07-22 08:48:22 -07:00
|
|
|
},
|
2015-09-06 16:07:44 -07:00
|
|
|
|
2015-07-22 08:48:22 -07:00
|
|
|
BearerToken: "avalidtoken",
|
|
|
|
},
|
2015-07-18 14:23:58 -07:00
|
|
|
{
|
|
|
|
JobName: "service-kubernetes",
|
|
|
|
|
|
|
|
ScrapeInterval: Duration(15 * time.Second),
|
|
|
|
ScrapeTimeout: DefaultGlobalConfig.ScrapeTimeout,
|
|
|
|
|
|
|
|
MetricsPath: DefaultScrapeConfig.MetricsPath,
|
|
|
|
Scheme: DefaultScrapeConfig.Scheme,
|
|
|
|
|
|
|
|
KubernetesSDConfigs: []*KubernetesSDConfig{
|
|
|
|
{
|
2015-09-03 02:47:09 -07:00
|
|
|
Masters: []URL{kubernetesSDHostURL()},
|
2015-07-18 14:23:58 -07:00
|
|
|
Username: "myusername",
|
|
|
|
Password: "mypassword",
|
|
|
|
KubeletPort: 10255,
|
|
|
|
RequestTimeout: Duration(10 * time.Second),
|
|
|
|
RetryInterval: Duration(1 * time.Second),
|
|
|
|
},
|
|
|
|
},
|
|
|
|
},
|
2015-09-02 06:08:37 -07:00
|
|
|
{
|
|
|
|
JobName: "service-marathon",
|
|
|
|
|
|
|
|
ScrapeInterval: Duration(15 * time.Second),
|
|
|
|
ScrapeTimeout: DefaultGlobalConfig.ScrapeTimeout,
|
|
|
|
|
|
|
|
MetricsPath: DefaultScrapeConfig.MetricsPath,
|
|
|
|
Scheme: DefaultScrapeConfig.Scheme,
|
|
|
|
|
|
|
|
MarathonSDConfigs: []*MarathonSDConfig{
|
|
|
|
{
|
|
|
|
Servers: []string{
|
|
|
|
"http://marathon.example.com:8080",
|
|
|
|
},
|
|
|
|
RefreshInterval: Duration(30 * time.Second),
|
|
|
|
},
|
|
|
|
},
|
|
|
|
},
|
2015-09-21 11:49:19 -07:00
|
|
|
{
|
|
|
|
JobName: "service-ec2",
|
|
|
|
|
|
|
|
ScrapeInterval: Duration(15 * time.Second),
|
|
|
|
ScrapeTimeout: DefaultGlobalConfig.ScrapeTimeout,
|
|
|
|
|
|
|
|
MetricsPath: DefaultScrapeConfig.MetricsPath,
|
|
|
|
Scheme: DefaultScrapeConfig.Scheme,
|
|
|
|
|
|
|
|
EC2SDConfigs: []*EC2SDConfig{
|
|
|
|
{
|
|
|
|
Region: "us-east-1",
|
|
|
|
AccessKey: "access",
|
|
|
|
SecretKey: "secret",
|
|
|
|
RefreshInterval: Duration(60 * time.Second),
|
|
|
|
Port: 80,
|
|
|
|
},
|
|
|
|
},
|
|
|
|
},
|
2015-05-07 01:55:03 -07:00
|
|
|
},
|
2015-06-04 08:03:12 -07:00
|
|
|
original: "",
|
|
|
|
}
|
2015-05-07 01:55:03 -07:00
|
|
|
|
|
|
|
func TestLoadConfig(t *testing.T) {
|
2015-06-07 08:40:22 -07:00
|
|
|
// Parse a valid file that sets a global scrape timeout. This tests whether parsing
|
|
|
|
// an overwritten default field in the global config permanently changes the default.
|
2015-08-05 09:30:37 -07:00
|
|
|
if _, err := LoadFile("testdata/global_timeout.good.yml"); err != nil {
|
2015-06-07 08:40:22 -07:00
|
|
|
t.Errorf("Error parsing %s: %s", "testdata/conf.good.yml", err)
|
|
|
|
}
|
|
|
|
|
2015-08-05 09:30:37 -07:00
|
|
|
c, err := LoadFile("testdata/conf.good.yml")
|
2015-05-07 01:55:03 -07:00
|
|
|
if err != nil {
|
2015-06-12 04:39:59 -07:00
|
|
|
t.Fatalf("Error parsing %s: %s", "testdata/conf.good.yml", err)
|
2015-05-07 01:55:03 -07:00
|
|
|
}
|
2015-07-18 14:23:58 -07:00
|
|
|
|
2015-05-07 01:55:03 -07:00
|
|
|
bgot, err := yaml.Marshal(c)
|
|
|
|
if err != nil {
|
2015-06-12 04:39:59 -07:00
|
|
|
t.Fatalf("%s", err)
|
2015-05-07 01:55:03 -07:00
|
|
|
}
|
2015-07-18 14:23:58 -07:00
|
|
|
|
2015-05-07 01:55:03 -07:00
|
|
|
bexp, err := yaml.Marshal(expectedConf)
|
|
|
|
if err != nil {
|
2015-06-12 04:39:59 -07:00
|
|
|
t.Fatalf("%s", err)
|
2015-05-07 01:55:03 -07:00
|
|
|
}
|
|
|
|
expectedConf.original = c.original
|
2013-02-13 16:04:07 -08:00
|
|
|
|
2015-05-07 01:55:03 -07:00
|
|
|
if !reflect.DeepEqual(c, expectedConf) {
|
2015-06-12 04:39:59 -07:00
|
|
|
t.Fatalf("%s: unexpected config result: \n\n%s\n expected\n\n%s", "testdata/conf.good.yml", bgot, bexp)
|
2015-05-07 01:55:03 -07:00
|
|
|
}
|
2015-07-06 05:25:20 -07:00
|
|
|
|
|
|
|
// String method must not reveal authentication credentials.
|
|
|
|
s := c.String()
|
2015-10-08 07:13:21 -07:00
|
|
|
if strings.Contains(s, "admin_password") {
|
2015-07-06 05:25:20 -07:00
|
|
|
t.Fatalf("config's String method reveals authentication credentials.")
|
|
|
|
}
|
2015-05-07 01:55:03 -07:00
|
|
|
}
|
|
|
|
|
|
|
|
var expectedErrors = []struct {
|
|
|
|
filename string
|
|
|
|
errMsg string
|
2013-02-13 16:04:07 -08:00
|
|
|
}{
|
|
|
|
{
|
2015-05-07 01:55:03 -07:00
|
|
|
filename: "jobname.bad.yml",
|
|
|
|
errMsg: `"prom^etheus" is not a valid job name`,
|
2013-02-13 16:04:07 -08:00
|
|
|
}, {
|
2015-05-07 01:55:03 -07:00
|
|
|
filename: "jobname_dup.bad.yml",
|
|
|
|
errMsg: `found multiple scrape configs with job name "prometheus"`,
|
2013-06-11 13:59:27 -07:00
|
|
|
}, {
|
2015-05-07 01:55:03 -07:00
|
|
|
filename: "labelname.bad.yml",
|
|
|
|
errMsg: `"not$allowed" is not a valid label name`,
|
2015-06-06 00:55:22 -07:00
|
|
|
}, {
|
|
|
|
filename: "labelname2.bad.yml",
|
|
|
|
errMsg: `"not:allowed" is not a valid label name`,
|
2015-04-30 12:15:18 -07:00
|
|
|
}, {
|
2015-05-07 01:55:03 -07:00
|
|
|
filename: "regex.bad.yml",
|
|
|
|
errMsg: "error parsing regexp",
|
2015-06-10 14:40:39 -07:00
|
|
|
}, {
|
|
|
|
filename: "regex_missing.bad.yml",
|
|
|
|
errMsg: "relabel configuration requires a regular expression",
|
2015-06-24 00:07:17 -07:00
|
|
|
}, {
|
|
|
|
filename: "modulus_missing.bad.yml",
|
|
|
|
errMsg: "relabel configuration for hashmod requires non-zero modulus",
|
2015-05-27 22:36:21 -07:00
|
|
|
}, {
|
|
|
|
filename: "rules.bad.yml",
|
|
|
|
errMsg: "invalid rule file path",
|
2015-06-12 04:39:59 -07:00
|
|
|
}, {
|
|
|
|
filename: "unknown_attr.bad.yml",
|
|
|
|
errMsg: "unknown fields in scrape_config: consult_sd_configs",
|
2015-07-22 08:48:22 -07:00
|
|
|
}, {
|
|
|
|
filename: "bearertoken.bad.yml",
|
|
|
|
errMsg: "at most one of bearer_token & bearer_token_file must be configured",
|
|
|
|
}, {
|
|
|
|
filename: "bearertoken_basicauth.bad.yml",
|
|
|
|
errMsg: "at most one of basic_auth, bearer_token & bearer_token_file must be configured",
|
2015-09-02 06:08:37 -07:00
|
|
|
}, {
|
|
|
|
filename: "marathon_no_servers.bad.yml",
|
|
|
|
errMsg: "Marathon SD config must contain at least one Marathon server",
|
2013-12-03 02:59:38 -08:00
|
|
|
},
|
2013-02-13 16:04:07 -08:00
|
|
|
}
|
|
|
|
|
2015-05-07 01:55:03 -07:00
|
|
|
func TestBadConfigs(t *testing.T) {
|
|
|
|
for _, ee := range expectedErrors {
|
2015-08-05 09:30:37 -07:00
|
|
|
_, err := LoadFile("testdata/" + ee.filename)
|
2015-05-07 01:55:03 -07:00
|
|
|
if err == nil {
|
|
|
|
t.Errorf("Expected error parsing %s but got none", ee.filename)
|
2015-05-27 22:36:21 -07:00
|
|
|
continue
|
2015-05-07 01:55:03 -07:00
|
|
|
}
|
|
|
|
if !strings.Contains(err.Error(), ee.errMsg) {
|
|
|
|
t.Errorf("Expected error for %s to contain %q but got: %s", ee.filename, ee.errMsg, err)
|
2013-02-13 16:04:07 -08:00
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
2015-06-06 00:55:22 -07:00
|
|
|
|
|
|
|
func TestBadTargetGroup(t *testing.T) {
|
|
|
|
content, err := ioutil.ReadFile("testdata/tgroup.bad.json")
|
|
|
|
if err != nil {
|
|
|
|
t.Fatal(err)
|
|
|
|
}
|
|
|
|
var tg TargetGroup
|
|
|
|
err = json.Unmarshal(content, &tg)
|
|
|
|
if err == nil {
|
|
|
|
t.Errorf("Expected unmarshal error but got none.")
|
|
|
|
}
|
|
|
|
}
|
2015-07-17 07:12:33 -07:00
|
|
|
|
|
|
|
func TestEmptyConfig(t *testing.T) {
|
|
|
|
c, err := Load("")
|
|
|
|
if err != nil {
|
|
|
|
t.Fatalf("Unexpected error parsing empty config file: %s", err)
|
|
|
|
}
|
|
|
|
exp := DefaultConfig
|
|
|
|
|
|
|
|
if !reflect.DeepEqual(*c, exp) {
|
|
|
|
t.Fatalf("want %v, got %v", exp, c)
|
|
|
|
}
|
|
|
|
}
|
2015-07-17 10:58:34 -07:00
|
|
|
|
|
|
|
func TestEmptyGlobalBlock(t *testing.T) {
|
|
|
|
c, err := Load("global:\n")
|
|
|
|
if err != nil {
|
|
|
|
t.Fatalf("Unexpected error parsing empty config file: %s", err)
|
|
|
|
}
|
|
|
|
exp := DefaultConfig
|
|
|
|
exp.original = "global:\n"
|
|
|
|
|
|
|
|
if !reflect.DeepEqual(*c, exp) {
|
|
|
|
t.Fatalf("want %v, got %v", exp, c)
|
|
|
|
}
|
|
|
|
}
|
2015-09-03 02:47:09 -07:00
|
|
|
|
|
|
|
func kubernetesSDHostURL() URL {
|
|
|
|
tURL, _ := url.Parse("https://localhost:1234")
|
|
|
|
return URL{URL: tURL}
|
|
|
|
}
|