Skip to content

Commit

Permalink
Update sentinel auth with explicit kwargs (#1221)
Browse files Browse the repository at this point in the history
* updates README with new sentinel auth params

* bump redis-client from >=0.16.0 to >=0.17.0

* update specs to use explicit sentinel credentials

* drops sentinel preparation config

* updates CHANGELOG
  • Loading branch information
moofkit authored Sep 14, 2023
1 parent 01de51a commit 8e9183a
Show file tree
Hide file tree
Showing 6 changed files with 31 additions and 32 deletions.
1 change: 1 addition & 0 deletions CHANGELOG.md
Original file line number Diff line number Diff line change
@@ -1,6 +1,7 @@
# Unreleased

- Fix `Redis#without_reconnect` for sentinel clients. Fix #1212.
- Add `sentinel_username`, `sentinel_password` for sentinel clients. Bump `redis-client` to `>=0.17.0`. See #1213

# 5.0.7

Expand Down
28 changes: 19 additions & 9 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -120,29 +120,39 @@ but a few so that if one is down the client will try the next one. The client
is able to remember the last Sentinel that was able to reply correctly and will
use it for the next requests.

To [authenticate](https://redis.io/docs/management/sentinel/#configuring-sentinel-instances-with-authentication) Sentinel itself, you can specify the `username` and `password` options per instance. Exclude the `username` option if you're using password-only authentication.
To [authenticate](https://redis.io/docs/management/sentinel/#configuring-sentinel-instances-with-authentication) Sentinel itself, you can specify the `sentinel_username` and `sentinel_password`. Exclude the `sentinel_username` option if you're using password-only authentication.

```ruby
SENTINELS = [{ host: '127.0.0.1', port: 26380, username: 'appuser', password: 'mysecret' },
{ host: '127.0.0.1', port: 26381, username: 'appuser', password: 'mysecret' }]
SENTINELS = [{ host: '127.0.0.1', port: 26380},
{ host: '127.0.0.1', port: 26381}]

redis = Redis.new(name: 'mymaster', sentinels: SENTINELS, role: :master)
redis = Redis.new(name: 'mymaster', sentinels: SENTINELS, sentinel_username: 'appuser', sentinel_password: 'mysecret', role: :master)
```

If you specify a username and/or password at the top level for your main Redis instance, Sentinel will default to using those credentials. You can pass nil or override them for each sentinel.
If you specify a username and/or password at the top level for your main Redis instance, Sentinel *will not* using thouse credentials

```ruby
# Use 'mysecret' to authenticate against the mymaster instance, but skip authentication for the sentinels:
SENTINELS = [{ host: '127.0.0.1', port: 26380, password: nil },
{ host: '127.0.0.1', port: 26381, password: nil }]
SENTINELS = [{ host: '127.0.0.1', port: 26380 },
{ host: '127.0.0.1', port: 26381 }]

redis = Redis.new(name: 'mymaster', sentinels: SENTINELS, role: :master, password: 'mysecret')
```

Also the name can be passed as an url:
So you have to provide Sentinel credential and Redis explictly even they are the same

```ruby
redis = Redis.new(name: "redis://mymaster", sentinels: SENTINELS, role: :master)
# Use 'mysecret' to authenticate against the mymaster instance and sentinel
SENTINELS = [{ host: '127.0.0.1', port: 26380 },
{ host: '127.0.0.1', port: 26381 }]

redis = Redis.new(name: 'mymaster', sentinels: SENTINELS, role: :master, password: 'mysecret', sentinel_password: 'mysecret')
```

Also the `name`, `password`, `username` and `db` for Redis instance can be passed as an url:

```ruby
redis = Redis.new(url: "redis://appuser:mysecret@mymaster/10", sentinels: SENTINELS, role: :master)
```

## Cluster support
Expand Down
15 changes: 0 additions & 15 deletions lib/redis.rb
Original file line number Diff line number Diff line change
Expand Up @@ -137,21 +137,6 @@ def initialize_client(options)
end

if options.key?(:sentinels)
if url = options.delete(:url)
uri = URI.parse(url)
if !options.key?(:name) && uri.host
options[:name] = uri.host
end

if !options.key?(:password) && uri.password && !uri.password.empty?
options[:password] = uri.password
end

if !options.key?(:username) && uri.user && !uri.user.empty?
options[:username] = uri.user
end
end

Client.sentinel(**options).new_client
else
Client.config(**options).new_client
Expand Down
2 changes: 1 addition & 1 deletion redis.gemspec
Original file line number Diff line number Diff line change
Expand Up @@ -45,5 +45,5 @@ Gem::Specification.new do |s|

s.required_ruby_version = '>= 2.5.0'

s.add_runtime_dependency('redis-client', '>= 0.16.0')
s.add_runtime_dependency('redis-client', '>= 0.17.0')
end
14 changes: 7 additions & 7 deletions test/sentinel/sentinel_test.rb
Original file line number Diff line number Diff line change
Expand Up @@ -205,7 +205,7 @@ def test_sentinel_with_non_sentinel_options
end
end

assert_equal [%w[auth foo], %w[get-master-addr-by-name master1], ["sentinels", "master1"]], commands[:s1]
assert_equal [%w[get-master-addr-by-name master1], ["sentinels", "master1"]], commands[:s1]
assert_equal [%w[auth foo], %w[role]], commands[:m1]
end

Expand Down Expand Up @@ -252,8 +252,8 @@ def test_authentication_for_sentinel

RedisMock.start(master) do |master_port|
RedisMock.start(sentinel.call(master_port)) do |sen_port|
s = [{ host: '127.0.0.1', port: sen_port, password: 'foo' }]
r = Redis.new(name: 'master1', sentinels: s, role: :master)
s = [{ host: '127.0.0.1', port: sen_port }]
r = Redis.new(name: 'master1', sentinels: s, role: :master, sentinel_password: 'foo')
assert r.ping
end
end
Expand Down Expand Up @@ -308,8 +308,8 @@ def test_authentication_for_sentinel_and_redis

RedisMock.start(master) do |master_port|
RedisMock.start(sentinel.call(master_port)) do |sen_port|
s = [{ host: '127.0.0.1', port: sen_port, password: 'foo' }]
r = Redis.new(name: 'master1', sentinels: s, role: :master, password: 'bar')
s = [{ host: '127.0.0.1', port: sen_port }]
r = Redis.new(name: 'master1', sentinels: s, role: :master, password: 'bar', sentinel_password: 'foo')
assert r.ping
end
end
Expand Down Expand Up @@ -361,8 +361,8 @@ def test_authentication_with_acl

RedisMock.start(master) do |master_port|
RedisMock.start(sentinel.call(master_port)) do |sen_port|
s = [{ host: '127.0.0.1', port: sen_port, username: 'bob', password: 'foo' }]
r = Redis.new(name: 'master1', sentinels: s, role: :master, username: 'alice', password: 'bar')
s = [{ host: '127.0.0.1', port: sen_port }]
r = Redis.new(name: 'master1', sentinels: s, role: :master, username: 'alice', password: 'bar', sentinel_username: 'bob', sentinel_password: 'foo')
assert r.ping
end
end
Expand Down
3 changes: 3 additions & 0 deletions test/support/conf/redis-7.2.conf
Original file line number Diff line number Diff line change
@@ -0,0 +1,3 @@
appendonly no
save ""
enable-debug-command yes

0 comments on commit 8e9183a

Please sign in to comment.