mirror of
https://github.com/prometheus/prometheus.git
synced 2025-03-05 20:59:13 -08:00
Expose TargetsFromGroup/AlertmanagerFromGroup func and reuse this for (#9343)
static/file sd config check in promtool Signed-off-by: DrAuYueng <ouyang1204@gmail.com>
This commit is contained in:
parent
8207b132fd
commit
69e309d202
|
@ -44,13 +44,16 @@ import (
|
||||||
yaml "gopkg.in/yaml.v2"
|
yaml "gopkg.in/yaml.v2"
|
||||||
|
|
||||||
"github.com/prometheus/prometheus/config"
|
"github.com/prometheus/prometheus/config"
|
||||||
|
"github.com/prometheus/prometheus/discovery"
|
||||||
"github.com/prometheus/prometheus/discovery/file"
|
"github.com/prometheus/prometheus/discovery/file"
|
||||||
_ "github.com/prometheus/prometheus/discovery/install" // Register service discovery implementations.
|
_ "github.com/prometheus/prometheus/discovery/install" // Register service discovery implementations.
|
||||||
"github.com/prometheus/prometheus/discovery/kubernetes"
|
"github.com/prometheus/prometheus/discovery/kubernetes"
|
||||||
"github.com/prometheus/prometheus/discovery/targetgroup"
|
"github.com/prometheus/prometheus/discovery/targetgroup"
|
||||||
|
"github.com/prometheus/prometheus/notifier"
|
||||||
"github.com/prometheus/prometheus/pkg/labels"
|
"github.com/prometheus/prometheus/pkg/labels"
|
||||||
"github.com/prometheus/prometheus/pkg/rulefmt"
|
"github.com/prometheus/prometheus/pkg/rulefmt"
|
||||||
"github.com/prometheus/prometheus/promql"
|
"github.com/prometheus/prometheus/promql"
|
||||||
|
"github.com/prometheus/prometheus/scrape"
|
||||||
)
|
)
|
||||||
|
|
||||||
func main() {
|
func main() {
|
||||||
|
@ -363,19 +366,60 @@ func checkConfig(filename string) ([]string, error) {
|
||||||
}
|
}
|
||||||
if len(files) != 0 {
|
if len(files) != 0 {
|
||||||
for _, f := range files {
|
for _, f := range files {
|
||||||
err = checkSDFile(f)
|
var targetGroups []*targetgroup.Group
|
||||||
|
targetGroups, err = checkSDFile(f)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return nil, errors.Errorf("checking SD file %q: %v", file, err)
|
return nil, errors.Errorf("checking SD file %q: %v", file, err)
|
||||||
}
|
}
|
||||||
|
if err := checkTargetGroupsForScrapeConfig(targetGroups, scfg); err != nil {
|
||||||
|
return nil, err
|
||||||
|
}
|
||||||
}
|
}
|
||||||
continue
|
continue
|
||||||
}
|
}
|
||||||
fmt.Printf(" WARNING: file %q for file_sd in scrape job %q does not exist\n", file, scfg.JobName)
|
fmt.Printf(" WARNING: file %q for file_sd in scrape job %q does not exist\n", file, scfg.JobName)
|
||||||
}
|
}
|
||||||
|
case discovery.StaticConfig:
|
||||||
|
if err := checkTargetGroupsForScrapeConfig(c, scfg); err != nil {
|
||||||
|
return nil, err
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
alertConfig := cfg.AlertingConfig
|
||||||
|
for _, amcfg := range alertConfig.AlertmanagerConfigs {
|
||||||
|
for _, c := range amcfg.ServiceDiscoveryConfigs {
|
||||||
|
switch c := c.(type) {
|
||||||
|
case *file.SDConfig:
|
||||||
|
for _, file := range c.Files {
|
||||||
|
files, err := filepath.Glob(file)
|
||||||
|
if err != nil {
|
||||||
|
return nil, err
|
||||||
|
}
|
||||||
|
if len(files) != 0 {
|
||||||
|
for _, f := range files {
|
||||||
|
var targetGroups []*targetgroup.Group
|
||||||
|
targetGroups, err = checkSDFile(f)
|
||||||
|
if err != nil {
|
||||||
|
return nil, errors.Errorf("checking SD file %q: %v", file, err)
|
||||||
|
}
|
||||||
|
|
||||||
|
if err := checkTargetGroupsForAlertmanager(targetGroups, amcfg); err != nil {
|
||||||
|
return nil, err
|
||||||
|
}
|
||||||
|
}
|
||||||
|
continue
|
||||||
|
}
|
||||||
|
fmt.Printf(" WARNING: file %q for file_sd in alertmanager config does not exist\n", file)
|
||||||
|
}
|
||||||
|
case discovery.StaticConfig:
|
||||||
|
if err := checkTargetGroupsForAlertmanager(c, amcfg); err != nil {
|
||||||
|
return nil, err
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
return ruleFiles, nil
|
return ruleFiles, nil
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -397,16 +441,16 @@ func checkTLSConfig(tlsConfig config_util.TLSConfig) error {
|
||||||
return nil
|
return nil
|
||||||
}
|
}
|
||||||
|
|
||||||
func checkSDFile(filename string) error {
|
func checkSDFile(filename string) ([]*targetgroup.Group, error) {
|
||||||
fd, err := os.Open(filename)
|
fd, err := os.Open(filename)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return err
|
return nil, err
|
||||||
}
|
}
|
||||||
defer fd.Close()
|
defer fd.Close()
|
||||||
|
|
||||||
content, err := ioutil.ReadAll(fd)
|
content, err := ioutil.ReadAll(fd)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return err
|
return nil, err
|
||||||
}
|
}
|
||||||
|
|
||||||
var targetGroups []*targetgroup.Group
|
var targetGroups []*targetgroup.Group
|
||||||
|
@ -414,23 +458,23 @@ func checkSDFile(filename string) error {
|
||||||
switch ext := filepath.Ext(filename); strings.ToLower(ext) {
|
switch ext := filepath.Ext(filename); strings.ToLower(ext) {
|
||||||
case ".json":
|
case ".json":
|
||||||
if err := json.Unmarshal(content, &targetGroups); err != nil {
|
if err := json.Unmarshal(content, &targetGroups); err != nil {
|
||||||
return err
|
return nil, err
|
||||||
}
|
}
|
||||||
case ".yml", ".yaml":
|
case ".yml", ".yaml":
|
||||||
if err := yaml.UnmarshalStrict(content, &targetGroups); err != nil {
|
if err := yaml.UnmarshalStrict(content, &targetGroups); err != nil {
|
||||||
return err
|
return nil, err
|
||||||
}
|
}
|
||||||
default:
|
default:
|
||||||
return errors.Errorf("invalid file extension: %q", ext)
|
return nil, errors.Errorf("invalid file extension: %q", ext)
|
||||||
}
|
}
|
||||||
|
|
||||||
for i, tg := range targetGroups {
|
for i, tg := range targetGroups {
|
||||||
if tg == nil {
|
if tg == nil {
|
||||||
return errors.Errorf("nil target group item found (index %d)", i)
|
return nil, errors.Errorf("nil target group item found (index %d)", i)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
return nil
|
return targetGroups, nil
|
||||||
}
|
}
|
||||||
|
|
||||||
// CheckRules validates rule files.
|
// CheckRules validates rule files.
|
||||||
|
@ -981,3 +1025,25 @@ func importRules(url *url.URL, start, end, outputDir string, evalInterval time.D
|
||||||
|
|
||||||
return nil
|
return nil
|
||||||
}
|
}
|
||||||
|
|
||||||
|
func checkTargetGroupsForAlertmanager(targetGroups []*targetgroup.Group, amcfg *config.AlertmanagerConfig) error {
|
||||||
|
for _, tg := range targetGroups {
|
||||||
|
if _, _, err := notifier.AlertmanagerFromGroup(tg, amcfg); err != nil {
|
||||||
|
return err
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
return nil
|
||||||
|
}
|
||||||
|
|
||||||
|
func checkTargetGroupsForScrapeConfig(targetGroups []*targetgroup.Group, scfg *config.ScrapeConfig) error {
|
||||||
|
for _, tg := range targetGroups {
|
||||||
|
_, failures := scrape.TargetsFromGroup(tg, scfg)
|
||||||
|
if len(failures) > 0 {
|
||||||
|
first := failures[0]
|
||||||
|
return first
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
return nil
|
||||||
|
}
|
||||||
|
|
|
@ -111,7 +111,7 @@ func TestCheckSDFile(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 := checkSDFile(test.file)
|
_, err := checkSDFile(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
|
||||||
|
@ -163,3 +163,42 @@ func BenchmarkCheckDuplicates(b *testing.B) {
|
||||||
checkDuplicates(rgs.Groups)
|
checkDuplicates(rgs.Groups)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
func TestCheckTargetConfig(t *testing.T) {
|
||||||
|
cases := []struct {
|
||||||
|
name string
|
||||||
|
file string
|
||||||
|
err string
|
||||||
|
}{
|
||||||
|
{
|
||||||
|
name: "url_in_scrape_targetgroup_with_relabel_config.good",
|
||||||
|
file: "url_in_scrape_targetgroup_with_relabel_config.good.yml",
|
||||||
|
err: "",
|
||||||
|
},
|
||||||
|
{
|
||||||
|
name: "url_in_alert_targetgroup_with_relabel_config.good",
|
||||||
|
file: "url_in_alert_targetgroup_with_relabel_config.good.yml",
|
||||||
|
err: "",
|
||||||
|
},
|
||||||
|
{
|
||||||
|
name: "url_in_scrape_targetgroup_with_relabel_config.bad",
|
||||||
|
file: "url_in_scrape_targetgroup_with_relabel_config.bad.yml",
|
||||||
|
err: "instance 0 in group 0: \"http://bad\" is not a valid hostname",
|
||||||
|
},
|
||||||
|
{
|
||||||
|
name: "url_in_alert_targetgroup_with_relabel_config.bad",
|
||||||
|
file: "url_in_alert_targetgroup_with_relabel_config.bad.yml",
|
||||||
|
err: "\"http://bad\" is not a valid hostname",
|
||||||
|
},
|
||||||
|
}
|
||||||
|
for _, test := range cases {
|
||||||
|
t.Run(test.name, func(t *testing.T) {
|
||||||
|
_, err := checkConfig("testdata/" + test.file)
|
||||||
|
if test.err != "" {
|
||||||
|
require.Equalf(t, test.err, err.Error(), "Expected error %q, got %q", test.err, err.Error())
|
||||||
|
return
|
||||||
|
}
|
||||||
|
require.NoError(t, err)
|
||||||
|
})
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
8
cmd/promtool/testdata/url_in_alert_targetgroup_with_relabel_config.bad.yml
vendored
Normal file
8
cmd/promtool/testdata/url_in_alert_targetgroup_with_relabel_config.bad.yml
vendored
Normal file
|
@ -0,0 +1,8 @@
|
||||||
|
alerting:
|
||||||
|
alertmanagers:
|
||||||
|
- relabel_configs:
|
||||||
|
- source_labels: [__address__]
|
||||||
|
target_label: __param_target
|
||||||
|
static_configs:
|
||||||
|
- targets:
|
||||||
|
- http://bad
|
10
cmd/promtool/testdata/url_in_alert_targetgroup_with_relabel_config.good.yml
vendored
Normal file
10
cmd/promtool/testdata/url_in_alert_targetgroup_with_relabel_config.good.yml
vendored
Normal file
|
@ -0,0 +1,10 @@
|
||||||
|
alerting:
|
||||||
|
alertmanagers:
|
||||||
|
- relabel_configs:
|
||||||
|
- source_labels: [__address__]
|
||||||
|
target_label: __param_target
|
||||||
|
- target_label: __address__
|
||||||
|
replacement: good
|
||||||
|
static_configs:
|
||||||
|
- targets:
|
||||||
|
- http://bad
|
8
cmd/promtool/testdata/url_in_scrape_targetgroup_with_relabel_config.bad.yml
vendored
Normal file
8
cmd/promtool/testdata/url_in_scrape_targetgroup_with_relabel_config.bad.yml
vendored
Normal file
|
@ -0,0 +1,8 @@
|
||||||
|
scrape_configs:
|
||||||
|
- job_name: prometheus
|
||||||
|
relabel_configs:
|
||||||
|
- source_labels: [__address__]
|
||||||
|
target_label: __param_target
|
||||||
|
static_configs:
|
||||||
|
- targets:
|
||||||
|
- http://bad
|
10
cmd/promtool/testdata/url_in_scrape_targetgroup_with_relabel_config.good.yml
vendored
Normal file
10
cmd/promtool/testdata/url_in_scrape_targetgroup_with_relabel_config.good.yml
vendored
Normal file
|
@ -0,0 +1,10 @@
|
||||||
|
scrape_configs:
|
||||||
|
- job_name: prometheus
|
||||||
|
relabel_configs:
|
||||||
|
- source_labels: [__address__]
|
||||||
|
target_label: __param_target
|
||||||
|
- target_label: __address__
|
||||||
|
replacement: good
|
||||||
|
static_configs:
|
||||||
|
- targets:
|
||||||
|
- http://good
|
|
@ -602,7 +602,7 @@ func (n *Manager) Stop() {
|
||||||
n.cancel()
|
n.cancel()
|
||||||
}
|
}
|
||||||
|
|
||||||
// alertmanager holds Alertmanager endpoint information.
|
// Alertmanager holds Alertmanager endpoint information.
|
||||||
type alertmanager interface {
|
type alertmanager interface {
|
||||||
url() *url.URL
|
url() *url.URL
|
||||||
}
|
}
|
||||||
|
@ -654,7 +654,7 @@ func (s *alertmanagerSet) sync(tgs []*targetgroup.Group) {
|
||||||
allDroppedAms := []alertmanager{}
|
allDroppedAms := []alertmanager{}
|
||||||
|
|
||||||
for _, tg := range tgs {
|
for _, tg := range tgs {
|
||||||
ams, droppedAms, err := alertmanagerFromGroup(tg, s.cfg)
|
ams, droppedAms, err := AlertmanagerFromGroup(tg, s.cfg)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
level.Error(s.logger).Log("msg", "Creating discovered Alertmanagers failed", "err", err)
|
level.Error(s.logger).Log("msg", "Creating discovered Alertmanagers failed", "err", err)
|
||||||
continue
|
continue
|
||||||
|
@ -691,9 +691,9 @@ func postPath(pre string, v config.AlertmanagerAPIVersion) string {
|
||||||
return path.Join("/", pre, alertPushEndpoint)
|
return path.Join("/", pre, alertPushEndpoint)
|
||||||
}
|
}
|
||||||
|
|
||||||
// alertmanagerFromGroup extracts a list of alertmanagers from a target group
|
// AlertmanagerFromGroup extracts a list of alertmanagers from a target group
|
||||||
// and an associated AlertmanagerConfig.
|
// and an associated AlertmanagerConfig.
|
||||||
func alertmanagerFromGroup(tg *targetgroup.Group, cfg *config.AlertmanagerConfig) ([]alertmanager, []alertmanager, error) {
|
func AlertmanagerFromGroup(tg *targetgroup.Group, cfg *config.AlertmanagerConfig) ([]alertmanager, []alertmanager, error) {
|
||||||
var res []alertmanager
|
var res []alertmanager
|
||||||
var droppedAlertManagers []alertmanager
|
var droppedAlertManagers []alertmanager
|
||||||
|
|
||||||
|
|
|
@ -447,7 +447,7 @@ func (a alertmanagerMock) url() *url.URL {
|
||||||
|
|
||||||
func TestLabelSetNotReused(t *testing.T) {
|
func TestLabelSetNotReused(t *testing.T) {
|
||||||
tg := makeInputTargetGroup()
|
tg := makeInputTargetGroup()
|
||||||
_, _, err := alertmanagerFromGroup(tg, &config.AlertmanagerConfig{})
|
_, _, err := AlertmanagerFromGroup(tg, &config.AlertmanagerConfig{})
|
||||||
|
|
||||||
require.NoError(t, err)
|
require.NoError(t, err)
|
||||||
|
|
||||||
|
|
|
@ -472,7 +472,7 @@ func (sp *scrapePool) Sync(tgs []*targetgroup.Group) {
|
||||||
var all []*Target
|
var all []*Target
|
||||||
sp.droppedTargets = []*Target{}
|
sp.droppedTargets = []*Target{}
|
||||||
for _, tg := range tgs {
|
for _, tg := range tgs {
|
||||||
targets, failures := targetsFromGroup(tg, sp.config)
|
targets, failures := TargetsFromGroup(tg, sp.config)
|
||||||
for _, err := range failures {
|
for _, err := range failures {
|
||||||
level.Error(sp.logger).Log("msg", "Creating target failed", "err", err)
|
level.Error(sp.logger).Log("msg", "Creating target failed", "err", err)
|
||||||
}
|
}
|
||||||
|
|
|
@ -469,8 +469,8 @@ func populateLabels(lset labels.Labels, cfg *config.ScrapeConfig) (res, orig lab
|
||||||
return res, preRelabelLabels, nil
|
return res, preRelabelLabels, nil
|
||||||
}
|
}
|
||||||
|
|
||||||
// targetsFromGroup builds targets based on the given TargetGroup and config.
|
// TargetsFromGroup builds targets based on the given TargetGroup and config.
|
||||||
func targetsFromGroup(tg *targetgroup.Group, cfg *config.ScrapeConfig) ([]*Target, []error) {
|
func TargetsFromGroup(tg *targetgroup.Group, cfg *config.ScrapeConfig) ([]*Target, []error) {
|
||||||
targets := make([]*Target, 0, len(tg.Targets))
|
targets := make([]*Target, 0, len(tg.Targets))
|
||||||
failures := []error{}
|
failures := []error{}
|
||||||
|
|
||||||
|
|
|
@ -371,7 +371,7 @@ func TestNewClientWithBadTLSConfig(t *testing.T) {
|
||||||
func TestTargetsFromGroup(t *testing.T) {
|
func TestTargetsFromGroup(t *testing.T) {
|
||||||
expectedError := "instance 0 in group : no address"
|
expectedError := "instance 0 in group : no address"
|
||||||
|
|
||||||
targets, failures := targetsFromGroup(&targetgroup.Group{Targets: []model.LabelSet{{}, {model.AddressLabel: "localhost:9090"}}}, &config.ScrapeConfig{})
|
targets, failures := TargetsFromGroup(&targetgroup.Group{Targets: []model.LabelSet{{}, {model.AddressLabel: "localhost:9090"}}}, &config.ScrapeConfig{})
|
||||||
if len(targets) != 1 {
|
if len(targets) != 1 {
|
||||||
t.Fatalf("Expected 1 target, got %v", len(targets))
|
t.Fatalf("Expected 1 target, got %v", len(targets))
|
||||||
}
|
}
|
||||||
|
|
Loading…
Reference in a new issue