diff --git a/pkg/config/config.go b/pkg/config/config.go index c22496f..38f5056 100644 --- a/pkg/config/config.go +++ b/pkg/config/config.go @@ -44,6 +44,7 @@ type Common struct { type Redis struct { // Deprecated: Address is deprecated: use Addresses + // If Addresses set, Address will be ignored Address string `yaml:"address"` Addresses []string `yaml:"addresses"` Sentinel RedisSentinel `yaml:"sentinel"` @@ -68,15 +69,22 @@ type TLS struct { } func (r *Redis) validate() error { - if r.Address != "" && len(r.Addresses) != 0 { - return fmt.Errorf("invalid redis config: either address or addresses must be used, but not both") - } - if r.Address == "" && len(r.Addresses) == 0 { + if len(r.GetAddresses()) == 0 { return fmt.Errorf("invalid redis config: address is not set") } return nil } +func (r *Redis) GetAddresses() []string { + if len(r.Addresses) != 0 { + return r.Addresses + } + if r.Address != "" { + return []string{r.Address} + } + return nil +} + func Get(conf any, sources ...Src) error { data, err := configFile.Open("config.yaml") if err != nil { diff --git a/pkg/config/config.yaml b/pkg/config/config.yaml index 1698d83..3145a4e 100644 --- a/pkg/config/config.yaml +++ b/pkg/config/config.yaml @@ -9,8 +9,11 @@ trace: endpoint: # url to Jaeger or other open trace provider redis: # redis master address for standalone installation + # will be ignored if addresses is set. + # This fiel is deprecated. Use addresses instead. address: "127.0.0.1:6379" - # list of redis addresses for HA (cluster or sentinel) setup + # List of redis addresses for HA (cluster or sentinel) setup. + # For standalone redis setup add a single address to the list. addresses: [] user: password: diff --git a/pkg/config/config_test.go b/pkg/config/config_test.go index a8105bb..6a72ba5 100644 --- a/pkg/config/config_test.go +++ b/pkg/config/config_test.go @@ -1,6 +1,7 @@ package config import ( + "reflect" "testing" "github.com/clyso/chorus/pkg/s3" @@ -27,9 +28,16 @@ func TestOverride(t *testing.T) { r.EqualValues(69, conf.Metrics.Port) r.EqualValues("info", conf.Log.Level) r.EqualValues(true, conf.Log.Json) - r.Empty(conf.Redis.Password) r.NotEmpty(conf.Redis.Address) + r.EqualValues("user", conf.Redis.User) + r.EqualValues("pass", conf.Redis.Password) + r.EqualValues("sentinel", conf.Redis.Sentinel.User) + r.EqualValues("sentinel-pass", conf.Redis.Sentinel.Password) + r.EqualValues("master", conf.Redis.Sentinel.MasterName) + r.True(conf.Redis.TLS.Enabled) + r.True(conf.Redis.TLS.Insecure) + } func TestOverride2(t *testing.T) { @@ -42,13 +50,15 @@ func TestOverride2(t *testing.T) { r.EqualValues(420, conf.Metrics.Port) r.EqualValues("info", conf.Log.Level) r.EqualValues(true, conf.Log.Json) - r.Empty(conf.Redis.Password) r.NotEmpty(conf.Redis.Address) + r.Empty(conf.Redis.Addresses) + r.EqualValues([]string{conf.Redis.Address}, conf.Redis.GetAddresses()) } func TestOverrideEnv(t *testing.T) { t.Setenv("CFG_METRICS_PORT", "55") t.Setenv("CFG_REDIS_PASSWORD", "secret") + t.Setenv("CFG_REDIS_ADDRESSES", "a,b,c") r := require.New(t) var conf Common @@ -60,6 +70,8 @@ func TestOverrideEnv(t *testing.T) { r.EqualValues(true, conf.Log.Json) r.EqualValues("secret", conf.Redis.Password) r.NotEmpty(conf.Redis.Address) + r.EqualValues([]string{"a", "b", "c"}, conf.Redis.Addresses, "redis addresses set from env") + r.EqualValues([]string{"a", "b", "c"}, conf.Redis.GetAddresses(), "address is ignored") } func TestStorageConfig_RateLimitConf(t *testing.T) { @@ -127,12 +139,12 @@ func TestRedis_validate(t *testing.T) { wantErr: true, }, { - name: "invalid: both addresses set", + name: "valid: both addresses set", fields: fields{ Address: "addr", Addresses: []string{"addr"}, }, - wantErr: true, + wantErr: false, }, { name: "valid: only address set", @@ -177,3 +189,56 @@ func TestRedis_validate(t *testing.T) { }) } } + +func TestRedis_GetAddresses(t *testing.T) { + type fields struct { + Address string + Addresses []string + } + tests := []struct { + name string + fields fields + want []string + }{ + { + name: "only address is set", + fields: fields{ + Address: "a", + Addresses: []string{}, + }, + want: []string{"a"}, + }, + { + name: "only addresses are set", + fields: fields{ + Address: "", + Addresses: []string{"a", "b"}, + }, + want: []string{"a", "b"}, + }, + { + name: "address is ignored when addresses set", + fields: fields{ + Address: "a", + Addresses: []string{"b", "c"}, + }, + want: []string{"b", "c"}, + }, + { + name: "nothing is set", + fields: fields{}, + want: nil, + }, + } + for _, tt := range tests { + t.Run(tt.name, func(t *testing.T) { + r := &Redis{ + Address: tt.fields.Address, + Addresses: tt.fields.Addresses, + } + if got := r.GetAddresses(); !reflect.DeepEqual(got, tt.want) { + t.Errorf("Redis.GetAddresses() = %v, want %v", got, tt.want) + } + }) + } +} diff --git a/pkg/config/override_test.yaml b/pkg/config/override_test.yaml index e332989..cf6d99a 100644 --- a/pkg/config/override_test.yaml +++ b/pkg/config/override_test.yaml @@ -1,4 +1,15 @@ log: json: true metrics: - port: 69 \ No newline at end of file + port: 69 +redis: + user: user + password: pass + tls: + enabled: true + insecure: true + sentinel: + masterName: master + user: sentinel + password: sentinel-pass + diff --git a/pkg/util/redis.go b/pkg/util/redis.go index ff78d73..a47c2ee 100644 --- a/pkg/util/redis.go +++ b/pkg/util/redis.go @@ -9,11 +9,8 @@ import ( ) func NewRedis(conf *config.Redis, db int) redis.UniversalClient { - if conf.Address != "" { - conf.Addresses = append(conf.Addresses, conf.Address) - } opt := &redis.UniversalOptions{ - Addrs: conf.Addresses, + Addrs: conf.GetAddresses(), DB: db, Username: conf.User, Password: conf.Password, @@ -28,12 +25,10 @@ func NewRedis(conf *config.Redis, db int) redis.UniversalClient { } func NewRedisAsynq(conf *config.Redis, db int) asynq.RedisConnOpt { - if conf.Address != "" { - conf.Addresses = append(conf.Addresses, conf.Address) - } - if len(conf.Addresses) == 1 { + addresses := conf.GetAddresses() + if len(addresses) == 1 { // Standalone - opt := asynq.RedisClientOpt{Addr: conf.Addresses[0], Username: conf.User, Password: conf.Password, DB: db} + opt := asynq.RedisClientOpt{Addr: addresses[0], Username: conf.User, Password: conf.Password, DB: db} if conf.TLS.Enabled { opt.TLSConfig = &tls.Config{InsecureSkipVerify: conf.TLS.Insecure} } @@ -44,7 +39,7 @@ func NewRedisAsynq(conf *config.Redis, db int) asynq.RedisConnOpt { // Sentinel opt := asynq.RedisFailoverClientOpt{ MasterName: conf.Sentinel.MasterName, - SentinelAddrs: conf.Addresses, + SentinelAddrs: addresses, SentinelPassword: conf.Sentinel.Password, Username: conf.User, Password: conf.Password, @@ -57,7 +52,7 @@ func NewRedisAsynq(conf *config.Redis, db int) asynq.RedisConnOpt { } // Cluster opt := asynq.RedisClusterClientOpt{ - Addrs: conf.Addresses, + Addrs: addresses, Username: conf.User, Password: conf.Password, }