Skip to content

Commit

Permalink
Accept sentinels credentials in the URL (#398)
Browse files Browse the repository at this point in the history
(cherry picked from commit 470d6be)
  • Loading branch information
jlledom committed Jul 30, 2024
1 parent a48c695 commit e0a9b07
Show file tree
Hide file tree
Showing 3 changed files with 32 additions and 115 deletions.
46 changes: 20 additions & 26 deletions lib/3scale/backend/storage_helpers.rb
Original file line number Diff line number Diff line change
Expand Up @@ -222,17 +222,24 @@ def cfg_sentinels_handler(options)

sentinels = Splitter.split(sentinels) if sentinels.is_a? String

sentinel_user = nil
sentinel_password = nil
sentinels = sentinels.map do |sentinel|
if sentinel.is_a? Hash
next if sentinel.nil?

if sentinel.respond_to? :strip!
sentinel.strip!
# invalid string if it's empty after stripping
next if sentinel.empty?
sentinel.fetch(:host) do
raise InvalidURI.new("(sentinel #{sentinel.inspect})",
'no host given')
end
sentinel
else
sentinel_to_hash sentinel
end

valid_uri_str = to_redis_uri(sentinel)
# it is safe to perform URI parsing now
uri = URI.parse valid_uri_str

sentinel_user ||= uri.user
sentinel_password ||= uri.password
{ host: uri.host, port: uri.port }
end.compact

return options if sentinels.empty?
Expand All @@ -244,11 +251,15 @@ def cfg_sentinels_handler(options)
# sentinel port
options[:sentinels].each do |sentinel|
sentinel[:port] ||= DEFAULT_SENTINEL_PORT
sentinel.delete(:password) if sentinel[:password].nil? || sentinel[:password].empty?
end

# Handle role option when sentinels are validated
options[:role] = role if role && !role.empty?

# Sentinel credentials
options[:sentinel_username] = sentinel_user unless sentinel_user.to_s.strip.empty?
options[:sentinel_password] = sentinel_password unless sentinel_password.to_s.strip.empty?

options
end

Expand Down Expand Up @@ -285,23 +296,6 @@ def cfg_defaults_handler(options, defaults)
cfg_with_defaults
end

# helper to convert a sentinel object to a Hash
def sentinel_to_hash(sentinel)
return if sentinel.nil?

if sentinel.respond_to? :strip!
sentinel.strip!
# invalid string if it's empty after stripping
return if sentinel.empty?
end

valid_uri_str = to_redis_uri(sentinel)
# it is safe to perform URI parsing now
uri = URI.parse valid_uri_str

{ host: uri.host, port: uri.port, password: uri.password }
end

# split a string by a delimiter character with escaping
module Splitter
def self.split(str, delimiter: ',', escaper: '\\')
Expand Down
35 changes: 1 addition & 34 deletions test/unit/storage_async_test.rb
Original file line number Diff line number Diff line change
Expand Up @@ -68,21 +68,6 @@ def test_sentinels_connection_array_strings
conn)
end

def test_sentinels_connection_array_hashes
config_obj = {
url: 'redis://master-group-name',
sentinels: [{ host: '127.0.0.1', port: 26_379 },
{},
{ host: '127.0.0.1', port: 36_379 },
nil]
}

conn = StorageAsync::Client.send :new, Storage::Helpers.config_with(config_obj)
assert_sentinel_config({ url: config_obj[:url],
sentinels: config_obj[:sentinels].compact.reject(&:empty?) },
conn)
end

def test_sentinels_malformed_url
config_obj = {
url: 'redis://master-group-name',
Expand All @@ -105,24 +90,6 @@ def test_sentinels_simple_url
conn)
end

def test_sentinels_array_hashes_default_port
default_sentinel_port = Storage::Helpers.singleton_class.const_get(:DEFAULT_SENTINEL_PORT)
config_obj = {
url: 'redis://master-group-name',
sentinels: [{ host: '127.0.0.1' }, { host: '192.168.1.1' },
{ host: '192.168.1.2', port: nil },
{ host: '127.0.0.1', port: 36379 }]
}

conn = StorageAsync::Client.send :new, Storage::Helpers.config_with(config_obj)
assert_sentinel_config({ url: config_obj[:url],
sentinels: [{ host: '127.0.0.1', port: default_sentinel_port },
{ host: '192.168.1.1', port: default_sentinel_port },
{ host: '192.168.1.2', port: default_sentinel_port },
{ host: '127.0.0.1', port: 36379 }] },
conn)
end

def test_sentinels_array_strings_default_port
default_sentinel_port = Storage::Helpers.singleton_class.const_get(:DEFAULT_SENTINEL_PORT)
config_obj = {
Expand Down Expand Up @@ -180,7 +147,7 @@ def test_role_empty_when_sentinels_does_not_exist
end

def test_sentinels_empty
[nil, '', ' ', [], [nil], [''], [' '], [{}]].each do |sentinels_val|
[nil, '', ' ', [], [nil], [''], [' ']].each do |sentinels_val|
config_obj = {
url: 'redis://master-group-name',
sentinels: sentinels_val
Expand Down
66 changes: 11 additions & 55 deletions test/unit/storage_sync_test.rb
Original file line number Diff line number Diff line change
Expand Up @@ -72,8 +72,10 @@ def test_sentinels_connection_string_escaped

conn = StorageSync.send :new, Storage::Helpers.config_with(config_obj)
assert_sentinel_config({ url: config_obj[:url],
sentinels: [{ host: '127.0.0.1', port: 26_379, password: 'passw,ord' },
{ host: '127.0.0.1', port: 36_379 }] },
sentinels: [{ host: '127.0.0.1', port: 26_379},
{ host: '127.0.0.1', port: 36_379 }],
sentinel_username: 'user',
sentinel_password: 'passw,ord'},
conn)
end

Expand All @@ -90,21 +92,6 @@ def test_sentinels_connection_array_strings
conn)
end

def test_sentinels_connection_array_hashes
config_obj = {
url: 'redis://master-group-name',
sentinels: [{ host: '127.0.0.1', port: 26_379 },
{},
{ host: '127.0.0.1', port: 36_379 },
nil]
}

conn = StorageSync.send :new, Storage::Helpers.config_with(config_obj)
assert_sentinel_config({ url: config_obj[:url],
sentinels: config_obj[:sentinels].compact.reject(&:empty?) },
conn)
end

def test_sentinels_malformed_url
config_obj = {
url: 'redis://master-group-name',
Expand All @@ -127,24 +114,6 @@ def test_sentinels_simple_url
conn)
end

def test_sentinels_array_hashes_default_port
default_sentinel_port = Storage::Helpers.singleton_class.const_get(:DEFAULT_SENTINEL_PORT)
config_obj = {
url: 'redis://master-group-name',
sentinels: [{ host: '127.0.0.1' }, { host: '192.168.1.1' },
{ host: '192.168.1.2', port: nil },
{ host: '127.0.0.1', port: 36379 }]
}

conn = StorageSync.send :new, Storage::Helpers.config_with(config_obj)
assert_sentinel_config({ url: config_obj[:url],
sentinels: [{ host: '127.0.0.1', port: default_sentinel_port },
{ host: '192.168.1.1', port: default_sentinel_port },
{ host: '192.168.1.2', port: default_sentinel_port },
{ host: '127.0.0.1', port: 36379 }] },
conn)
end

def test_sentinels_array_strings_default_port
default_sentinel_port = Storage::Helpers.singleton_class.const_get(:DEFAULT_SENTINEL_PORT)
config_obj = {
Expand All @@ -164,22 +133,6 @@ def test_sentinels_array_strings_default_port
conn)
end

def test_sentinels_array_hashes_password
config_obj = {
url: 'redis://master-group-name',
sentinels: [{ host: '192.168.1.1', port: 3333, password: 'abc' },
{ host: '192.168.1.2', port: 4444, password: '' },
{ host: '192.168.1.3', port: 5555, password: nil }]
}

conn = StorageSync.send :new, Storage::Helpers.config_with(config_obj)
assert_sentinel_config({ url: config_obj[:url],
sentinels: [{ host: '192.168.1.1', port: 3333, password: 'abc' },
{ host: '192.168.1.2', port: 4444 },
{ host: '192.168.1.3', port: 5555 }] },
conn)
end

def test_sentinels_array_strings_password
config_obj = {
url: 'redis://master-group-name',
Expand All @@ -190,9 +143,10 @@ def test_sentinels_array_strings_password

conn = StorageSync.send :new, Storage::Helpers.config_with(config_obj)
assert_sentinel_config({ url: config_obj[:url],
sentinels: [{ host: '192.168.1.1', port: 3333, password: 'abc' },
sentinels: [{ host: '192.168.1.1', port: 3333 },
{ host: '192.168.1.2', port: 4444 },
{ host: '192.168.1.3', port: 5555 }] },
{ host: '192.168.1.3', port: 5555 }],
sentinel_password: 'abc'},
conn)
end

Expand Down Expand Up @@ -234,7 +188,7 @@ def test_role_empty_when_sentinels_does_not_exist
end

def test_sentinels_empty
[nil, '', ' ', [], [nil], [''], [' '], [{}]].each do |sentinels_val|
[nil, '', ' ', [], [nil], [''], [' ']].each do |sentinels_val|
config_obj = {
url: 'redis://master-group-name',
sentinels: sentinels_val
Expand Down Expand Up @@ -337,8 +291,10 @@ def assert_sentinel_config(conf, client)
conf[:sentinels].each_with_index do |s, i|
assert_equal s[:host], config.sentinels[i].host
assert_equal s[:port], config.sentinels[i].port
assert_equal s[:password], config.sentinels[i].password
end
extra_conf = config.instance_variable_get(:@extra_config)
assert_equal conf[:sentinel_username], extra_conf[:username]
assert_equal conf[:sentinel_password], extra_conf[:password]
end

def url(url)
Expand Down

0 comments on commit e0a9b07

Please sign in to comment.