From b617e98c5b20360c2827e1b45e2726d9e065a0a4 Mon Sep 17 00:00:00 2001 From: wangrushen Date: Sun, 27 Oct 2024 22:04:26 +0800 Subject: [PATCH 1/4] Provide support for scaling based on Redis Key-Values Signed-off-by: wangrushen --- CHANGELOG.md | 1 + pkg/scalers/redis_scaler.go | 163 ++++++++------ pkg/scalers/redis_scaler_test.go | 95 +++++++- tests/scalers/redis/helper/helper.go | 31 +++ .../redis_cluster_strings_test.go | 207 +++++++++++++++++ .../redis_sentinel_strings_test.go | 211 ++++++++++++++++++ .../redis_standlone_strings_test.go | 205 +++++++++++++++++ 7 files changed, 845 insertions(+), 68 deletions(-) create mode 100644 tests/scalers/redis/redis_cluster_strings/redis_cluster_strings_test.go create mode 100644 tests/scalers/redis/redis_sentinel_strings/redis_sentinel_strings_test.go create mode 100644 tests/scalers/redis/redis_standalone_strings/redis_standlone_strings_test.go diff --git a/CHANGELOG.md b/CHANGELOG.md index 32f6c393aae..37f715bc064 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -72,6 +72,7 @@ Here is an overview of all new **experimental** features: ### Improvements +- **Redis Scaler**: Provide support for scaling based on Redis Key-Values ([#5003](https://github.com/kedacore/keda/issues/5003)) - **General**: Prevent multiple ScaledObjects managing one HPA ([#6130](https://github.com/kedacore/keda/issues/6130)) - **AWS CloudWatch Scaler**: Add support for ignoreNullValues ([#5352](https://github.com/kedacore/keda/issues/5352)) - **Elasticsearch Scaler**: Support Query at the Elasticsearch scaler ([#6216](https://github.com/kedacore/keda/issues/6216)) diff --git a/pkg/scalers/redis_scaler.go b/pkg/scalers/redis_scaler.go index 3746735dce6..d1810924729 100644 --- a/pkg/scalers/redis_scaler.go +++ b/pkg/scalers/redis_scaler.go @@ -23,9 +23,25 @@ const ( defaultEnableTLS = false ) +const getListLengthLuaScript = ` +local listName = KEYS[1] +local listType = redis.call('type', listName).ok +local cmd = { + zset = 'zcard', + set = 'scard', + list = 'llen', + hash = 'hlen', + none = 'llen' +} + +return redis.call(cmd[listType], listName)` + var ( - // ErrRedisNoListName is returned when "listName" is missing from the config. - ErrRedisNoListName = errors.New("no list name given") + // ErrRedisNeitherKeyOrList is none of "listName" and "keyName" are set. + ErrRedisNeitherKeyOrList = errors.New("neither listName nor keyName are set") + + // ErrRedisBothKeyAndList is both "listName" and "keyName" are set. + ErrRedisBothKeyAndList = errors.New("both listName and keyName are set") // ErrRedisNoAddresses is returned when the "addresses" in the connection info is empty. ErrRedisNoAddresses = errors.New("no addresses or hosts given. address should be a comma separated list of host:port or set the host/port values") @@ -41,7 +57,8 @@ type redisScaler struct { metricType v2.MetricTargetType metadata *redisMetadata closeFn func() error - getListLengthFn func(context.Context) (int64, error) + getValueFn func(context.Context) (float64, error) + activationValue float64 logger logr.Logger } @@ -63,14 +80,19 @@ type redisConnectionInfo struct { } type redisMetadata struct { - ListLength int64 `keda:"name=listLength, order=triggerMetadata, optional, default=5"` - ActivationListLength int64 `keda:"name=activationListLength, order=triggerMetadata, optional"` - ListName string `keda:"name=listName, order=triggerMetadata"` - DatabaseIndex int `keda:"name=databaseIndex, order=triggerMetadata, optional"` - MetadataEnableTLS string `keda:"name=enableTLS, order=triggerMetadata, optional"` - AuthParamEnableTLS string `keda:"name=tls, order=authParams, optional"` - ConnectionInfo redisConnectionInfo `keda:"optional"` - triggerIndex int + ListLength int64 `keda:"name=listLength, order=triggerMetadata, optional, default=5"` + ActivationListLength int64 `keda:"name=activationListLength, order=triggerMetadata, optional"` + ListName string `keda:"name=listName, order=triggerMetadata, optional"` + + KeyValue float64 `keda:"name=keyValue, order=triggerMetadata, optional, default=5"` + ActivationKeyValue float64 `keda:"name=activationKeyValue, order=triggerMetadata, optional"` + KeyName string `keda:"name=keyName, order=triggerMetadata, optional"` + + DatabaseIndex int `keda:"name=databaseIndex, order=triggerMetadata, optional"` + MetadataEnableTLS string `keda:"name=enableTLS, order=triggerMetadata, optional"` + AuthParamEnableTLS string `keda:"name=tls, order=authParams, optional"` + ConnectionInfo redisConnectionInfo `keda:"optional"` + triggerIndex int } func (rci *redisConnectionInfo) SetEnableTLS(metadataEnableTLS string, authParamEnableTLS string) error { @@ -105,7 +127,6 @@ func (rci *redisConnectionInfo) SetEnableTLS(metadataEnableTLS string, authParam func (r *redisMetadata) Validate() error { err := validateRedisAddress(&r.ConnectionInfo) - if err != nil { return err } @@ -115,25 +136,19 @@ func (r *redisMetadata) Validate() error { r.MetadataEnableTLS, r.AuthParamEnableTLS = "", "" } + if r.ListName == "" && r.KeyName == "" { + return ErrRedisNeitherKeyOrList + } + + if r.ListName != "" && r.KeyName != "" { + return ErrRedisBothKeyAndList + } + return err } // NewRedisScaler creates a new redisScaler func NewRedisScaler(ctx context.Context, isClustered, isSentinel bool, config *scalersconfig.ScalerConfig) (Scaler, error) { - luaScript := ` - local listName = KEYS[1] - local listType = redis.call('type', listName).ok - local cmd = { - zset = 'zcard', - set = 'scard', - list = 'llen', - hash = 'hlen', - none = 'llen' - } - - return redis.call(cmd[listType], listName) - ` - metricType, err := GetMetricTargetType(config) if err != nil { return nil, fmt.Errorf("error getting scaler metric type: %w", err) @@ -147,14 +162,52 @@ func NewRedisScaler(ctx context.Context, isClustered, isSentinel bool, config *s } if isClustered { - return createClusteredRedisScaler(ctx, meta, luaScript, metricType, logger) + return createClusteredRedisScaler(ctx, meta, metricType, logger) } else if isSentinel { - return createSentinelRedisScaler(ctx, meta, luaScript, metricType, logger) + return createSentinelRedisScaler(ctx, meta, metricType, logger) + } + return createRedisScaler(ctx, meta, metricType, logger) +} + +func getValueFn(meta *redisMetadata, client redis.Cmdable) func(ctx context.Context) (float64, error) { + switch { + case meta.KeyName != "": + return func(ctx context.Context) (float64, error) { + cmd := client.Get(ctx, meta.KeyName) + if cmd.Err() != nil { + return -1, cmd.Err() + } + + return cmd.Float64() + } + case meta.ListName != "": + return func(ctx context.Context) (float64, error) { + cmd := client.Eval(ctx, getListLengthLuaScript, []string{meta.ListName}) + if cmd.Err() != nil { + return -1, cmd.Err() + } + + return cmd.Float64() + } + // should never happen, because we check keyName and listName in meta.Valaidate() + default: + return nil + } +} + +func getActivationValue(meta *redisMetadata) float64 { + switch { + case meta.KeyName != "": + return meta.ActivationKeyValue + case meta.ListName != "": + return float64(meta.ActivationListLength) + // should never happen, because we check keyName and listName in meta.Valaidate() + default: + return 0 } - return createRedisScaler(ctx, meta, luaScript, metricType, logger) } -func createClusteredRedisScaler(ctx context.Context, meta *redisMetadata, script string, metricType v2.MetricTargetType, logger logr.Logger) (Scaler, error) { +func createClusteredRedisScaler(ctx context.Context, meta *redisMetadata, metricType v2.MetricTargetType, logger logr.Logger) (Scaler, error) { client, err := getRedisClusterClient(ctx, meta.ConnectionInfo) if err != nil { return nil, fmt.Errorf("connection to redis cluster failed: %w", err) @@ -168,43 +221,37 @@ func createClusteredRedisScaler(ctx context.Context, meta *redisMetadata, script return nil } - listLengthFn := func(ctx context.Context) (int64, error) { - cmd := client.Eval(ctx, script, []string{meta.ListName}) - if cmd.Err() != nil { - return -1, cmd.Err() - } - - return cmd.Int64() - } - - return &redisScaler{ + scaler := &redisScaler{ metricType: metricType, metadata: meta, closeFn: closeFn, - getListLengthFn: listLengthFn, + getValueFn: getValueFn(meta, client), + activationValue: getActivationValue(meta), logger: logger, - }, nil + } + + return scaler, nil } -func createSentinelRedisScaler(ctx context.Context, meta *redisMetadata, script string, metricType v2.MetricTargetType, logger logr.Logger) (Scaler, error) { +func createSentinelRedisScaler(ctx context.Context, meta *redisMetadata, metricType v2.MetricTargetType, logger logr.Logger) (Scaler, error) { client, err := getRedisSentinelClient(ctx, meta.ConnectionInfo, meta.DatabaseIndex) if err != nil { return nil, fmt.Errorf("connection to redis sentinel failed: %w", err) } - return createRedisScalerWithClient(client, meta, script, metricType, logger), nil + return createRedisScalerWithClient(client, meta, metricType, logger), nil } -func createRedisScaler(ctx context.Context, meta *redisMetadata, script string, metricType v2.MetricTargetType, logger logr.Logger) (Scaler, error) { +func createRedisScaler(ctx context.Context, meta *redisMetadata, metricType v2.MetricTargetType, logger logr.Logger) (Scaler, error) { client, err := getRedisClient(ctx, meta.ConnectionInfo, meta.DatabaseIndex) if err != nil { return nil, fmt.Errorf("connection to redis failed: %w", err) } - return createRedisScalerWithClient(client, meta, script, metricType, logger), nil + return createRedisScalerWithClient(client, meta, metricType, logger), nil } -func createRedisScalerWithClient(client *redis.Client, meta *redisMetadata, script string, metricType v2.MetricTargetType, logger logr.Logger) Scaler { +func createRedisScalerWithClient(client *redis.Client, meta *redisMetadata, metricType v2.MetricTargetType, logger logr.Logger) Scaler { closeFn := func() error { if err := client.Close(); err != nil { logger.Error(err, "error closing redis client") @@ -213,20 +260,12 @@ func createRedisScalerWithClient(client *redis.Client, meta *redisMetadata, scri return nil } - listLengthFn := func(ctx context.Context) (int64, error) { - cmd := client.Eval(ctx, script, []string{meta.ListName}) - if cmd.Err() != nil { - return -1, cmd.Err() - } - - return cmd.Int64() - } - return &redisScaler{ metricType: metricType, metadata: meta, closeFn: closeFn, - getListLengthFn: listLengthFn, + getValueFn: getValueFn(meta, client), + activationValue: getActivationValue(meta), logger: logger, } } @@ -262,16 +301,15 @@ func (s *redisScaler) GetMetricSpecForScaling(context.Context) []v2.MetricSpec { // GetMetricsAndActivity connects to Redis and finds the length of the list func (s *redisScaler) GetMetricsAndActivity(ctx context.Context, metricName string) ([]external_metrics.ExternalMetricValue, bool, error) { - listLen, err := s.getListLengthFn(ctx) - + value, err := s.getValueFn(ctx) if err != nil { - s.logger.Error(err, "error getting list length") + s.logger.Error(err, "error getting value") return []external_metrics.ExternalMetricValue{}, false, err } - metric := GenerateMetricInMili(metricName, float64(listLen)) + metric := GenerateMetricInMili(metricName, value) - return []external_metrics.ExternalMetricValue{metric}, listLen > s.metadata.ActivationListLength, nil + return []external_metrics.ExternalMetricValue{metric}, value > s.activationValue, nil } func validateRedisAddress(c *redisConnectionInfo) error { @@ -283,7 +321,6 @@ func validateRedisAddress(c *redisConnectionInfo) error { c.Addresses = append(c.Addresses, net.JoinHostPort(c.Hosts[i], c.Ports[i])) } } - // } if len(c.Addresses) == 0 || len(c.Addresses[0]) == 0 { return ErrRedisNoAddresses diff --git a/pkg/scalers/redis_scaler_test.go b/pkg/scalers/redis_scaler_test.go index 734a1c359a0..28ccd1d3a84 100644 --- a/pkg/scalers/redis_scaler_test.go +++ b/pkg/scalers/redis_scaler_test.go @@ -71,7 +71,16 @@ var testRedisMetadata = []parseRedisMetadataTestData{ // enableTLS is defined both in authParams and metadata {map[string]string{"listName": "mylist", "listLength": "0", "enableTLS": "true"}, true, map[string]string{"address": "localhost:6379", "tls": "disable"}, true}, // host only is defined in the authParams - {map[string]string{"listName": "mylist", "listLength": "0"}, true, map[string]string{"host": "localhost"}, false}} + {map[string]string{"listName": "mylist", "listLength": "0"}, true, map[string]string{"host": "localhost"}, false}, + // properly formed keyName + {map[string]string{"keyName": "mykey", "keyValue": "10", "addressFromEnv": "REDIS_HOST", "passwordFromEnv": "REDIS_PASSWORD"}, false, map[string]string{}, false}, + // improperly formed keyValue + {map[string]string{"keyName": "mykey", "keyValue": "AA", "addressFromEnv": "REDIS_HOST", "passwordFromEnv": "REDIS_PASSWORD"}, true, map[string]string{}, false}, + // improperly formed activationKeyValue + {map[string]string{"keyName": "mykey", "keyValue": "10", "activationKeyValue": "AA", "addressFromEnv": "REDIS_HOST", "passwordFromEnv": "REDIS_PASSWORD"}, true, map[string]string{}, false}, + // both keyName and listName are set + {map[string]string{"listName": "mylist", "listLength": "10", "keyName": "mykey", "keyValue": "10", "addressFromEnv": "REDIS_HOST", "passwordFromEnv": "REDIS_PASSWORD"}, true, map[string]string{}, false}, +} var redisMetricIdentifiers = []redisMetricIdentifier{ {&testRedisMetadata[1], 0, "s0-redis-mylist"}, @@ -119,12 +128,13 @@ func TestRedisGetMetricSpecForScaling(t *testing.T) { t.Fatal("Could not parse metadata:", err) } closeFn := func() error { return nil } - lengthFn := func(context.Context) (int64, error) { return -1, nil } + valueFn := func(context.Context) (float64, error) { return -1, nil } mockRedisScaler := redisScaler{ "", meta, closeFn, - lengthFn, + valueFn, + 0, logr.Discard(), } @@ -161,7 +171,7 @@ func TestParseRedisClusterMetadata(t *testing.T) { wantErr: ErrRedisUnequalHostsAndPorts, }, { - name: "no list name", + name: "no list name and key name", metadata: map[string]string{ "hosts": "a, b, c", "ports": "1, 2, 3", @@ -181,6 +191,30 @@ func TestParseRedisClusterMetadata(t *testing.T) { wantMeta: nil, wantErr: ErrRedisParse, }, + { + name: "invalid key value", + metadata: map[string]string{ + "hosts": "a, b, c", + "ports": "1, 2, 3", + "keyName": "mykey", + "keyValue": "invalid", + }, + wantMeta: nil, + wantErr: ErrRedisParse, + }, + { + name: "both key name and list name", + metadata: map[string]string{ + "hosts": "a, b, c", + "ports": "1, 2, 3", + "keyName": "mykey", + "keyValue": "10", + "listName": "mylist", + "listLength": "10", + }, + wantMeta: nil, + wantErr: ErrRedisParse, + }, { name: "address is defined in auth params", metadata: map[string]string{ @@ -192,6 +226,7 @@ func TestParseRedisClusterMetadata(t *testing.T) { wantMeta: &redisMetadata{ ListLength: 5, ListName: "mylist", + KeyValue: 5, // default value ConnectionInfo: redisConnectionInfo{ Addresses: []string{":7001", ":7002"}, }, @@ -210,6 +245,7 @@ func TestParseRedisClusterMetadata(t *testing.T) { wantMeta: &redisMetadata{ ListLength: 5, ListName: "mylist", + KeyValue: 5, // default value ConnectionInfo: redisConnectionInfo{ Addresses: []string{"a:1", "b:2", "c:3"}, Hosts: []string{"a", "b", "c"}, @@ -231,6 +267,7 @@ func TestParseRedisClusterMetadata(t *testing.T) { wantMeta: &redisMetadata{ ListLength: 5, ListName: "mylist", + KeyValue: 5, // default value ConnectionInfo: redisConnectionInfo{ Addresses: []string{"a:1", "b:2", "c:3"}, Hosts: []string{"a", "b", "c"}, @@ -252,6 +289,7 @@ func TestParseRedisClusterMetadata(t *testing.T) { wantMeta: &redisMetadata{ ListLength: 5, ListName: "mylist", + KeyValue: 5, // default value ConnectionInfo: redisConnectionInfo{ Addresses: []string{"a:1", "b:2", "c:3"}, Hosts: []string{"a", "b", "c"}, @@ -274,6 +312,7 @@ func TestParseRedisClusterMetadata(t *testing.T) { wantMeta: &redisMetadata{ ListLength: 5, ListName: "mylist", + KeyValue: 5, // default value ConnectionInfo: redisConnectionInfo{ Addresses: []string{"a:1", "b:2", "c:3"}, Hosts: []string{"a", "b", "c"}, @@ -296,6 +335,7 @@ func TestParseRedisClusterMetadata(t *testing.T) { wantMeta: &redisMetadata{ ListLength: 5, ListName: "mylist", + KeyValue: 5, // default value ConnectionInfo: redisConnectionInfo{ Addresses: []string{"a:1", "b:2", "c:3"}, Hosts: []string{"a", "b", "c"}, @@ -318,6 +358,7 @@ func TestParseRedisClusterMetadata(t *testing.T) { wantMeta: &redisMetadata{ ListLength: 5, ListName: "mylist", + KeyValue: 5, // default value ConnectionInfo: redisConnectionInfo{ Addresses: []string{"a:1", "b:2", "c:3"}, Hosts: []string{"a", "b", "c"}, @@ -339,6 +380,7 @@ func TestParseRedisClusterMetadata(t *testing.T) { wantMeta: &redisMetadata{ ListLength: 5, ListName: "mylist", + KeyValue: 5, // default value ConnectionInfo: redisConnectionInfo{ Addresses: []string{":7001", ":7002"}, EnableTLS: true, @@ -360,6 +402,7 @@ func TestParseRedisClusterMetadata(t *testing.T) { wantMeta: &redisMetadata{ ListLength: 5, ListName: "mylist", + KeyValue: 5, // default value ConnectionInfo: redisConnectionInfo{ Addresses: []string{":7001", ":7002"}, EnableTLS: true, @@ -413,7 +456,7 @@ func TestParseRedisSentinelMetadata(t *testing.T) { wantErr: ErrRedisUnequalHostsAndPorts, }, { - name: "no list name", + name: "no key name and list name", metadata: map[string]string{ "hosts": "a, b, c", "ports": "1, 2, 3", @@ -433,6 +476,30 @@ func TestParseRedisSentinelMetadata(t *testing.T) { wantMeta: nil, wantErr: ErrRedisParse, }, + { + name: "invalid key value", + metadata: map[string]string{ + "hosts": "a, b, c", + "ports": "1, 2, 3", + "keyName": "mykey", + "keyValue": "invalid", + }, + wantMeta: nil, + wantErr: ErrRedisParse, + }, + { + name: "both key name and list name", + metadata: map[string]string{ + "hosts": "a, b, c", + "ports": "1, 2, 3", + "keyName": "mykey", + "keyValue": "10", + "listName": "mylist", + "listLength": "10", + }, + wantMeta: nil, + wantErr: ErrRedisParse, + }, { name: "address is defined in auth params", metadata: map[string]string{ @@ -444,6 +511,7 @@ func TestParseRedisSentinelMetadata(t *testing.T) { wantMeta: &redisMetadata{ ListLength: 5, ListName: "mylist", + KeyValue: 5, // default value ConnectionInfo: redisConnectionInfo{ Addresses: []string{":7001", ":7002"}, }, @@ -462,6 +530,7 @@ func TestParseRedisSentinelMetadata(t *testing.T) { wantMeta: &redisMetadata{ ListLength: 5, ListName: "mylist", + KeyValue: 5, // default value ConnectionInfo: redisConnectionInfo{ Addresses: []string{"a:1", "b:2", "c:3"}, Hosts: []string{"a", "b", "c"}, @@ -482,6 +551,7 @@ func TestParseRedisSentinelMetadata(t *testing.T) { wantMeta: &redisMetadata{ ListLength: 5, ListName: "mylist", + KeyValue: 5, // default value ConnectionInfo: redisConnectionInfo{ Addresses: []string{"a:1", "b:2", "c:3"}, Hosts: []string{"a", "b", "c"}, @@ -503,6 +573,7 @@ func TestParseRedisSentinelMetadata(t *testing.T) { wantMeta: &redisMetadata{ ListLength: 5, ListName: "mylist", + KeyValue: 5, // default value ConnectionInfo: redisConnectionInfo{ Addresses: []string{"a:1", "b:2", "c:3"}, Hosts: []string{"a", "b", "c"}, @@ -524,6 +595,7 @@ func TestParseRedisSentinelMetadata(t *testing.T) { wantMeta: &redisMetadata{ ListLength: 5, ListName: "mylist", + KeyValue: 5, // default value ConnectionInfo: redisConnectionInfo{ Addresses: []string{"a:1", "b:2", "c:3"}, Hosts: []string{"a", "b", "c"}, @@ -546,6 +618,7 @@ func TestParseRedisSentinelMetadata(t *testing.T) { wantMeta: &redisMetadata{ ListLength: 5, ListName: "mylist", + KeyValue: 5, // default value ConnectionInfo: redisConnectionInfo{ Addresses: []string{"a:1", "b:2", "c:3"}, Hosts: []string{"a", "b", "c"}, @@ -568,6 +641,7 @@ func TestParseRedisSentinelMetadata(t *testing.T) { wantMeta: &redisMetadata{ ListLength: 5, ListName: "mylist", + KeyValue: 5, // default value ConnectionInfo: redisConnectionInfo{ Addresses: []string{"a:1", "b:2", "c:3"}, Hosts: []string{"a", "b", "c"}, @@ -590,6 +664,7 @@ func TestParseRedisSentinelMetadata(t *testing.T) { wantMeta: &redisMetadata{ ListLength: 5, ListName: "mylist", + KeyValue: 5, // default value ConnectionInfo: redisConnectionInfo{ Addresses: []string{"a:1", "b:2", "c:3"}, Hosts: []string{"a", "b", "c"}, @@ -612,6 +687,7 @@ func TestParseRedisSentinelMetadata(t *testing.T) { wantMeta: &redisMetadata{ ListLength: 5, ListName: "mylist", + KeyValue: 5, // default value ConnectionInfo: redisConnectionInfo{ Addresses: []string{"a:1", "b:2", "c:3"}, Hosts: []string{"a", "b", "c"}, @@ -633,6 +709,7 @@ func TestParseRedisSentinelMetadata(t *testing.T) { wantMeta: &redisMetadata{ ListLength: 5, ListName: "mylist", + KeyValue: 5, // default value ConnectionInfo: redisConnectionInfo{ Addresses: []string{"a:1", "b:2", "c:3"}, Hosts: []string{"a", "b", "c"}, @@ -655,6 +732,7 @@ func TestParseRedisSentinelMetadata(t *testing.T) { wantMeta: &redisMetadata{ ListLength: 5, ListName: "mylist", + KeyValue: 5, // default value ConnectionInfo: redisConnectionInfo{ Addresses: []string{"a:1", "b:2", "c:3"}, Hosts: []string{"a", "b", "c"}, @@ -677,6 +755,7 @@ func TestParseRedisSentinelMetadata(t *testing.T) { wantMeta: &redisMetadata{ ListLength: 5, ListName: "mylist", + KeyValue: 5, // default value ConnectionInfo: redisConnectionInfo{ Addresses: []string{"a:1", "b:2", "c:3"}, Hosts: []string{"a", "b", "c"}, @@ -699,6 +778,7 @@ func TestParseRedisSentinelMetadata(t *testing.T) { wantMeta: &redisMetadata{ ListLength: 5, ListName: "mylist", + KeyValue: 5, // default value ConnectionInfo: redisConnectionInfo{ Addresses: []string{"a:1", "b:2", "c:3"}, Hosts: []string{"a", "b", "c"}, @@ -721,6 +801,7 @@ func TestParseRedisSentinelMetadata(t *testing.T) { wantMeta: &redisMetadata{ ListLength: 5, ListName: "mylist", + KeyValue: 5, // default value ConnectionInfo: redisConnectionInfo{ Addresses: []string{"a:1", "b:2", "c:3"}, Hosts: []string{"a", "b", "c"}, @@ -742,6 +823,7 @@ func TestParseRedisSentinelMetadata(t *testing.T) { wantMeta: &redisMetadata{ ListLength: 5, ListName: "mylist", + KeyValue: 5, // default value ConnectionInfo: redisConnectionInfo{ Addresses: []string{"a:1", "b:2", "c:3"}, Hosts: []string{"a", "b", "c"}, @@ -764,6 +846,7 @@ func TestParseRedisSentinelMetadata(t *testing.T) { wantMeta: &redisMetadata{ ListLength: 5, ListName: "mylist", + KeyValue: 5, // default value ConnectionInfo: redisConnectionInfo{ Addresses: []string{"a:1", "b:2", "c:3"}, Hosts: []string{"a", "b", "c"}, @@ -785,6 +868,7 @@ func TestParseRedisSentinelMetadata(t *testing.T) { wantMeta: &redisMetadata{ ListLength: 5, ListName: "mylist", + KeyValue: 5, // default value ConnectionInfo: redisConnectionInfo{ Addresses: []string{":7001", ":7002"}, EnableTLS: true, @@ -806,6 +890,7 @@ func TestParseRedisSentinelMetadata(t *testing.T) { wantMeta: &redisMetadata{ ListLength: 5, ListName: "mylist", + KeyValue: 5, // default value ConnectionInfo: redisConnectionInfo{ Addresses: []string{":7001", ":7002"}, EnableTLS: true, diff --git a/tests/scalers/redis/helper/helper.go b/tests/scalers/redis/helper/helper.go index a052f79e0f9..eb4a0532ef5 100644 --- a/tests/scalers/redis/helper/helper.go +++ b/tests/scalers/redis/helper/helper.go @@ -65,6 +65,20 @@ spec: targetPort: 6379 selector: app: {{.RedisName}}` + + clientRedisTemplate = `apiVersion: v1 +kind: Pod +metadata: + name: {{.RedisName}} + namespace: {{.Namespace}} +spec: + containers: + - name: {{.RedisName}} + image: redis:7.0 + command: + - sh + - -c + - "exec tail -f /dev/null"` ) func InstallStandalone(t *testing.T, kc *kubernetes.Clientset, name, namespace, password string) { @@ -127,3 +141,20 @@ func RemoveCluster(t *testing.T, name, namespace string) { assert.NoErrorf(t, err, "cannot execute command - %s", err) helper.DeleteNamespace(t, namespace) } + +func InstallClient(t *testing.T, kc *kubernetes.Clientset, name, namespace string) { + var data = templateData{ + Namespace: namespace, + RedisName: name, + } + helper.KubectlApplyWithTemplate(t, data, "redisClientTemplate", clientRedisTemplate) +} + +func RemoveClient(t *testing.T, name, namespace string) { + var data = templateData{ + Namespace: namespace, + RedisName: name, + } + helper.KubectlApplyWithTemplate(t, data, "redisClientTemplate", clientRedisTemplate) + helper.DeleteNamespace(t, namespace) +} diff --git a/tests/scalers/redis/redis_cluster_strings/redis_cluster_strings_test.go b/tests/scalers/redis/redis_cluster_strings/redis_cluster_strings_test.go new file mode 100644 index 00000000000..f3c6fcf5169 --- /dev/null +++ b/tests/scalers/redis/redis_cluster_strings/redis_cluster_strings_test.go @@ -0,0 +1,207 @@ +//go:build e2e +// +build e2e + +package redis_standalone_keyvalue_test + +import ( + "encoding/base64" + "fmt" + "testing" + "time" + + "github.com/joho/godotenv" + "github.com/stretchr/testify/assert" + "k8s.io/client-go/kubernetes" + + . "github.com/kedacore/keda/v2/tests/helper" + redis "github.com/kedacore/keda/v2/tests/scalers/redis/helper" +) + +// Load environment variables from .env file +var _ = godotenv.Load("../../.env") + +const ( + testName = "redis-cluster-keyvalue-test" +) + +var ( + testNamespace = fmt.Sprintf("%s-ns", testName) + redisNamespace = fmt.Sprintf("%s-redis-ns", testName) + deploymentName = fmt.Sprintf("%s-deployment", testName) + clientName = fmt.Sprintf("%s-client", testName) + scaledObjectName = fmt.Sprintf("%s-so", testName) + triggerAuthenticationName = fmt.Sprintf("%s-ta", testName) + secretName = fmt.Sprintf("%s-secret", testName) + redisPassword = "admin" + redisKey = fmt.Sprintf("%s-key", testName) + redisHost = fmt.Sprintf("%s-headless", testName) + minReplicaCount = 0 + maxReplicaCount = 2 +) + +type templateData struct { + TestNamespace string + RedisNamespace string + DeploymentName string + ScaledObjectName string + TriggerAuthenticationName string + SecretName string + MinReplicaCount int + MaxReplicaCount int + RedisPassword string + RedisPasswordBase64 string + RedisKey string + RedisHost string +} + +const ( + deploymentTemplate = `apiVersion: apps/v1 +kind: Deployment +metadata: + name: {{.DeploymentName}} + namespace: {{.TestNamespace}} +spec: + selector: + matchLabels: + app: {{.DeploymentName}} + replicas: 0 + template: + metadata: + labels: + app: {{.DeploymentName}} + spec: + containers: + - name: my-app + image: nginxinc/nginx-unprivileged + imagePullPolicy: IfNotPresent + ports: + - containerPort: 80 + env: + - name: REDIS_ADDRESSES + value: {{.RedisHost}}.{{.RedisNamespace}}:6379 + - name: REDIS_PORT + value: "6379" +` + + secretTemplate = `apiVersion: v1 +kind: Secret +metadata: + name: {{.SecretName}} + namespace: {{.TestNamespace}} +type: Opaque +data: + password: {{.RedisPasswordBase64}} +` + + triggerAuthenticationTemplate = `apiVersion: keda.sh/v1alpha1 +kind: TriggerAuthentication +metadata: + name: {{.TriggerAuthenticationName}} + namespace: {{.TestNamespace}} +spec: + secretTargetRef: + - parameter: password + name: {{.SecretName}} + key: password +` + + scaledObjectTemplate = `apiVersion: keda.sh/v1alpha1 +kind: ScaledObject +metadata: + name: {{.ScaledObjectName}} + namespace: {{.TestNamespace}} +spec: + scaleTargetRef: + name: {{.DeploymentName}} + pollingInterval: 5 + cooldownPeriod: 10 + minReplicaCount: {{.MinReplicaCount}} + maxReplicaCount: {{.MaxReplicaCount}} + triggers: + - type: redis + metadata: + addressesFromEnv: REDIS_ADDRESSES + keyName: {{.RedisKey}} + keyValue: "1.5" + activationKeyValue: "5" + authenticationRef: + name: {{.TriggerAuthenticationName}} +` +) + +func TestScaler(t *testing.T) { + // Create kubernetes resources for PostgreSQL server + kc := GetKubernetesClient(t) + data, templates := getTemplateData() + t.Cleanup(func() { + redis.RemoveCluster(t, testName, redisNamespace) + redis.RemoveClient(t, clientName, redisNamespace) + DeleteKubernetesResources(t, testNamespace, data, templates) + }) + + // Create Redis Cluster + redis.InstallCluster(t, kc, testName, redisNamespace, redisPassword) + + redis.InstallClient(t, kc, clientName, redisNamespace) + // wait until client is ready + time.Sleep(10 * time.Second) + + // Create kubernetes resources for testing + CreateKubernetesResources(t, kc, testNamespace, data, templates) + + testActivation(t, kc, data) + testScaleOut(t, kc, data) + testScaleIn(t, kc) +} + +func testActivation(t *testing.T, kc *kubernetes.Clientset, data templateData) { + t.Log("--- testing activation ---") + setKeyValue(t, 4) + + AssertReplicaCountNotChangeDuringTimePeriod(t, kc, deploymentName, testNamespace, minReplicaCount, 60) +} + +func testScaleOut(t *testing.T, kc *kubernetes.Clientset, data templateData) { + t.Log("--- testing scale out ---") + setKeyValue(t, 10) + + assert.True(t, WaitForDeploymentReplicaReadyCount(t, kc, deploymentName, testNamespace, maxReplicaCount, 60, 3), + "replica count should be %d after 3 minutes", maxReplicaCount) +} + +func testScaleIn(t *testing.T, kc *kubernetes.Clientset) { + t.Log("--- testing scale in ---") + setKeyValue(t, 0) + assert.True(t, WaitForDeploymentReplicaReadyCount(t, kc, deploymentName, testNamespace, minReplicaCount, 60, 3), + "replica count should be %d after 3 minutes", minReplicaCount) +} + +var data = templateData{ + TestNamespace: testNamespace, + RedisNamespace: redisNamespace, + DeploymentName: deploymentName, + ScaledObjectName: scaledObjectName, + MinReplicaCount: minReplicaCount, + MaxReplicaCount: maxReplicaCount, + TriggerAuthenticationName: triggerAuthenticationName, + SecretName: secretName, + RedisPassword: redisPassword, + RedisPasswordBase64: base64.StdEncoding.EncodeToString([]byte(redisPassword)), + RedisKey: redisKey, + RedisHost: redisHost, +} + +func getTemplateData() (templateData, []Template) { + return data, []Template{ + {Name: "secretTemplate", Config: secretTemplate}, + {Name: "deploymentTemplate", Config: deploymentTemplate}, + {Name: "triggerAuthenticationTemplate", Config: triggerAuthenticationTemplate}, + {Name: "scaledObjectTemplate", Config: scaledObjectTemplate}, + } +} + +func setKeyValue(t *testing.T, value int) { + _, _, err := ExecCommandOnSpecificPod(t, clientName, redisNamespace, + fmt.Sprintf(`redis-cli -c -h %s --pass %s SET %s %d`, redisHost, redisPassword, redisKey, value)) + assert.NoErrorf(t, err, "cannot execute command - %s", err) +} diff --git a/tests/scalers/redis/redis_sentinel_strings/redis_sentinel_strings_test.go b/tests/scalers/redis/redis_sentinel_strings/redis_sentinel_strings_test.go new file mode 100644 index 00000000000..3f06310ae75 --- /dev/null +++ b/tests/scalers/redis/redis_sentinel_strings/redis_sentinel_strings_test.go @@ -0,0 +1,211 @@ +//go:build e2e +// +build e2e + +package redis_standalone_keyvalue_test + +import ( + "encoding/base64" + "fmt" + "testing" + "time" + + "github.com/joho/godotenv" + "github.com/stretchr/testify/assert" + "k8s.io/client-go/kubernetes" + + . "github.com/kedacore/keda/v2/tests/helper" + redis "github.com/kedacore/keda/v2/tests/scalers/redis/helper" +) + +// Load environment variables from .env file +var _ = godotenv.Load("../../.env") + +const ( + testName = "redis-sentinel-keyvalue-test" +) + +var ( + testNamespace = fmt.Sprintf("%s-ns", testName) + redisNamespace = fmt.Sprintf("%s-redis-ns", testName) + deploymentName = fmt.Sprintf("%s-deployment", testName) + clientName = fmt.Sprintf("%s-client", testName) + scaledObjectName = fmt.Sprintf("%s-so", testName) + triggerAuthenticationName = fmt.Sprintf("%s-ta", testName) + secretName = fmt.Sprintf("%s-secret", testName) + redisPassword = "admin" + redisKey = fmt.Sprintf("%s-key", testName) + redisHost = fmt.Sprintf("%s-headless", testName) + minReplicaCount = 0 + maxReplicaCount = 2 +) + +type templateData struct { + TestNamespace string + RedisNamespace string + DeploymentName string + ScaledObjectName string + TriggerAuthenticationName string + SecretName string + MinReplicaCount int + MaxReplicaCount int + RedisPassword string + RedisPasswordBase64 string + RedisKey string + RedisHost string +} + +const ( + deploymentTemplate = `apiVersion: apps/v1 +kind: Deployment +metadata: + name: {{.DeploymentName}} + namespace: {{.TestNamespace}} +spec: + selector: + matchLabels: + app: {{.DeploymentName}} + replicas: 0 + template: + metadata: + labels: + app: {{.DeploymentName}} + spec: + containers: + - name: my-app + image: nginxinc/nginx-unprivileged + imagePullPolicy: IfNotPresent + ports: + - containerPort: 80 + env: + - name: REDIS_ADDRESSES + value: {{.RedisHost}}.{{.RedisNamespace}}:26379 + - name: REDIS_PORT + value: "6379" +` + + secretTemplate = `apiVersion: v1 +kind: Secret +metadata: + name: {{.SecretName}} + namespace: {{.TestNamespace}} +type: Opaque +data: + password: {{.RedisPasswordBase64}} +` + + triggerAuthenticationTemplate = `apiVersion: keda.sh/v1alpha1 +kind: TriggerAuthentication +metadata: + name: {{.TriggerAuthenticationName}} + namespace: {{.TestNamespace}} +spec: + secretTargetRef: + - parameter: password + name: {{.SecretName}} + key: password + - parameter: sentinelPassword + name: {{.SecretName}} + key: password +` + + scaledObjectTemplate = `apiVersion: keda.sh/v1alpha1 +kind: ScaledObject +metadata: + name: {{.ScaledObjectName}} + namespace: {{.TestNamespace}} +spec: + scaleTargetRef: + name: {{.DeploymentName}} + pollingInterval: 5 + cooldownPeriod: 10 + minReplicaCount: {{.MinReplicaCount}} + maxReplicaCount: {{.MaxReplicaCount}} + triggers: + - type: redis + metadata: + addressesFromEnv: REDIS_ADDRESSES + sentinelMaster: mymaster + keyName: {{.RedisKey}} + keyValue: "1.5" + activationKeyValue: "5" + authenticationRef: + name: {{.TriggerAuthenticationName}} +` +) + +func TestScaler(t *testing.T) { + // Create kubernetes resources for PostgreSQL server + kc := GetKubernetesClient(t) + data, templates := getTemplateData() + t.Cleanup(func() { + redis.RemoveSentinel(t, testName, redisNamespace) + redis.RemoveClient(t, clientName, redisNamespace) + DeleteKubernetesResources(t, testNamespace, data, templates) + }) + + // Create Redis Standalone + redis.InstallSentinel(t, kc, testName, redisNamespace, redisPassword) + redis.InstallClient(t, kc, clientName, redisNamespace) + // wait until client is ready + time.Sleep(10 * time.Second) + + // Create kubernetes resources for testing + CreateKubernetesResources(t, kc, testNamespace, data, templates) + + testActivation(t, kc, data) + testScaleOut(t, kc, data) + testScaleIn(t, kc) +} + +func testActivation(t *testing.T, kc *kubernetes.Clientset, data templateData) { + t.Log("--- testing activation ---") + setKeyValue(t, 4) + + AssertReplicaCountNotChangeDuringTimePeriod(t, kc, deploymentName, testNamespace, minReplicaCount, 60) +} + +func testScaleOut(t *testing.T, kc *kubernetes.Clientset, data templateData) { + t.Log("--- testing scale out ---") + setKeyValue(t, 10) + + assert.True(t, WaitForDeploymentReplicaReadyCount(t, kc, deploymentName, testNamespace, maxReplicaCount, 60, 3), + "replica count should be %d after 3 minutes", maxReplicaCount) +} + +func testScaleIn(t *testing.T, kc *kubernetes.Clientset) { + t.Log("--- testing scale in ---") + setKeyValue(t, 0) + assert.True(t, WaitForDeploymentReplicaReadyCount(t, kc, deploymentName, testNamespace, minReplicaCount, 60, 3), + "replica count should be %d after 3 minutes", minReplicaCount) +} + +var data = templateData{ + TestNamespace: testNamespace, + RedisNamespace: redisNamespace, + DeploymentName: deploymentName, + ScaledObjectName: scaledObjectName, + MinReplicaCount: minReplicaCount, + MaxReplicaCount: maxReplicaCount, + TriggerAuthenticationName: triggerAuthenticationName, + SecretName: secretName, + RedisPassword: redisPassword, + RedisPasswordBase64: base64.StdEncoding.EncodeToString([]byte(redisPassword)), + RedisKey: redisKey, + RedisHost: redisHost, +} + +func getTemplateData() (templateData, []Template) { + return data, []Template{ + {Name: "secretTemplate", Config: secretTemplate}, + {Name: "deploymentTemplate", Config: deploymentTemplate}, + {Name: "triggerAuthenticationTemplate", Config: triggerAuthenticationTemplate}, + {Name: "scaledObjectTemplate", Config: scaledObjectTemplate}, + } +} + +func setKeyValue(t *testing.T, value int) { + _, _, err := ExecCommandOnSpecificPod(t, clientName, redisNamespace, + fmt.Sprintf(`redis-cli --pass %s -h %s -p 26379 SENTINEL get-master-addr-by-name mymaster | xargs -n 2 sh -c 'redis-cli --pass %s -h $0 -p $1 SET %s %d'`, + redisPassword, redisHost, redisPassword, redisKey, value)) + assert.NoErrorf(t, err, "cannot execute command - %s", err) +} diff --git a/tests/scalers/redis/redis_standalone_strings/redis_standlone_strings_test.go b/tests/scalers/redis/redis_standalone_strings/redis_standlone_strings_test.go new file mode 100644 index 00000000000..5115398abf1 --- /dev/null +++ b/tests/scalers/redis/redis_standalone_strings/redis_standlone_strings_test.go @@ -0,0 +1,205 @@ +//go:build e2e +// +build e2e + +package redis_standalone_keyvalue_test + +import ( + "encoding/base64" + "fmt" + "testing" + "time" + + "github.com/joho/godotenv" + "github.com/stretchr/testify/assert" + "k8s.io/client-go/kubernetes" + + . "github.com/kedacore/keda/v2/tests/helper" + redis "github.com/kedacore/keda/v2/tests/scalers/redis/helper" +) + +// Load environment variables from .env file +var _ = godotenv.Load("../../.env") + +const ( + testName = "redis-standalone-keyvalue-test" +) + +var ( + testNamespace = fmt.Sprintf("%s-ns", testName) + redisNamespace = fmt.Sprintf("%s-redis-ns", testName) + deploymentName = fmt.Sprintf("%s-deployment", testName) + clientName = fmt.Sprintf("%s-client", testName) + scaledObjectName = fmt.Sprintf("%s-so", testName) + triggerAuthenticationName = fmt.Sprintf("%s-ta", testName) + secretName = fmt.Sprintf("%s-secret", testName) + redisPassword = "admin" + redisKey = fmt.Sprintf("%s-key", testName) + redisHost = fmt.Sprintf("redis.%s.svc.cluster.local", redisNamespace) + minReplicaCount = 0 + maxReplicaCount = 2 +) + +type templateData struct { + TestNamespace string + DeploymentName string + ScaledObjectName string + TriggerAuthenticationName string + SecretName string + MinReplicaCount int + MaxReplicaCount int + RedisPassword string + RedisPasswordBase64 string + RedisKey string + RedisHost string +} + +const ( + deploymentTemplate = `apiVersion: apps/v1 +kind: Deployment +metadata: + name: {{.DeploymentName}} + namespace: {{.TestNamespace}} +spec: + selector: + matchLabels: + app: {{.DeploymentName}} + replicas: 0 + template: + metadata: + labels: + app: {{.DeploymentName}} + spec: + containers: + - name: my-app + image: nginxinc/nginx-unprivileged + imagePullPolicy: IfNotPresent + ports: + - containerPort: 80 + env: + - name: REDIS_HOST + value: {{.RedisHost}} + - name: REDIS_PORT + value: "6379" +` + + secretTemplate = `apiVersion: v1 +kind: Secret +metadata: + name: {{.SecretName}} + namespace: {{.TestNamespace}} +type: Opaque +data: + password: {{.RedisPasswordBase64}} +` + + triggerAuthenticationTemplate = `apiVersion: keda.sh/v1alpha1 +kind: TriggerAuthentication +metadata: + name: {{.TriggerAuthenticationName}} + namespace: {{.TestNamespace}} +spec: + secretTargetRef: + - parameter: password + name: {{.SecretName}} + key: password +` + + scaledObjectTemplate = `apiVersion: keda.sh/v1alpha1 +kind: ScaledObject +metadata: + name: {{.ScaledObjectName}} + namespace: {{.TestNamespace}} +spec: + scaleTargetRef: + name: {{.DeploymentName}} + pollingInterval: 5 + cooldownPeriod: 10 + minReplicaCount: {{.MinReplicaCount}} + maxReplicaCount: {{.MaxReplicaCount}} + triggers: + - type: redis + metadata: + hostFromEnv: REDIS_HOST + portFromEnv: REDIS_PORT + keyName: {{.RedisKey}} + keyValue: "1.5" + activationKeyValue: "5" + authenticationRef: + name: {{.TriggerAuthenticationName}} +` +) + +func TestScaler(t *testing.T) { + // Create kubernetes resources for PostgreSQL server + kc := GetKubernetesClient(t) + data, templates := getTemplateData() + t.Cleanup(func() { + redis.RemoveStandalone(t, testName, redisNamespace) + redis.RemoveClient(t, clientName, redisNamespace) + DeleteKubernetesResources(t, testNamespace, data, templates) + }) + + // Create Redis Standalone + redis.InstallStandalone(t, kc, testName, redisNamespace, redisPassword) + redis.InstallClient(t, kc, clientName, redisNamespace) + // wait until client is ready + time.Sleep(10 * time.Second) + + // Create kubernetes resources for testing + CreateKubernetesResources(t, kc, testNamespace, data, templates) + + testActivation(t, kc, data) + testScaleOut(t, kc, data) + testScaleIn(t, kc) +} + +func testActivation(t *testing.T, kc *kubernetes.Clientset, data templateData) { + t.Log("--- testing activation ---") + setKeyValue(t, 4) + + AssertReplicaCountNotChangeDuringTimePeriod(t, kc, deploymentName, testNamespace, minReplicaCount, 60) +} + +func testScaleOut(t *testing.T, kc *kubernetes.Clientset, data templateData) { + t.Log("--- testing scale out ---") + setKeyValue(t, 10) + + assert.True(t, WaitForDeploymentReplicaReadyCount(t, kc, deploymentName, testNamespace, maxReplicaCount, 60, 3), + "replica count should be %d after 3 minutes", maxReplicaCount) +} + +func testScaleIn(t *testing.T, kc *kubernetes.Clientset) { + t.Log("--- testing scale in ---") + setKeyValue(t, 0) + assert.True(t, WaitForDeploymentReplicaReadyCount(t, kc, deploymentName, testNamespace, minReplicaCount, 60, 3), + "replica count should be %d after 3 minutes", minReplicaCount) +} + +var data = templateData{ + TestNamespace: testNamespace, + DeploymentName: deploymentName, + ScaledObjectName: scaledObjectName, + MinReplicaCount: minReplicaCount, + MaxReplicaCount: maxReplicaCount, + TriggerAuthenticationName: triggerAuthenticationName, + SecretName: secretName, + RedisPassword: redisPassword, + RedisPasswordBase64: base64.StdEncoding.EncodeToString([]byte(redisPassword)), + RedisKey: redisKey, + RedisHost: redisHost, +} + +func getTemplateData() (templateData, []Template) { + return data, []Template{ + {Name: "secretTemplate", Config: secretTemplate}, + {Name: "deploymentTemplate", Config: deploymentTemplate}, + {Name: "triggerAuthenticationTemplate", Config: triggerAuthenticationTemplate}, + {Name: "scaledObjectTemplate", Config: scaledObjectTemplate}, + } +} + +func setKeyValue(t *testing.T, value int) { + _, _, err := ExecCommandOnSpecificPod(t, clientName, redisNamespace, + fmt.Sprintf(`redis-cli -h %s --pass %s SET %s %d`, redisHost, redisPassword, redisKey, value)) + assert.NoErrorf(t, err, "cannot execute command - %s", err) +} From cc7153e4ceff54b53da95c687c2c9a58ac394af8 Mon Sep 17 00:00:00 2001 From: wangrushen Date: Sun, 27 Oct 2024 22:26:27 +0800 Subject: [PATCH 2/4] fix: static check for redis strings e2e test Signed-off-by: wangrushen --- CHANGELOG.md | 2 +- tests/scalers/redis/helper/helper.go | 2 +- .../redis_cluster_strings_test.go | 10 +++++----- .../redis_sentinel_strings_test.go | 10 +++++----- .../redis_standlone_strings_test.go | 10 +++++----- 5 files changed, 17 insertions(+), 17 deletions(-) diff --git a/CHANGELOG.md b/CHANGELOG.md index 37f715bc064..93bf5fa00b4 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -72,7 +72,6 @@ Here is an overview of all new **experimental** features: ### Improvements -- **Redis Scaler**: Provide support for scaling based on Redis Key-Values ([#5003](https://github.com/kedacore/keda/issues/5003)) - **General**: Prevent multiple ScaledObjects managing one HPA ([#6130](https://github.com/kedacore/keda/issues/6130)) - **AWS CloudWatch Scaler**: Add support for ignoreNullValues ([#5352](https://github.com/kedacore/keda/issues/5352)) - **Elasticsearch Scaler**: Support Query at the Elasticsearch scaler ([#6216](https://github.com/kedacore/keda/issues/6216)) @@ -83,6 +82,7 @@ Here is an overview of all new **experimental** features: - **Kafka**: Allow disabling FAST negotation when using Kerberos ([#6188](https://github.com/kedacore/keda/issues/6188)) - **Kafka**: Fix logic to scale to zero on invalid offset even with earliest offsetResetPolicy ([#5689](https://github.com/kedacore/keda/issues/5689)) - **RabbitMQ Scaler**: Add connection name for AMQP ([#5958](https://github.com/kedacore/keda/issues/5958)) +- **Redis Scaler**: Provide support for scaling based on Redis Key-Values ([#5003](https://github.com/kedacore/keda/issues/5003)) - **Selenium Scaler**: Add Support for Username and Password Authentication ([#6144](https://github.com/kedacore/keda/issues/6144)) - **Selenium Scaler**: Introduce new parameters setSessionsFromHub, sessionsPerNode and sessionBrowserVersion. ([#6080](https://github.com/kedacore/keda/issues/6080)) - TODO ([#XXX](https://github.com/kedacore/keda/issues/XXX)) diff --git a/tests/scalers/redis/helper/helper.go b/tests/scalers/redis/helper/helper.go index eb4a0532ef5..6f76537cef8 100644 --- a/tests/scalers/redis/helper/helper.go +++ b/tests/scalers/redis/helper/helper.go @@ -142,7 +142,7 @@ func RemoveCluster(t *testing.T, name, namespace string) { helper.DeleteNamespace(t, namespace) } -func InstallClient(t *testing.T, kc *kubernetes.Clientset, name, namespace string) { +func InstallClient(t *testing.T, name, namespace string) { var data = templateData{ Namespace: namespace, RedisName: name, diff --git a/tests/scalers/redis/redis_cluster_strings/redis_cluster_strings_test.go b/tests/scalers/redis/redis_cluster_strings/redis_cluster_strings_test.go index f3c6fcf5169..af103b48ac5 100644 --- a/tests/scalers/redis/redis_cluster_strings/redis_cluster_strings_test.go +++ b/tests/scalers/redis/redis_cluster_strings/redis_cluster_strings_test.go @@ -142,26 +142,26 @@ func TestScaler(t *testing.T) { // Create Redis Cluster redis.InstallCluster(t, kc, testName, redisNamespace, redisPassword) - redis.InstallClient(t, kc, clientName, redisNamespace) + redis.InstallClient(t, clientName, redisNamespace) // wait until client is ready time.Sleep(10 * time.Second) // Create kubernetes resources for testing CreateKubernetesResources(t, kc, testNamespace, data, templates) - testActivation(t, kc, data) - testScaleOut(t, kc, data) + testActivation(t, kc) + testScaleOut(t, kc) testScaleIn(t, kc) } -func testActivation(t *testing.T, kc *kubernetes.Clientset, data templateData) { +func testActivation(t *testing.T, kc *kubernetes.Clientset) { t.Log("--- testing activation ---") setKeyValue(t, 4) AssertReplicaCountNotChangeDuringTimePeriod(t, kc, deploymentName, testNamespace, minReplicaCount, 60) } -func testScaleOut(t *testing.T, kc *kubernetes.Clientset, data templateData) { +func testScaleOut(t *testing.T, kc *kubernetes.Clientset) { t.Log("--- testing scale out ---") setKeyValue(t, 10) diff --git a/tests/scalers/redis/redis_sentinel_strings/redis_sentinel_strings_test.go b/tests/scalers/redis/redis_sentinel_strings/redis_sentinel_strings_test.go index 3f06310ae75..f5c775361e0 100644 --- a/tests/scalers/redis/redis_sentinel_strings/redis_sentinel_strings_test.go +++ b/tests/scalers/redis/redis_sentinel_strings/redis_sentinel_strings_test.go @@ -145,26 +145,26 @@ func TestScaler(t *testing.T) { // Create Redis Standalone redis.InstallSentinel(t, kc, testName, redisNamespace, redisPassword) - redis.InstallClient(t, kc, clientName, redisNamespace) + redis.InstallClient(t, clientName, redisNamespace) // wait until client is ready time.Sleep(10 * time.Second) // Create kubernetes resources for testing CreateKubernetesResources(t, kc, testNamespace, data, templates) - testActivation(t, kc, data) - testScaleOut(t, kc, data) + testActivation(t, kc) + testScaleOut(t, kc) testScaleIn(t, kc) } -func testActivation(t *testing.T, kc *kubernetes.Clientset, data templateData) { +func testActivation(t *testing.T, kc *kubernetes.Clientset) { t.Log("--- testing activation ---") setKeyValue(t, 4) AssertReplicaCountNotChangeDuringTimePeriod(t, kc, deploymentName, testNamespace, minReplicaCount, 60) } -func testScaleOut(t *testing.T, kc *kubernetes.Clientset, data templateData) { +func testScaleOut(t *testing.T, kc *kubernetes.Clientset) { t.Log("--- testing scale out ---") setKeyValue(t, 10) diff --git a/tests/scalers/redis/redis_standalone_strings/redis_standlone_strings_test.go b/tests/scalers/redis/redis_standalone_strings/redis_standlone_strings_test.go index 5115398abf1..f3a79b3154d 100644 --- a/tests/scalers/redis/redis_standalone_strings/redis_standlone_strings_test.go +++ b/tests/scalers/redis/redis_standalone_strings/redis_standlone_strings_test.go @@ -141,26 +141,26 @@ func TestScaler(t *testing.T) { // Create Redis Standalone redis.InstallStandalone(t, kc, testName, redisNamespace, redisPassword) - redis.InstallClient(t, kc, clientName, redisNamespace) + redis.InstallClient(t, clientName, redisNamespace) // wait until client is ready time.Sleep(10 * time.Second) // Create kubernetes resources for testing CreateKubernetesResources(t, kc, testNamespace, data, templates) - testActivation(t, kc, data) - testScaleOut(t, kc, data) + testActivation(t, kc) + testScaleOut(t, kc) testScaleIn(t, kc) } -func testActivation(t *testing.T, kc *kubernetes.Clientset, data templateData) { +func testActivation(t *testing.T, kc *kubernetes.Clientset) { t.Log("--- testing activation ---") setKeyValue(t, 4) AssertReplicaCountNotChangeDuringTimePeriod(t, kc, deploymentName, testNamespace, minReplicaCount, 60) } -func testScaleOut(t *testing.T, kc *kubernetes.Clientset, data templateData) { +func testScaleOut(t *testing.T, kc *kubernetes.Clientset) { t.Log("--- testing scale out ---") setKeyValue(t, 10) From 544c7f86c393e4867c5688be33a55e6fbda69393 Mon Sep 17 00:00:00 2001 From: wangrushen Date: Tue, 29 Oct 2024 18:40:45 +0800 Subject: [PATCH 3/4] fix: redis e2e tests Signed-off-by: wangrushen --- .../redis_cluster_strings/redis_cluster_strings_test.go | 4 ++-- .../redis_sentinel_strings/redis_sentinel_strings_test.go | 8 ++++++-- .../redis_standlone_strings_test.go | 2 +- 3 files changed, 9 insertions(+), 5 deletions(-) diff --git a/tests/scalers/redis/redis_cluster_strings/redis_cluster_strings_test.go b/tests/scalers/redis/redis_cluster_strings/redis_cluster_strings_test.go index af103b48ac5..5211272b54d 100644 --- a/tests/scalers/redis/redis_cluster_strings/redis_cluster_strings_test.go +++ b/tests/scalers/redis/redis_cluster_strings/redis_cluster_strings_test.go @@ -21,7 +21,7 @@ import ( var _ = godotenv.Load("../../.env") const ( - testName = "redis-cluster-keyvalue-test" + testName = "redis-cluster-strings-test" ) var ( @@ -118,7 +118,7 @@ spec: minReplicaCount: {{.MinReplicaCount}} maxReplicaCount: {{.MaxReplicaCount}} triggers: - - type: redis + - type: redis-cluster metadata: addressesFromEnv: REDIS_ADDRESSES keyName: {{.RedisKey}} diff --git a/tests/scalers/redis/redis_sentinel_strings/redis_sentinel_strings_test.go b/tests/scalers/redis/redis_sentinel_strings/redis_sentinel_strings_test.go index f5c775361e0..c3f3a88694d 100644 --- a/tests/scalers/redis/redis_sentinel_strings/redis_sentinel_strings_test.go +++ b/tests/scalers/redis/redis_sentinel_strings/redis_sentinel_strings_test.go @@ -21,7 +21,7 @@ import ( var _ = godotenv.Load("../../.env") const ( - testName = "redis-sentinel-keyvalue-test" + testName = "redis-sentinel-strings-test" ) var ( @@ -121,7 +121,7 @@ spec: minReplicaCount: {{.MinReplicaCount}} maxReplicaCount: {{.MaxReplicaCount}} triggers: - - type: redis + - type: redis-sentinel metadata: addressesFromEnv: REDIS_ADDRESSES sentinelMaster: mymaster @@ -209,3 +209,7 @@ func setKeyValue(t *testing.T, value int) { redisPassword, redisHost, redisPassword, redisKey, value)) assert.NoErrorf(t, err, "cannot execute command - %s", err) } + +// kubectl exec -n redis-sentinel-strings-test-redis-ns redis-sentinel-strings-test-client -- ' +// redis-cli --pass admin -h redis-sentinel-strings-test-headless -p 26379 SENTINEL get-master-addr-by-name mymaster +// | xargs -n 2 sh -c 'redis-cli --pass admin -h $0 -p $1 get redis-sentinel-strings-test-key' diff --git a/tests/scalers/redis/redis_standalone_strings/redis_standlone_strings_test.go b/tests/scalers/redis/redis_standalone_strings/redis_standlone_strings_test.go index f3a79b3154d..13e140758cf 100644 --- a/tests/scalers/redis/redis_standalone_strings/redis_standlone_strings_test.go +++ b/tests/scalers/redis/redis_standalone_strings/redis_standlone_strings_test.go @@ -21,7 +21,7 @@ import ( var _ = godotenv.Load("../../.env") const ( - testName = "redis-standalone-keyvalue-test" + testName = "redis-standalone-strings-test" ) var ( From 58754d514963cc9bbddfbc2ec0e73f95f5717196 Mon Sep 17 00:00:00 2001 From: wangrushen Date: Mon, 4 Nov 2024 20:45:23 +0800 Subject: [PATCH 4/4] fix: remove unused comment Signed-off-by: wangrushen --- .../redis_sentinel_strings/redis_sentinel_strings_test.go | 4 ---- 1 file changed, 4 deletions(-) diff --git a/tests/scalers/redis/redis_sentinel_strings/redis_sentinel_strings_test.go b/tests/scalers/redis/redis_sentinel_strings/redis_sentinel_strings_test.go index c3f3a88694d..dbb52cdda89 100644 --- a/tests/scalers/redis/redis_sentinel_strings/redis_sentinel_strings_test.go +++ b/tests/scalers/redis/redis_sentinel_strings/redis_sentinel_strings_test.go @@ -209,7 +209,3 @@ func setKeyValue(t *testing.T, value int) { redisPassword, redisHost, redisPassword, redisKey, value)) assert.NoErrorf(t, err, "cannot execute command - %s", err) } - -// kubectl exec -n redis-sentinel-strings-test-redis-ns redis-sentinel-strings-test-client -- ' -// redis-cli --pass admin -h redis-sentinel-strings-test-headless -p 26379 SENTINEL get-master-addr-by-name mymaster -// | xargs -n 2 sh -c 'redis-cli --pass admin -h $0 -p $1 get redis-sentinel-strings-test-key'