From e176cf2837a853b7b79b06160d373b67f066f566 Mon Sep 17 00:00:00 2001 From: Joel Verezhak Date: Fri, 11 Jul 2025 23:32:55 +0200 Subject: [PATCH] fix: querier external labels match relabel config Signed-off-by: Joel Verezhak --- cmd/thanos/query.go | 1 + pkg/api/query/v1.go | 20 +++++++++++++++++++- pkg/store/proxy.go | 33 ++++++++++++++++++++++++++++++--- 3 files changed, 50 insertions(+), 4 deletions(-) diff --git a/cmd/thanos/query.go b/cmd/thanos/query.go index 20379f0611e..f7fd5e500ae 100644 --- a/cmd/thanos/query.go +++ b/cmd/thanos/query.go @@ -553,6 +553,7 @@ func runQuery( tenantCertField, enforceTenancy, tenantLabel, + tsdbSelector, ) api.Register(router.WithPrefix("/api/v1"), tracer, logger, ins, logMiddleware) diff --git a/pkg/api/query/v1.go b/pkg/api/query/v1.go index 18fcf49f80e..b9f4de691c7 100644 --- a/pkg/api/query/v1.go +++ b/pkg/api/query/v1.go @@ -111,6 +111,7 @@ type QueryAPI struct { replicaLabels []string endpointStatus func() []query.EndpointStatus + tsdbSelector *store.TSDBSelector defaultRangeQueryStep time.Duration defaultInstantQueryMaxSourceResolution time.Duration @@ -160,6 +161,7 @@ func NewQueryAPI( tenantCertField string, enforceTenancy bool, tenantLabel string, + tsdbSelector *store.TSDBSelector, ) *QueryAPI { if statsAggregatorFactory == nil { statsAggregatorFactory = &store.NoopSeriesStatsAggregatorFactory{} @@ -195,6 +197,7 @@ func NewQueryAPI( tenantCertField: tenantCertField, enforceTenancy: enforceTenancy, tenantLabel: tenantLabel, + tsdbSelector: tsdbSelector, queryRangeHist: promauto.With(reg).NewHistogram(prometheus.HistogramOpts{ Name: "thanos_query_range_requested_timespan_duration_seconds", @@ -1296,7 +1299,22 @@ func (qapi *QueryAPI) stores(_ *http.Request) (interface{}, []error, *api.ApiErr if status.ComponentType == nil { continue } - statuses[status.ComponentType.String()] = append(statuses[status.ComponentType.String()], status) + + // Apply TSDBSelector filtering to LabelSets if selector is configured + filteredStatus := status + if qapi.tsdbSelector != nil && len(status.LabelSets) > 0 { + matches, filteredLabelSets := qapi.tsdbSelector.MatchLabelSets(status.LabelSets...) + if !matches { + // Skip this endpoint if it doesn't match the TSDBSelector + continue + } + if filteredLabelSets != nil { + // Use the filtered label sets if available + filteredStatus.LabelSets = filteredLabelSets + } + } + + statuses[status.ComponentType.String()] = append(statuses[status.ComponentType.String()], filteredStatus) } return statuses, nil, nil, func() {} } diff --git a/pkg/store/proxy.go b/pkg/store/proxy.go index 2c63b6c099a..e4a9ffb8ad2 100644 --- a/pkg/store/proxy.go +++ b/pkg/store/proxy.go @@ -202,7 +202,22 @@ func (s *ProxyStore) LabelSet() []labelpb.ZLabelSet { mergedLabelSets := make(map[uint64]labelpb.ZLabelSet, len(stores)) for _, st := range stores { - for _, lset := range st.LabelSets() { + // Apply TSDBSelector filtering to each individual label set + matches, filteredLabelSets := s.tsdbSelector.MatchLabelSets(st.LabelSets()...) + + if !matches { + continue + } + + // Use the filtered label sets if available, otherwise use original + var labelSetsToProcess []labels.Labels + if filteredLabelSets != nil { + labelSetsToProcess = filteredLabelSets + } else { + labelSetsToProcess = st.LabelSets() + } + + for _, lset := range labelSetsToProcess { mergedLabelSet := labelpb.ExtendSortedLabels(lset, s.selectorLabels) mergedLabelSets[mergedLabelSet.Hash()] = labelpb.ZLabelSet{Labels: labelpb.ZLabelsFromPromLabels(mergedLabelSet)} } @@ -232,8 +247,15 @@ func (s *ProxyStore) TimeRange() (int64, int64) { } var minTime, maxTime int64 = math.MaxInt64, math.MinInt64 - for _, s := range stores { - storeMinTime, storeMaxTime := s.TimeRange() + hasMatchingStores := false + for _, st := range stores { + // Apply TSDBSelector filtering to match what's used in TSDBInfos() and actual queries + matches, _ := s.tsdbSelector.MatchLabelSets(st.LabelSets()...) + if !matches { + continue + } + hasMatchingStores = true + storeMinTime, storeMaxTime := st.TimeRange() if storeMinTime < minTime { minTime = storeMinTime } @@ -242,6 +264,11 @@ func (s *ProxyStore) TimeRange() (int64, int64) { } } + // If no stores match the selector, return the full range as fallback + if !hasMatchingStores { + return math.MinInt64, math.MaxInt64 + } + return minTime, maxTime }