Skip to content

Commit 95450d7

Browse files
authored
Rebuild targets on scrape config regex-only changes (open-telemetry#2171)
1 parent 4e3e79c commit 95450d7

File tree

3 files changed

+71
-34
lines changed

3 files changed

+71
-34
lines changed

.chloggen/fix_ta-regex-hashing.yaml

+16
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,16 @@
1+
# One of 'breaking', 'deprecation', 'new_component', 'enhancement', 'bug_fix'
2+
change_type: bug_fix
3+
4+
# The name of the component, or a single word describing the area of concern, (e.g. operator, target allocator, github action)
5+
component: target allocator
6+
7+
# A brief description of the change. Surround your text with quotes ("") if it needs to start with a backtick (`).
8+
note: Rebuild targets on scrape config regex-only changes
9+
10+
# One or more tracking issues related to the change
11+
issues: [1358,1926]
12+
13+
# (Optional) One or more lines of additional information to render under the primary note.
14+
# These lines will be padded with 2 spaces and then inserted directly into the document.
15+
# Use pipe (|) for multiline entries.
16+
subtext:

cmd/otel-allocator/target/discovery.go

+26-3
Original file line numberDiff line numberDiff line change
@@ -15,14 +15,17 @@
1515
package target
1616

1717
import (
18+
"hash"
19+
"hash/fnv"
20+
1821
"github.com/go-logr/logr"
19-
"github.com/mitchellh/hashstructure"
2022
"github.com/prometheus/client_golang/prometheus"
2123
"github.com/prometheus/client_golang/prometheus/promauto"
2224
"github.com/prometheus/common/model"
2325
"github.com/prometheus/prometheus/config"
2426
"github.com/prometheus/prometheus/discovery"
2527
"github.com/prometheus/prometheus/model/relabel"
28+
"gopkg.in/yaml.v3"
2629

2730
allocatorWatcher "github.com/open-telemetry/opentelemetry-operator/cmd/otel-allocator/watcher"
2831
)
@@ -40,7 +43,7 @@ type Discoverer struct {
4043
close chan struct{}
4144
configsMap map[allocatorWatcher.EventSource]*config.Config
4245
hook discoveryHook
43-
scrapeConfigsHash uint64
46+
scrapeConfigsHash hash.Hash
4447
scrapeConfigsUpdater scrapeConfigsUpdater
4548
}
4649

@@ -82,7 +85,7 @@ func (m *Discoverer) ApplyConfig(source allocatorWatcher.EventSource, cfg *confi
8285
}
8386
}
8487

85-
hash, err := hashstructure.Hash(jobToScrapeConfig, nil)
88+
hash, err := getScrapeConfigHash(jobToScrapeConfig)
8689
if err != nil {
8790
return err
8891
}
@@ -131,3 +134,23 @@ func (m *Discoverer) Watch(fn func(targets map[string]*Item)) error {
131134
func (m *Discoverer) Close() {
132135
close(m.close)
133136
}
137+
138+
// Calculate a hash for a scrape config map.
139+
// This is done by marshaling to YAML because it's the most straightforward and doesn't run into problems with unexported fields.
140+
func getScrapeConfigHash(jobToScrapeConfig map[string]*config.ScrapeConfig) (hash.Hash64, error) {
141+
var err error
142+
hash := fnv.New64()
143+
yamlEncoder := yaml.NewEncoder(hash)
144+
for jobName, scrapeConfig := range jobToScrapeConfig {
145+
_, err = hash.Write([]byte(jobName))
146+
if err != nil {
147+
return nil, err
148+
}
149+
err = yamlEncoder.Encode(scrapeConfig)
150+
if err != nil {
151+
return nil, err
152+
}
153+
}
154+
yamlEncoder.Close()
155+
return hash, err
156+
}

cmd/otel-allocator/target/discovery_test.go

+29-31
Original file line numberDiff line numberDiff line change
@@ -17,6 +17,7 @@ package target
1717
import (
1818
"context"
1919
"errors"
20+
"hash"
2021
"sort"
2122
"testing"
2223
"time"
@@ -252,6 +253,33 @@ func TestDiscovery_ScrapeConfigHashing(t *testing.T) {
252253
},
253254
},
254255
},
256+
{
257+
description: "different regex",
258+
cfg: &promconfig.Config{
259+
ScrapeConfigs: []*promconfig.ScrapeConfig{
260+
{
261+
JobName: "serviceMonitor/testapp/testapp/1",
262+
HonorTimestamps: false,
263+
ScrapeTimeout: model.Duration(30 * time.Second),
264+
MetricsPath: "/metrics",
265+
Scheme: "http",
266+
HTTPClientConfig: commonconfig.HTTPClientConfig{
267+
FollowRedirects: true,
268+
},
269+
RelabelConfigs: []*relabel.Config{
270+
{
271+
SourceLabels: model.LabelNames{model.LabelName("job")},
272+
Separator: ";",
273+
Regex: relabel.MustNewRegexp("(.+)"),
274+
TargetLabel: "__tmp_prometheus_job_name",
275+
Replacement: "$$1",
276+
Action: relabel.Replace,
277+
},
278+
},
279+
},
280+
},
281+
},
282+
},
255283
{
256284
description: "mock error on update - no hash update",
257285
cfg: &promconfig.Config{
@@ -263,39 +291,9 @@ func TestDiscovery_ScrapeConfigHashing(t *testing.T) {
263291
},
264292
expectErr: true,
265293
},
266-
// {
267-
// TODO: fix handler logic so this test passes.
268-
// This test currently fails due to the regexp struct not having any
269-
// exported fields for the hashing algorithm to hash on, causing the
270-
// hashes to be the same even though the data is different.
271-
// description: "different regex",
272-
// cfg: &promconfig.Config{
273-
// ScrapeConfigs: []*promconfig.ScrapeConfig{
274-
// {
275-
// JobName: "serviceMonitor/testapp/testapp/1",
276-
// HonorTimestamps: false,
277-
// ScrapeTimeout: model.Duration(30 * time.Second),
278-
// MetricsPath: "/metrics",
279-
// HTTPClientConfig: commonconfig.HTTPClientConfig{
280-
// FollowRedirects: true,
281-
// },
282-
// RelabelConfigs: []*relabel.Config{
283-
// {
284-
// SourceLabels: model.LabelNames{model.LabelName("job")},
285-
// Separator: ";",
286-
// Regex: relabel.MustNewRegexp("something else"),
287-
// TargetLabel: "__tmp_prometheus_job_name",
288-
// Replacement: "$$1",
289-
// Action: relabel.Replace,
290-
// },
291-
// },
292-
// },
293-
// },
294-
// },
295-
// },
296294
}
297295
var (
298-
lastValidHash uint64
296+
lastValidHash hash.Hash
299297
expectedConfig map[string]*promconfig.ScrapeConfig
300298
lastValidConfig map[string]*promconfig.ScrapeConfig
301299
)

0 commit comments

Comments
 (0)