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:
DrAuYueng 2021-10-28 08:01:28 +08:00 committed by GitHub
parent 8207b132fd
commit 69e309d202
No known key found for this signature in database
GPG key ID: 4AEE18F83AFDEB23
11 changed files with 160 additions and 19 deletions

View file

@ -44,13 +44,16 @@ import (
yaml "gopkg.in/yaml.v2"
"github.com/prometheus/prometheus/config"
"github.com/prometheus/prometheus/discovery"
"github.com/prometheus/prometheus/discovery/file"
_ "github.com/prometheus/prometheus/discovery/install" // Register service discovery implementations.
"github.com/prometheus/prometheus/discovery/kubernetes"
"github.com/prometheus/prometheus/discovery/targetgroup"
"github.com/prometheus/prometheus/notifier"
"github.com/prometheus/prometheus/pkg/labels"
"github.com/prometheus/prometheus/pkg/rulefmt"
"github.com/prometheus/prometheus/promql"
"github.com/prometheus/prometheus/scrape"
)
func main() {
@ -363,19 +366,60 @@ func checkConfig(filename string) ([]string, error) {
}
if len(files) != 0 {
for _, f := range files {
err = checkSDFile(f)
var targetGroups []*targetgroup.Group
targetGroups, err = checkSDFile(f)
if err != nil {
return nil, errors.Errorf("checking SD file %q: %v", file, err)
}
if err := checkTargetGroupsForScrapeConfig(targetGroups, scfg); err != nil {
return nil, err
}
}
continue
}
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
}
@ -397,16 +441,16 @@ func checkTLSConfig(tlsConfig config_util.TLSConfig) error {
return nil
}
func checkSDFile(filename string) error {
func checkSDFile(filename string) ([]*targetgroup.Group, error) {
fd, err := os.Open(filename)
if err != nil {
return err
return nil, err
}
defer fd.Close()
content, err := ioutil.ReadAll(fd)
if err != nil {
return err
return nil, err
}
var targetGroups []*targetgroup.Group
@ -414,23 +458,23 @@ func checkSDFile(filename string) error {
switch ext := filepath.Ext(filename); strings.ToLower(ext) {
case ".json":
if err := json.Unmarshal(content, &targetGroups); err != nil {
return err
return nil, err
}
case ".yml", ".yaml":
if err := yaml.UnmarshalStrict(content, &targetGroups); err != nil {
return err
return nil, err
}
default:
return errors.Errorf("invalid file extension: %q", ext)
return nil, errors.Errorf("invalid file extension: %q", ext)
}
for i, tg := range targetGroups {
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.
@ -981,3 +1025,25 @@ func importRules(url *url.URL, start, end, outputDir string, evalInterval time.D
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
}

View file

@ -111,7 +111,7 @@ func TestCheckSDFile(t *testing.T) {
}
for _, test := range cases {
t.Run(test.name, func(t *testing.T) {
err := checkSDFile(test.file)
_, err := checkSDFile(test.file)
if test.err != "" {
require.Equalf(t, test.err, err.Error(), "Expected error %q, got %q", test.err, err.Error())
return
@ -163,3 +163,42 @@ func BenchmarkCheckDuplicates(b *testing.B) {
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)
})
}
}

View file

@ -0,0 +1,8 @@
alerting:
alertmanagers:
- relabel_configs:
- source_labels: [__address__]
target_label: __param_target
static_configs:
- targets:
- http://bad

View 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

View file

@ -0,0 +1,8 @@
scrape_configs:
- job_name: prometheus
relabel_configs:
- source_labels: [__address__]
target_label: __param_target
static_configs:
- targets:
- http://bad

View 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

View file

@ -602,7 +602,7 @@ func (n *Manager) Stop() {
n.cancel()
}
// alertmanager holds Alertmanager endpoint information.
// Alertmanager holds Alertmanager endpoint information.
type alertmanager interface {
url() *url.URL
}
@ -654,7 +654,7 @@ func (s *alertmanagerSet) sync(tgs []*targetgroup.Group) {
allDroppedAms := []alertmanager{}
for _, tg := range tgs {
ams, droppedAms, err := alertmanagerFromGroup(tg, s.cfg)
ams, droppedAms, err := AlertmanagerFromGroup(tg, s.cfg)
if err != nil {
level.Error(s.logger).Log("msg", "Creating discovered Alertmanagers failed", "err", err)
continue
@ -691,9 +691,9 @@ func postPath(pre string, v config.AlertmanagerAPIVersion) string {
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.
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 droppedAlertManagers []alertmanager

View file

@ -447,7 +447,7 @@ func (a alertmanagerMock) url() *url.URL {
func TestLabelSetNotReused(t *testing.T) {
tg := makeInputTargetGroup()
_, _, err := alertmanagerFromGroup(tg, &config.AlertmanagerConfig{})
_, _, err := AlertmanagerFromGroup(tg, &config.AlertmanagerConfig{})
require.NoError(t, err)

View file

@ -472,7 +472,7 @@ func (sp *scrapePool) Sync(tgs []*targetgroup.Group) {
var all []*Target
sp.droppedTargets = []*Target{}
for _, tg := range tgs {
targets, failures := targetsFromGroup(tg, sp.config)
targets, failures := TargetsFromGroup(tg, sp.config)
for _, err := range failures {
level.Error(sp.logger).Log("msg", "Creating target failed", "err", err)
}

View file

@ -469,8 +469,8 @@ func populateLabels(lset labels.Labels, cfg *config.ScrapeConfig) (res, orig lab
return res, preRelabelLabels, nil
}
// targetsFromGroup builds targets based on the given TargetGroup and config.
func targetsFromGroup(tg *targetgroup.Group, cfg *config.ScrapeConfig) ([]*Target, []error) {
// TargetsFromGroup builds targets based on the given TargetGroup and config.
func TargetsFromGroup(tg *targetgroup.Group, cfg *config.ScrapeConfig) ([]*Target, []error) {
targets := make([]*Target, 0, len(tg.Targets))
failures := []error{}

View file

@ -371,7 +371,7 @@ func TestNewClientWithBadTLSConfig(t *testing.T) {
func TestTargetsFromGroup(t *testing.T) {
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 {
t.Fatalf("Expected 1 target, got %v", len(targets))
}