mirror of
https://github.com/prometheus/prometheus.git
synced 2025-01-11 13:57:36 -08:00
config: Make remote-write required for Agent mode (#9618)
* config: Make remote-write required for Agent mode Signed-off-by: ArthurSens <arthursens2005@gmail.com>
This commit is contained in:
parent
9da5382103
commit
be2599c853
|
@ -452,7 +452,7 @@ func main() {
|
||||||
|
|
||||||
// Throw error for invalid config before starting other components.
|
// Throw error for invalid config before starting other components.
|
||||||
var cfgFile *config.Config
|
var cfgFile *config.Config
|
||||||
if cfgFile, err = config.LoadFile(cfg.configFile, false, log.NewNopLogger()); err != nil {
|
if cfgFile, err = config.LoadFile(cfg.configFile, agentMode, false, log.NewNopLogger()); err != nil {
|
||||||
level.Error(logger).Log("msg", fmt.Sprintf("Error loading config (--config.file=%s)", cfg.configFile), "err", err)
|
level.Error(logger).Log("msg", fmt.Sprintf("Error loading config (--config.file=%s)", cfg.configFile), "err", err)
|
||||||
os.Exit(2)
|
os.Exit(2)
|
||||||
}
|
}
|
||||||
|
@ -1162,7 +1162,7 @@ func reloadConfig(filename string, expandExternalLabels bool, enableExemplarStor
|
||||||
}
|
}
|
||||||
}()
|
}()
|
||||||
|
|
||||||
conf, err := config.LoadFile(filename, expandExternalLabels, logger)
|
conf, err := config.LoadFile(filename, agentMode, expandExternalLabels, logger)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return errors.Wrapf(err, "couldn't load configuration (--config.file=%q)", filename)
|
return errors.Wrapf(err, "couldn't load configuration (--config.file=%q)", filename)
|
||||||
}
|
}
|
||||||
|
|
|
@ -37,6 +37,7 @@ import (
|
||||||
|
|
||||||
var promPath = os.Args[0]
|
var promPath = os.Args[0]
|
||||||
var promConfig = filepath.Join("..", "..", "documentation", "examples", "prometheus.yml")
|
var promConfig = filepath.Join("..", "..", "documentation", "examples", "prometheus.yml")
|
||||||
|
var agentConfig = filepath.Join("..", "..", "documentation", "examples", "prometheus-agent.yml")
|
||||||
var promData = filepath.Join(os.TempDir(), "data")
|
var promData = filepath.Join(os.TempDir(), "data")
|
||||||
|
|
||||||
func TestMain(m *testing.M) {
|
func TestMain(m *testing.M) {
|
||||||
|
@ -349,7 +350,7 @@ func getCurrentGaugeValuesFor(t *testing.T, reg prometheus.Gatherer, metricNames
|
||||||
}
|
}
|
||||||
|
|
||||||
func TestAgentSuccessfulStartup(t *testing.T) {
|
func TestAgentSuccessfulStartup(t *testing.T) {
|
||||||
prom := exec.Command(promPath, "-test.main", "--agent", "--config.file="+promConfig)
|
prom := exec.Command(promPath, "-test.main", "--agent", "--config.file="+agentConfig)
|
||||||
err := prom.Start()
|
err := prom.Start()
|
||||||
require.NoError(t, err)
|
require.NoError(t, err)
|
||||||
|
|
||||||
|
@ -367,3 +368,23 @@ func TestAgentSuccessfulStartup(t *testing.T) {
|
||||||
}
|
}
|
||||||
require.Equal(t, expectedExitStatus, actualExitStatus)
|
require.Equal(t, expectedExitStatus, actualExitStatus)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
func TestAgentStartupWithInvalidConfig(t *testing.T) {
|
||||||
|
prom := exec.Command(promPath, "-test.main", "--agent", "--config.file="+promConfig)
|
||||||
|
err := prom.Start()
|
||||||
|
require.NoError(t, err)
|
||||||
|
|
||||||
|
expectedExitStatus := 2
|
||||||
|
actualExitStatus := 0
|
||||||
|
|
||||||
|
done := make(chan error, 1)
|
||||||
|
go func() { done <- prom.Wait() }()
|
||||||
|
select {
|
||||||
|
case err := <-done:
|
||||||
|
t.Logf("prometheus agent should not be running: %v", err)
|
||||||
|
actualExitStatus = prom.ProcessState.ExitCode()
|
||||||
|
case <-time.After(5 * time.Second):
|
||||||
|
prom.Process.Kill()
|
||||||
|
}
|
||||||
|
require.Equal(t, expectedExitStatus, actualExitStatus)
|
||||||
|
}
|
||||||
|
|
|
@ -82,6 +82,7 @@ func main() {
|
||||||
).Required().ExistingFiles()
|
).Required().ExistingFiles()
|
||||||
|
|
||||||
checkMetricsCmd := checkCmd.Command("metrics", checkMetricsUsage)
|
checkMetricsCmd := checkCmd.Command("metrics", checkMetricsUsage)
|
||||||
|
agentMode := checkConfigCmd.Flag("agent", "Check config file for Prometheus in Agent mode.").Bool()
|
||||||
|
|
||||||
queryCmd := app.Command("query", "Run query against a Prometheus server.")
|
queryCmd := app.Command("query", "Run query against a Prometheus server.")
|
||||||
queryCmdFmt := queryCmd.Flag("format", "Output format of the query.").Short('o').Default("promql").Enum("promql", "json")
|
queryCmdFmt := queryCmd.Flag("format", "Output format of the query.").Short('o').Default("promql").Enum("promql", "json")
|
||||||
|
@ -202,7 +203,7 @@ func main() {
|
||||||
|
|
||||||
switch parsedCmd {
|
switch parsedCmd {
|
||||||
case checkConfigCmd.FullCommand():
|
case checkConfigCmd.FullCommand():
|
||||||
os.Exit(CheckConfig(*configFiles...))
|
os.Exit(CheckConfig(*agentMode, *configFiles...))
|
||||||
|
|
||||||
case checkWebConfigCmd.FullCommand():
|
case checkWebConfigCmd.FullCommand():
|
||||||
os.Exit(CheckWebConfig(*webConfigFiles...))
|
os.Exit(CheckWebConfig(*webConfigFiles...))
|
||||||
|
@ -258,11 +259,11 @@ func main() {
|
||||||
}
|
}
|
||||||
|
|
||||||
// CheckConfig validates configuration files.
|
// CheckConfig validates configuration files.
|
||||||
func CheckConfig(files ...string) int {
|
func CheckConfig(agentMode bool, files ...string) int {
|
||||||
failed := false
|
failed := false
|
||||||
|
|
||||||
for _, f := range files {
|
for _, f := range files {
|
||||||
ruleFiles, err := checkConfig(f)
|
ruleFiles, err := checkConfig(agentMode, f)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
fmt.Fprintln(os.Stderr, " FAILED:", err)
|
fmt.Fprintln(os.Stderr, " FAILED:", err)
|
||||||
failed = true
|
failed = true
|
||||||
|
@ -317,10 +318,10 @@ func checkFileExists(fn string) error {
|
||||||
return err
|
return err
|
||||||
}
|
}
|
||||||
|
|
||||||
func checkConfig(filename string) ([]string, error) {
|
func checkConfig(agentMode bool, filename string) ([]string, error) {
|
||||||
fmt.Println("Checking", filename)
|
fmt.Println("Checking", filename)
|
||||||
|
|
||||||
cfg, err := config.LoadFile(filename, false, log.NewNopLogger())
|
cfg, err := config.LoadFile(filename, agentMode, false, log.NewNopLogger())
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return nil, err
|
return nil, err
|
||||||
}
|
}
|
||||||
|
|
|
@ -193,7 +193,7 @@ func TestCheckTargetConfig(t *testing.T) {
|
||||||
}
|
}
|
||||||
for _, test := range cases {
|
for _, test := range cases {
|
||||||
t.Run(test.name, func(t *testing.T) {
|
t.Run(test.name, func(t *testing.T) {
|
||||||
_, err := checkConfig("testdata/" + test.file)
|
_, err := checkConfig(false, "testdata/"+test.file)
|
||||||
if test.err != "" {
|
if test.err != "" {
|
||||||
require.Equalf(t, test.err, err.Error(), "Expected error %q, got %q", test.err, err.Error())
|
require.Equalf(t, test.err, err.Error(), "Expected error %q, got %q", test.err, err.Error())
|
||||||
return
|
return
|
||||||
|
|
|
@ -99,7 +99,7 @@ func Load(s string, expandExternalLabels bool, logger log.Logger) (*Config, erro
|
||||||
}
|
}
|
||||||
|
|
||||||
// LoadFile parses the given YAML file into a Config.
|
// LoadFile parses the given YAML file into a Config.
|
||||||
func LoadFile(filename string, expandExternalLabels bool, logger log.Logger) (*Config, error) {
|
func LoadFile(filename string, agentMode bool, expandExternalLabels bool, logger log.Logger) (*Config, error) {
|
||||||
content, err := ioutil.ReadFile(filename)
|
content, err := ioutil.ReadFile(filename)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return nil, err
|
return nil, err
|
||||||
|
@ -108,6 +108,25 @@ func LoadFile(filename string, expandExternalLabels bool, logger log.Logger) (*C
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return nil, errors.Wrapf(err, "parsing YAML file %s", filename)
|
return nil, errors.Wrapf(err, "parsing YAML file %s", filename)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
if agentMode {
|
||||||
|
if len(cfg.RemoteWriteConfigs) == 0 {
|
||||||
|
return nil, errors.New("at least one remote_write target must be specified in agent mode")
|
||||||
|
}
|
||||||
|
|
||||||
|
if len(cfg.AlertingConfig.AlertmanagerConfigs) > 0 || len(cfg.AlertingConfig.AlertRelabelConfigs) > 0 {
|
||||||
|
return nil, errors.New("field alerting is not allowed in agent mode")
|
||||||
|
}
|
||||||
|
|
||||||
|
if len(cfg.RuleFiles) > 0 {
|
||||||
|
return nil, errors.New("field rule_files is not allowed in agent mode")
|
||||||
|
}
|
||||||
|
|
||||||
|
if len(cfg.RemoteReadConfigs) > 0 {
|
||||||
|
return nil, errors.New("field remote_read is not allowed in agent mode")
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
cfg.SetDirectory(filepath.Dir(filename))
|
cfg.SetDirectory(filepath.Dir(filename))
|
||||||
return cfg, nil
|
return cfg, nil
|
||||||
}
|
}
|
||||||
|
|
|
@ -986,7 +986,7 @@ var expectedConf = &Config{
|
||||||
}
|
}
|
||||||
|
|
||||||
func TestYAMLRoundtrip(t *testing.T) {
|
func TestYAMLRoundtrip(t *testing.T) {
|
||||||
want, err := LoadFile("testdata/roundtrip.good.yml", false, log.NewNopLogger())
|
want, err := LoadFile("testdata/roundtrip.good.yml", false, false, log.NewNopLogger())
|
||||||
require.NoError(t, err)
|
require.NoError(t, err)
|
||||||
|
|
||||||
out, err := yaml.Marshal(want)
|
out, err := yaml.Marshal(want)
|
||||||
|
@ -999,7 +999,7 @@ func TestYAMLRoundtrip(t *testing.T) {
|
||||||
}
|
}
|
||||||
|
|
||||||
func TestRemoteWriteRetryOnRateLimit(t *testing.T) {
|
func TestRemoteWriteRetryOnRateLimit(t *testing.T) {
|
||||||
want, err := LoadFile("testdata/remote_write_retry_on_rate_limit.good.yml", false, log.NewNopLogger())
|
want, err := LoadFile("testdata/remote_write_retry_on_rate_limit.good.yml", false, false, log.NewNopLogger())
|
||||||
require.NoError(t, err)
|
require.NoError(t, err)
|
||||||
|
|
||||||
out, err := yaml.Marshal(want)
|
out, err := yaml.Marshal(want)
|
||||||
|
@ -1015,16 +1015,16 @@ func TestRemoteWriteRetryOnRateLimit(t *testing.T) {
|
||||||
func TestLoadConfig(t *testing.T) {
|
func TestLoadConfig(t *testing.T) {
|
||||||
// Parse a valid file that sets a global scrape timeout. This tests whether parsing
|
// 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.
|
// an overwritten default field in the global config permanently changes the default.
|
||||||
_, err := LoadFile("testdata/global_timeout.good.yml", false, log.NewNopLogger())
|
_, err := LoadFile("testdata/global_timeout.good.yml", false, false, log.NewNopLogger())
|
||||||
require.NoError(t, err)
|
require.NoError(t, err)
|
||||||
|
|
||||||
c, err := LoadFile("testdata/conf.good.yml", false, log.NewNopLogger())
|
c, err := LoadFile("testdata/conf.good.yml", false, false, log.NewNopLogger())
|
||||||
require.NoError(t, err)
|
require.NoError(t, err)
|
||||||
require.Equal(t, expectedConf, c)
|
require.Equal(t, expectedConf, c)
|
||||||
}
|
}
|
||||||
|
|
||||||
func TestScrapeIntervalLarger(t *testing.T) {
|
func TestScrapeIntervalLarger(t *testing.T) {
|
||||||
c, err := LoadFile("testdata/scrape_interval_larger.good.yml", false, log.NewNopLogger())
|
c, err := LoadFile("testdata/scrape_interval_larger.good.yml", false, false, log.NewNopLogger())
|
||||||
require.NoError(t, err)
|
require.NoError(t, err)
|
||||||
require.Equal(t, 1, len(c.ScrapeConfigs))
|
require.Equal(t, 1, len(c.ScrapeConfigs))
|
||||||
for _, sc := range c.ScrapeConfigs {
|
for _, sc := range c.ScrapeConfigs {
|
||||||
|
@ -1034,7 +1034,7 @@ func TestScrapeIntervalLarger(t *testing.T) {
|
||||||
|
|
||||||
// YAML marshaling must not reveal authentication credentials.
|
// YAML marshaling must not reveal authentication credentials.
|
||||||
func TestElideSecrets(t *testing.T) {
|
func TestElideSecrets(t *testing.T) {
|
||||||
c, err := LoadFile("testdata/conf.good.yml", false, log.NewNopLogger())
|
c, err := LoadFile("testdata/conf.good.yml", false, false, log.NewNopLogger())
|
||||||
require.NoError(t, err)
|
require.NoError(t, err)
|
||||||
|
|
||||||
secretRe := regexp.MustCompile(`\\u003csecret\\u003e|<secret>`)
|
secretRe := regexp.MustCompile(`\\u003csecret\\u003e|<secret>`)
|
||||||
|
@ -1051,31 +1051,31 @@ func TestElideSecrets(t *testing.T) {
|
||||||
|
|
||||||
func TestLoadConfigRuleFilesAbsolutePath(t *testing.T) {
|
func TestLoadConfigRuleFilesAbsolutePath(t *testing.T) {
|
||||||
// Parse a valid file that sets a rule files with an absolute path
|
// Parse a valid file that sets a rule files with an absolute path
|
||||||
c, err := LoadFile(ruleFilesConfigFile, false, log.NewNopLogger())
|
c, err := LoadFile(ruleFilesConfigFile, false, false, log.NewNopLogger())
|
||||||
require.NoError(t, err)
|
require.NoError(t, err)
|
||||||
require.Equal(t, ruleFilesExpectedConf, c)
|
require.Equal(t, ruleFilesExpectedConf, c)
|
||||||
}
|
}
|
||||||
|
|
||||||
func TestKubernetesEmptyAPIServer(t *testing.T) {
|
func TestKubernetesEmptyAPIServer(t *testing.T) {
|
||||||
_, err := LoadFile("testdata/kubernetes_empty_apiserver.good.yml", false, log.NewNopLogger())
|
_, err := LoadFile("testdata/kubernetes_empty_apiserver.good.yml", false, false, log.NewNopLogger())
|
||||||
require.NoError(t, err)
|
require.NoError(t, err)
|
||||||
}
|
}
|
||||||
|
|
||||||
func TestKubernetesWithKubeConfig(t *testing.T) {
|
func TestKubernetesWithKubeConfig(t *testing.T) {
|
||||||
_, err := LoadFile("testdata/kubernetes_kubeconfig_without_apiserver.good.yml", false, log.NewNopLogger())
|
_, err := LoadFile("testdata/kubernetes_kubeconfig_without_apiserver.good.yml", false, false, log.NewNopLogger())
|
||||||
require.NoError(t, err)
|
require.NoError(t, err)
|
||||||
}
|
}
|
||||||
|
|
||||||
func TestKubernetesSelectors(t *testing.T) {
|
func TestKubernetesSelectors(t *testing.T) {
|
||||||
_, err := LoadFile("testdata/kubernetes_selectors_endpoints.good.yml", false, log.NewNopLogger())
|
_, err := LoadFile("testdata/kubernetes_selectors_endpoints.good.yml", false, false, log.NewNopLogger())
|
||||||
require.NoError(t, err)
|
require.NoError(t, err)
|
||||||
_, err = LoadFile("testdata/kubernetes_selectors_node.good.yml", false, log.NewNopLogger())
|
_, err = LoadFile("testdata/kubernetes_selectors_node.good.yml", false, false, log.NewNopLogger())
|
||||||
require.NoError(t, err)
|
require.NoError(t, err)
|
||||||
_, err = LoadFile("testdata/kubernetes_selectors_ingress.good.yml", false, log.NewNopLogger())
|
_, err = LoadFile("testdata/kubernetes_selectors_ingress.good.yml", false, false, log.NewNopLogger())
|
||||||
require.NoError(t, err)
|
require.NoError(t, err)
|
||||||
_, err = LoadFile("testdata/kubernetes_selectors_pod.good.yml", false, log.NewNopLogger())
|
_, err = LoadFile("testdata/kubernetes_selectors_pod.good.yml", false, false, log.NewNopLogger())
|
||||||
require.NoError(t, err)
|
require.NoError(t, err)
|
||||||
_, err = LoadFile("testdata/kubernetes_selectors_service.good.yml", false, log.NewNopLogger())
|
_, err = LoadFile("testdata/kubernetes_selectors_service.good.yml", false, false, log.NewNopLogger())
|
||||||
require.NoError(t, err)
|
require.NoError(t, err)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -1381,7 +1381,7 @@ var expectedErrors = []struct {
|
||||||
|
|
||||||
func TestBadConfigs(t *testing.T) {
|
func TestBadConfigs(t *testing.T) {
|
||||||
for _, ee := range expectedErrors {
|
for _, ee := range expectedErrors {
|
||||||
_, err := LoadFile("testdata/"+ee.filename, false, log.NewNopLogger())
|
_, err := LoadFile("testdata/"+ee.filename, false, false, log.NewNopLogger())
|
||||||
require.Error(t, err, "%s", ee.filename)
|
require.Error(t, err, "%s", ee.filename)
|
||||||
require.Contains(t, err.Error(), ee.errMsg,
|
require.Contains(t, err.Error(), ee.errMsg,
|
||||||
"Expected error for %s to contain %q but got: %s", ee.filename, ee.errMsg, err)
|
"Expected error for %s to contain %q but got: %s", ee.filename, ee.errMsg, err)
|
||||||
|
@ -1415,20 +1415,20 @@ func TestExpandExternalLabels(t *testing.T) {
|
||||||
// Cleanup ant TEST env variable that could exist on the system.
|
// Cleanup ant TEST env variable that could exist on the system.
|
||||||
os.Setenv("TEST", "")
|
os.Setenv("TEST", "")
|
||||||
|
|
||||||
c, err := LoadFile("testdata/external_labels.good.yml", false, log.NewNopLogger())
|
c, err := LoadFile("testdata/external_labels.good.yml", false, false, log.NewNopLogger())
|
||||||
require.NoError(t, err)
|
require.NoError(t, err)
|
||||||
require.Equal(t, labels.Label{Name: "bar", Value: "foo"}, c.GlobalConfig.ExternalLabels[0])
|
require.Equal(t, labels.Label{Name: "bar", Value: "foo"}, c.GlobalConfig.ExternalLabels[0])
|
||||||
require.Equal(t, labels.Label{Name: "baz", Value: "foo${TEST}bar"}, c.GlobalConfig.ExternalLabels[1])
|
require.Equal(t, labels.Label{Name: "baz", Value: "foo${TEST}bar"}, c.GlobalConfig.ExternalLabels[1])
|
||||||
require.Equal(t, labels.Label{Name: "foo", Value: "${TEST}"}, c.GlobalConfig.ExternalLabels[2])
|
require.Equal(t, labels.Label{Name: "foo", Value: "${TEST}"}, c.GlobalConfig.ExternalLabels[2])
|
||||||
|
|
||||||
c, err = LoadFile("testdata/external_labels.good.yml", true, log.NewNopLogger())
|
c, err = LoadFile("testdata/external_labels.good.yml", false, true, log.NewNopLogger())
|
||||||
require.NoError(t, err)
|
require.NoError(t, err)
|
||||||
require.Equal(t, labels.Label{Name: "bar", Value: "foo"}, c.GlobalConfig.ExternalLabels[0])
|
require.Equal(t, labels.Label{Name: "bar", Value: "foo"}, c.GlobalConfig.ExternalLabels[0])
|
||||||
require.Equal(t, labels.Label{Name: "baz", Value: "foobar"}, c.GlobalConfig.ExternalLabels[1])
|
require.Equal(t, labels.Label{Name: "baz", Value: "foobar"}, c.GlobalConfig.ExternalLabels[1])
|
||||||
require.Equal(t, labels.Label{Name: "foo", Value: ""}, c.GlobalConfig.ExternalLabels[2])
|
require.Equal(t, labels.Label{Name: "foo", Value: ""}, c.GlobalConfig.ExternalLabels[2])
|
||||||
|
|
||||||
os.Setenv("TEST", "TestValue")
|
os.Setenv("TEST", "TestValue")
|
||||||
c, err = LoadFile("testdata/external_labels.good.yml", true, log.NewNopLogger())
|
c, err = LoadFile("testdata/external_labels.good.yml", false, true, log.NewNopLogger())
|
||||||
require.NoError(t, err)
|
require.NoError(t, err)
|
||||||
require.Equal(t, labels.Label{Name: "bar", Value: "foo"}, c.GlobalConfig.ExternalLabels[0])
|
require.Equal(t, labels.Label{Name: "bar", Value: "foo"}, c.GlobalConfig.ExternalLabels[0])
|
||||||
require.Equal(t, labels.Label{Name: "baz", Value: "fooTestValuebar"}, c.GlobalConfig.ExternalLabels[1])
|
require.Equal(t, labels.Label{Name: "baz", Value: "fooTestValuebar"}, c.GlobalConfig.ExternalLabels[1])
|
||||||
|
|
22
documentation/examples/prometheus-agent.yml
Normal file
22
documentation/examples/prometheus-agent.yml
Normal file
|
@ -0,0 +1,22 @@
|
||||||
|
# my global config
|
||||||
|
global:
|
||||||
|
scrape_interval: 15s # Set the scrape interval to every 15 seconds. Default is every 1 minute.
|
||||||
|
evaluation_interval: 15s # Evaluate rules every 15 seconds. The default is every 1 minute.
|
||||||
|
# scrape_timeout is set to the global default (10s).
|
||||||
|
|
||||||
|
# A scrape configuration containing exactly one endpoint to scrape:
|
||||||
|
# Here it's Prometheus itself.
|
||||||
|
scrape_configs:
|
||||||
|
# The job name is added as a label `job=<job_name>` to any timeseries scraped from this config.
|
||||||
|
- job_name: "prometheus"
|
||||||
|
|
||||||
|
# metrics_path defaults to '/metrics'
|
||||||
|
# scheme defaults to 'http'.
|
||||||
|
|
||||||
|
static_configs:
|
||||||
|
- targets: ["localhost:9090"]
|
||||||
|
|
||||||
|
# When running prometheus in Agent mode, remote-write is required.
|
||||||
|
remote_write:
|
||||||
|
# Agent is able to run with a invalid remote-write URL, but, of course, will fail to push timeseries.
|
||||||
|
- url: "http://remote-write-url"
|
Loading…
Reference in a new issue