4
4
package integration
5
5
6
6
import (
7
+ "bytes"
7
8
"context"
8
9
"crypto/x509"
9
10
"crypto/x509/pkix"
@@ -29,6 +30,7 @@ import (
29
30
"github.com/prometheus/prometheus/prompb"
30
31
"github.com/stretchr/testify/assert"
31
32
"github.com/stretchr/testify/require"
33
+ "github.com/thanos-io/objstore/providers/s3"
32
34
"gopkg.in/yaml.v3"
33
35
34
36
"github.com/cortexproject/cortex/integration/ca"
@@ -915,6 +917,127 @@ func TestRulerMetricsWhenIngesterFails(t *testing.T) {
915
917
})
916
918
}
917
919
920
+ func TestRulerDisablesRuleGroups (t * testing.T ) {
921
+ s , err := e2e .NewScenario (networkName )
922
+ require .NoError (t , err )
923
+ defer s .Close ()
924
+
925
+ // Start dependencies.
926
+ consul := e2edb .NewConsul ()
927
+ minio := e2edb .NewMinio (9000 , bucketName , rulestoreBucketName )
928
+ require .NoError (t , s .StartAndWaitReady (consul , minio ))
929
+
930
+ const blockRangePeriod = 2 * time .Second
931
+ // Configure the ruler.
932
+ flags := mergeFlags (
933
+ BlocksStorageFlags (),
934
+ RulerFlags (),
935
+ map [string ]string {
936
+ "-blocks-storage.tsdb.block-ranges-period" : blockRangePeriod .String (),
937
+ "-blocks-storage.tsdb.ship-interval" : "1s" ,
938
+ "-blocks-storage.bucket-store.sync-interval" : "1s" ,
939
+ "-blocks-storage.bucket-store.index-cache.backend" : tsdb .IndexCacheBackendInMemory ,
940
+ "-blocks-storage.tsdb.retention-period" : ((blockRangePeriod * 2 ) - 1 ).String (),
941
+
942
+ // Enable the bucket index so we can skip the initial bucket scan.
943
+ "-blocks-storage.bucket-store.bucket-index.enabled" : "false" ,
944
+ // Evaluate rules often, so that we don't need to wait for metrics to show up.
945
+ "-ruler.evaluation-interval" : "2s" ,
946
+ "-ruler.poll-interval" : "2s" ,
947
+ // No delay
948
+ "-ruler.evaluation-delay-duration" : "0" ,
949
+
950
+ // We run single ingester only, no replication.
951
+ "-distributor.replication-factor" : "1" ,
952
+
953
+ // Very low limit so that ruler hits it.
954
+ "-querier.max-fetched-chunks-per-query" : "15" ,
955
+ "-querier.query-store-after" : (1 * time .Second ).String (),
956
+ "-querier.query-ingesters-within" : (2 * time .Second ).String (),
957
+ },
958
+ )
959
+
960
+ const namespace = "test"
961
+ const user = "user"
962
+ configFileName := "runtime-config.yaml"
963
+ bucketName := "cortex"
964
+
965
+ storeGateway := e2ecortex .NewStoreGateway ("store-gateway-1" , e2ecortex .RingStoreConsul , consul .NetworkHTTPEndpoint (), flags , "" )
966
+
967
+ flags = mergeFlags (flags , map [string ]string {
968
+ "-querier.store-gateway-addresses" : storeGateway .NetworkGRPCEndpoint (),
969
+ "-runtime-config.backend" : "s3" ,
970
+ "-runtime-config.s3.access-key-id" : e2edb .MinioAccessKey ,
971
+ "-runtime-config.s3.secret-access-key" : e2edb .MinioSecretKey ,
972
+ "-runtime-config.s3.bucket-name" : bucketName ,
973
+ "-runtime-config.s3.endpoint" : fmt .Sprintf ("%s-minio-9000:9000" , networkName ),
974
+ "-runtime-config.s3.insecure" : "true" ,
975
+ "-runtime-config.file" : configFileName ,
976
+ "-runtime-config.reload-period" : "2s" ,
977
+ })
978
+
979
+ distributor := e2ecortex .NewDistributor ("distributor" , e2ecortex .RingStoreConsul , consul .NetworkHTTPEndpoint (), flags , "" )
980
+
981
+ client , err := s3 .NewBucketWithConfig (nil , s3.Config {
982
+ Endpoint : minio .HTTPEndpoint (),
983
+ Insecure : true ,
984
+ Bucket : bucketName ,
985
+ AccessKey : e2edb .MinioAccessKey ,
986
+ SecretKey : e2edb .MinioSecretKey ,
987
+ }, "runtime-config-test" )
988
+
989
+ require .NoError (t , err )
990
+
991
+ // update runtime config
992
+ newRuntimeConfig := []byte (`overrides:
993
+ user:
994
+ disabled_rule_groups:
995
+ - name: bad_rule
996
+ namespace: test` )
997
+ require .NoError (t , client .Upload (context .Background (), configFileName , bytes .NewReader (newRuntimeConfig )))
998
+ time .Sleep (2 * time .Second )
999
+
1000
+ ruler := e2ecortex .NewRuler ("ruler" , consul .NetworkHTTPEndpoint (), flags , "" )
1001
+
1002
+ ingester := e2ecortex .NewIngester ("ingester" , e2ecortex .RingStoreConsul , consul .NetworkHTTPEndpoint (), flags , "" )
1003
+ require .NoError (t , s .StartAndWaitReady (distributor , ingester , ruler , storeGateway ))
1004
+
1005
+ // Wait until both the distributor and ruler have updated the ring. The querier will also watch
1006
+ // the store-gateway ring if blocks sharding is enabled.
1007
+ require .NoError (t , distributor .WaitSumMetrics (e2e .Equals (512 ), "cortex_ring_tokens_total" ))
1008
+ require .NoError (t , ruler .WaitSumMetrics (e2e .Equals (1024 ), "cortex_ring_tokens_total" ))
1009
+
1010
+ c , err := e2ecortex .NewClient (distributor .HTTPEndpoint (), "" , "" , ruler .HTTPEndpoint (), user )
1011
+ require .NoError (t , err )
1012
+
1013
+ expression := "absent(sum_over_time(metric{}[2s] offset 1h))"
1014
+
1015
+ t .Run ("disable_rule_group" , func (t * testing.T ) {
1016
+
1017
+ ruleGroup := ruleGroupWithRule ("bad_rule" , "rule" , expression )
1018
+ ruleGroup .Interval = 2
1019
+ require .NoError (t , c .SetRuleGroup (ruleGroup , namespace ))
1020
+
1021
+ ruleGroup = ruleGroupWithRule ("good_rule" , "rule" , expression )
1022
+ ruleGroup .Interval = 2
1023
+ require .NoError (t , c .SetRuleGroup (ruleGroup , namespace ))
1024
+
1025
+ m1 := ruleGroupMatcher (user , namespace , "good_rule" )
1026
+
1027
+ // Wait until ruler has loaded the group.
1028
+ require .NoError (t , ruler .WaitSumMetricsWithOptions (e2e .GreaterOrEqual (1 ), []string {"cortex_ruler_sync_rules_total" }, e2e .WaitMissingMetrics ))
1029
+
1030
+ require .NoError (t , ruler .WaitSumMetricsWithOptions (e2e .Equals (1 ), []string {"cortex_prometheus_rule_group_rules" }, e2e .WithLabelMatchers (m1 ), e2e .WaitMissingMetrics ))
1031
+
1032
+ filter := e2ecortex.RuleFilter {}
1033
+ actualGroups , err := c .GetPrometheusRules (filter )
1034
+ require .NoError (t , err )
1035
+ assert .Equal (t , 1 , len (actualGroups ))
1036
+ assert .Equal (t , "good_rule" , actualGroups [0 ].Name )
1037
+ assert .Equal (t , "test" , actualGroups [0 ].File )
1038
+ })
1039
+ }
1040
+
918
1041
func ruleGroupMatcher (user , namespace , groupName string ) * labels.Matcher {
919
1042
return labels .MustNewMatcher (labels .MatchEqual , "rule_group" , fmt .Sprintf ("/rules/%s/%s;%s" , user , namespace , groupName ))
920
1043
}
0 commit comments