Skip to content

Commit 4d0a9e3

Browse files
committed
fix: validate scrape_config job name
1 parent ec34aaa commit 4d0a9e3

File tree

3 files changed

+95
-1
lines changed

3 files changed

+95
-1
lines changed

clients/pkg/promtail/promtail.go

+8-1
Original file line numberDiff line numberDiff line change
@@ -18,6 +18,7 @@ import (
1818
"github.com/grafana/loki/v3/clients/pkg/promtail/api"
1919
"github.com/grafana/loki/v3/clients/pkg/promtail/client"
2020
"github.com/grafana/loki/v3/clients/pkg/promtail/config"
21+
"github.com/grafana/loki/v3/clients/pkg/promtail/scrapeconfig"
2122
"github.com/grafana/loki/v3/clients/pkg/promtail/server"
2223
"github.com/grafana/loki/v3/clients/pkg/promtail/targets"
2324
"github.com/grafana/loki/v3/clients/pkg/promtail/targets/target"
@@ -139,10 +140,16 @@ func (p *Promtail) reloadConfig(cfg *config.Config) error {
139140
}
140141

141142
cfg.Setup(p.logger)
143+
var err error
144+
err = scrapeconfig.ValidateJobName(cfg.ScrapeConfig)
145+
if err != nil {
146+
return err
147+
}
148+
142149
if cfg.LimitsConfig.ReadlineRateEnabled {
143150
stages.SetReadLineRateLimiter(cfg.LimitsConfig.ReadlineRate, cfg.LimitsConfig.ReadlineBurst, cfg.LimitsConfig.ReadlineRateDrop)
144151
}
145-
var err error
152+
146153
// entryHandlers contains all sinks were scraped log entries should get to
147154
var entryHandlers = []api.EntryHandler{}
148155

clients/pkg/promtail/scrapeconfig/scrapeconfig.go

+21
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,7 @@
11
package scrapeconfig
22

33
import (
4+
"errors"
45
"fmt"
56
"reflect"
67
"time"
@@ -26,6 +27,7 @@ import (
2627
"github.com/prometheus/prometheus/discovery/triton"
2728
"github.com/prometheus/prometheus/discovery/zookeeper"
2829
"github.com/prometheus/prometheus/model/relabel"
30+
"github.com/prometheus/prometheus/util/strutil"
2931

3032
"github.com/grafana/loki/v3/clients/pkg/logentry/stages"
3133
"github.com/grafana/loki/v3/clients/pkg/promtail/discovery/consulagent"
@@ -484,3 +486,22 @@ func (c *Config) UnmarshalYAML(unmarshal func(interface{}) error) error {
484486

485487
return nil
486488
}
489+
490+
func ValidateJobName(scrapeConfigs []Config) error {
491+
jobNames := map[string]struct{}{}
492+
for i, cfg := range scrapeConfigs {
493+
if cfg.JobName == "" {
494+
return errors.New("`job_name` must be defined for the scrape_config with a " +
495+
"unique name, " +
496+
"at least one scrape_config has no `job_name` defined")
497+
}
498+
if _, ok := jobNames[cfg.JobName]; ok {
499+
return fmt.Errorf("`job_name` must be unique for each scrape_config, "+
500+
"a duplicate `job_name` of %s was found", cfg.JobName)
501+
}
502+
jobNames[cfg.JobName] = struct{}{}
503+
504+
scrapeConfigs[i].JobName = strutil.SanitizeLabelName(cfg.JobName)
505+
}
506+
return nil
507+
}

clients/pkg/promtail/scrapeconfig/scrapeconfig_test.go

+66
Original file line numberDiff line numberDiff line change
@@ -142,3 +142,69 @@ func TestLoadConfig(t *testing.T) {
142142

143143
require.NotZero(t, len(config.PipelineStages))
144144
}
145+
146+
func Test_validateJobName(t *testing.T) {
147+
tests := []struct {
148+
name string
149+
configs []Config
150+
// Only validated against the first job in the provided scrape configs
151+
expectedJob string
152+
wantErr bool
153+
}{
154+
{
155+
name: "valid with spaces removed",
156+
configs: []Config{
157+
{
158+
JobName: "jobby job job",
159+
},
160+
},
161+
wantErr: false,
162+
expectedJob: "jobby_job_job",
163+
},
164+
{
165+
name: "missing job",
166+
configs: []Config{
167+
{
168+
},
169+
},
170+
wantErr: true,
171+
},
172+
{
173+
name: "duplicate job",
174+
configs: []Config{
175+
{
176+
JobName: "job1",
177+
},
178+
{
179+
JobName: "job1",
180+
},
181+
},
182+
wantErr: true,
183+
},
184+
{
185+
name: "validate with special characters",
186+
configs: []Config{
187+
{
188+
JobName: "job$1-2!3@4*job",
189+
},
190+
},
191+
wantErr: false,
192+
expectedJob: "job_1_2_3_4_job",
193+
},
194+
}
195+
for _, tt := range tests {
196+
t.Run(tt.name, func(t *testing.T) {
197+
err := ValidateJobName(tt.configs)
198+
if (err != nil) != tt.wantErr {
199+
t.Errorf("validateJobName() error = %v, wantErr %v", err, tt.wantErr)
200+
return
201+
}
202+
if !tt.wantErr {
203+
if tt.configs[0].JobName != tt.expectedJob {
204+
t.Errorf("Expected to find a job with name %v but did not find it", tt.expectedJob)
205+
return
206+
}
207+
}
208+
})
209+
}
210+
}

0 commit comments

Comments
 (0)