Skip to content

Commit 9f67a58

Browse files
committed
change to check config load validation only for some targets
Signed-off-by: SungJin1212 <[email protected]>
1 parent 960b372 commit 9f67a58

File tree

4 files changed

+194
-3
lines changed

4 files changed

+194
-3
lines changed

CHANGELOG.md

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -74,6 +74,7 @@
7474
* [BUGFIX] Ingester: Allow shipper to skip corrupted blocks. #6786
7575
* [BUGFIX] Compactor: Delete the prefix `blocks_meta` from the metadata fetcher metrics. #6832
7676
* [BUGFIX] Store Gateway: Avoid race condition by deduplicating entries in bucket stores user scan. #6863
77+
* [BUGFIX] Runtime-config: Change to check tenant limit validation when loading runtime config only for `all`, `distributor` and `querier` targets. #6880
7778

7879
## 1.19.0 2025-02-27
7980

integration/runtime_config_test.go

Lines changed: 87 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -10,6 +10,7 @@ import (
1010
"io"
1111
"os"
1212
"path/filepath"
13+
"strings"
1314
"testing"
1415
"time"
1516

@@ -164,6 +165,92 @@ func TestLoadRuntimeConfigFromCloudStorage(t *testing.T) {
164165
require.NoError(t, s.Stop(cortexSvc))
165166
}
166167

168+
func Test_RuntimeConfigLoadValidation(t *testing.T) {
169+
s, err := e2e.NewScenario(networkName)
170+
require.NoError(t, err)
171+
defer s.Close()
172+
173+
runtimeConfigYamlFile := `
174+
overrides:
175+
'user-1':
176+
max_global_series_per_user: 15000
177+
`
178+
179+
require.NoError(t, writeFileToSharedDir(s, runtimeConfigFile, []byte(runtimeConfigYamlFile)))
180+
filePath := filepath.Join(e2e.ContainerSharedDir, runtimeConfigFile)
181+
182+
flags := mergeFlags(BlocksStorageFlags(), map[string]string{
183+
"-runtime-config.file": filePath,
184+
"-runtime-config.backend": "filesystem",
185+
186+
// alert manager
187+
"-alertmanager.web.external-url": "http://localhost/alertmanager",
188+
"-alertmanager-storage.backend": "local",
189+
"-alertmanager-storage.local.path": filepath.Join(e2e.ContainerSharedDir, "alertmanager_configs"),
190+
191+
// store-gateway
192+
"-querier.store-gateway-addresses": "localhost:12345",
193+
194+
// distributor.shard-by-all-labels is false
195+
"-distributor.shard-by-all-labels": "false",
196+
})
197+
198+
// Start dependencies.
199+
consul := e2edb.NewConsul()
200+
minio := e2edb.NewMinio(9000, flags["-blocks-storage.s3.bucket-name"])
201+
require.NoError(t, s.StartAndWaitReady(consul, minio))
202+
203+
// make alert manager config dir
204+
require.NoError(t, writeFileToSharedDir(s, "alertmanager_configs", []byte{}))
205+
206+
// Ingester and Store gateway start
207+
ingester := e2ecortex.NewIngester("ingester", e2ecortex.RingStoreConsul, consul.NetworkHTTPEndpoint(), flags, "")
208+
storeGateway := e2ecortex.NewStoreGateway("store-gateway", e2ecortex.RingStoreConsul, consul.NetworkHTTPEndpoint(), flags, "")
209+
require.NoError(t, s.StartAndWaitReady(ingester, storeGateway))
210+
211+
// Querier start, but fail with "-distributor.shard-by-all-labels": "false"
212+
querier := e2ecortex.NewQuerier("querier", e2ecortex.RingStoreConsul, consul.NetworkHTTPEndpoint(), mergeFlags(flags, map[string]string{
213+
"-querier.store-gateway-addresses": strings.Join([]string{storeGateway.NetworkGRPCEndpoint()}, ","),
214+
}), "")
215+
require.Error(t, s.StartAndWaitReady(querier))
216+
217+
// Start Query frontend
218+
queryFrontend := e2ecortex.NewQueryFrontendWithConfigFile("query-frontend", "", flags, "")
219+
require.NoError(t, s.Start(queryFrontend))
220+
221+
// Querier start, should success with "-distributor.shard-by-all-labels": "true"
222+
querier = e2ecortex.NewQuerier("querier", e2ecortex.RingStoreConsul, consul.NetworkHTTPEndpoint(), mergeFlags(flags, map[string]string{
223+
"-querier.store-gateway-addresses": strings.Join([]string{storeGateway.NetworkGRPCEndpoint()}, ","),
224+
"-distributor.shard-by-all-labels": "true",
225+
"-querier.frontend-address": queryFrontend.NetworkGRPCEndpoint(),
226+
}), "")
227+
require.NoError(t, s.StartAndWaitReady(querier))
228+
229+
// Start Ruler.
230+
ruler := e2ecortex.NewRuler("ruler", consul.NetworkHTTPEndpoint(), mergeFlags(flags, RulerFlags()), "")
231+
require.NoError(t, s.StartAndWaitReady(ruler))
232+
233+
// Start the query-scheduler
234+
queryScheduler := e2ecortex.NewQueryScheduler("query-scheduler", flags, "")
235+
require.NoError(t, s.StartAndWaitReady(queryScheduler))
236+
flags["-frontend.scheduler-address"] = queryScheduler.NetworkGRPCEndpoint()
237+
flags["-querier.scheduler-address"] = queryScheduler.NetworkGRPCEndpoint()
238+
239+
// Start Alertmanager
240+
alertmanager := e2ecortex.NewAlertmanager("alertmanager", mergeFlags(flags, AlertmanagerFlags()), "")
241+
require.NoError(t, s.StartAndWaitReady(alertmanager))
242+
243+
// Distributor start, but fail with "-distributor.shard-by-all-labels": "false"
244+
distributor := e2ecortex.NewQuerier("distributor", e2ecortex.RingStoreConsul, consul.NetworkHTTPEndpoint(), mergeFlags(flags, map[string]string{}), "")
245+
require.Error(t, s.StartAndWaitReady(distributor))
246+
247+
// Distributor start, should success with "-distributor.shard-by-all-labels": "true"
248+
distributor = e2ecortex.NewQuerier("distributor", e2ecortex.RingStoreConsul, consul.NetworkHTTPEndpoint(), mergeFlags(flags, map[string]string{
249+
"-distributor.shard-by-all-labels": "true",
250+
}), "")
251+
require.NoError(t, s.StartAndWaitReady(distributor))
252+
}
253+
167254
func assertRuntimeConfigLoadedCorrectly(t *testing.T, cortexSvc *e2ecortex.CortexService) {
168255
runtimeConfig := getRuntimeConfig(t, cortexSvc)
169256

pkg/cortex/runtime_config.go

Lines changed: 9 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -4,6 +4,7 @@ import (
44
"errors"
55
"io"
66
"net/http"
7+
"strings"
78

89
"gopkg.in/yaml.v2"
910

@@ -78,9 +79,14 @@ func (l runtimeConfigLoader) load(r io.Reader) (interface{}, error) {
7879
return nil, errMultipleDocuments
7980
}
8081

81-
for _, ul := range overrides.TenantLimits {
82-
if err := ul.Validate(l.cfg.Distributor.ShardByAllLabels, l.cfg.Ingester.ActiveSeriesMetricsEnabled); err != nil {
83-
return nil, err
82+
targetStr := l.cfg.Target.String()
83+
if strings.Contains(targetStr, All) || strings.Contains(targetStr, Distributor) || strings.Contains(targetStr, Querier) {
84+
// only check if target is `all`, `distributor` and "querier"
85+
// refer to https://github.com/cortexproject/cortex/issues/6741#issuecomment-3067244929
86+
for _, ul := range overrides.TenantLimits {
87+
if err := ul.Validate(l.cfg.Distributor.ShardByAllLabels, l.cfg.Ingester.ActiveSeriesMetricsEnabled); err != nil {
88+
return nil, err
89+
}
8490
}
8591
}
8692

pkg/cortex/runtime_config_test.go

Lines changed: 97 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -8,6 +8,7 @@ import (
88
"github.com/stretchr/testify/require"
99

1010
"github.com/cortexproject/cortex/pkg/distributor"
11+
"github.com/cortexproject/cortex/pkg/ingester"
1112
"github.com/cortexproject/cortex/pkg/util/validation"
1213
)
1314

@@ -109,3 +110,99 @@ overrides:
109110
assert.Nil(t, actual)
110111
}
111112
}
113+
114+
func TestLoad_ShouldNotErrorWithCertainTarget(t *testing.T) {
115+
116+
tests := []struct {
117+
desc string
118+
target []string
119+
shardByAllLabels bool
120+
isErr bool
121+
}{
122+
{
123+
desc: "all",
124+
target: []string{All},
125+
shardByAllLabels: true,
126+
},
127+
{
128+
desc: "all, shardByAllLabels:false",
129+
target: []string{All},
130+
shardByAllLabels: false,
131+
isErr: true,
132+
},
133+
{
134+
desc: "distributor",
135+
target: []string{Distributor},
136+
shardByAllLabels: true,
137+
},
138+
{
139+
desc: "distributor, shardByAllLabels:false",
140+
target: []string{Distributor},
141+
shardByAllLabels: false,
142+
isErr: true,
143+
},
144+
{
145+
desc: "querier",
146+
target: []string{Querier},
147+
shardByAllLabels: true,
148+
},
149+
{
150+
desc: "querier, shardByAllLabels:false",
151+
target: []string{Querier},
152+
shardByAllLabels: false,
153+
isErr: true,
154+
},
155+
{
156+
desc: "ingester",
157+
target: []string{Ingester},
158+
},
159+
{
160+
desc: "query frontend",
161+
target: []string{QueryFrontend},
162+
},
163+
{
164+
desc: "alertmanager",
165+
target: []string{AlertManager},
166+
},
167+
{
168+
desc: "ruler",
169+
target: []string{Ruler},
170+
},
171+
{
172+
desc: "store gateway",
173+
target: []string{StoreGateway},
174+
},
175+
{
176+
desc: "compactor",
177+
target: []string{Compactor},
178+
},
179+
{
180+
desc: "overrides exporter",
181+
target: []string{OverridesExporter},
182+
},
183+
}
184+
185+
for _, tc := range tests {
186+
t.Run(tc.desc, func(t *testing.T) {
187+
yamlFile := strings.NewReader(`
188+
overrides:
189+
'user-1':
190+
max_global_series_per_user: 15000
191+
`)
192+
193+
loader := runtimeConfigLoader{}
194+
loader.cfg = Config{
195+
Target: tc.target,
196+
Distributor: distributor.Config{ShardByAllLabels: tc.shardByAllLabels},
197+
Ingester: ingester.Config{ActiveSeriesMetricsEnabled: true},
198+
}
199+
200+
_, err := loader.load(yamlFile)
201+
if tc.isErr {
202+
require.Error(t, err)
203+
} else {
204+
require.NoError(t, err)
205+
}
206+
})
207+
}
208+
}

0 commit comments

Comments
 (0)