Skip to content

Commit

Permalink
Merge pull request #407 from jlledom/THREESCALE-10826-async-unix-path
Browse files Browse the repository at this point in the history
THREESCALE-10826: Add support for unix sockets in async mode
  • Loading branch information
jlledom authored Oct 30, 2024

Verified

This commit was created on GitHub.com and signed with GitHub’s verified signature. The key has expired.
2 parents d43efbd + 9c45561 commit 57c5a2d
Showing 7 changed files with 117 additions and 19 deletions.
35 changes: 35 additions & 0 deletions .circleci/config.yml
Original file line number Diff line number Diff line change
@@ -49,6 +49,7 @@ commands:
cp -r script/config/examples/tls/sentinel1 ./sentinel1_tls
cp -r script/config/examples/tls/sentinel2 ./sentinel2_tls
cp -r script/config/examples/tls/sentinel3 ./sentinel3_tls
mkdir -m 1777 ./run
- run:
name: Start services
command: |
@@ -119,9 +120,15 @@ workflows:
- test_single:
requires:
- install_dependencies
- test_single_unix:
requires:
- install_dependencies
- test_sentinels:
requires:
- install_dependencies
- test_acl_unix:
requires:
- install_dependencies
- test_tls:
requires:
- install_dependencies
@@ -161,6 +168,18 @@ jobs:
- start_services:
services: redis-master
- run_tests
test_single_unix:
executor:
name: ubuntu_vm
working_directory: ~/project
environment:
CONFIG_QUEUES_MASTER_NAME: unix://run/redis.sock
CONFIG_REDIS_PROXY: unix://run/redis.sock
steps:
- *attach-to-workspace
- start_services:
services: redis-master
- run_tests
test_sentinels:
executor:
name: ubuntu_vm
@@ -175,6 +194,22 @@ jobs:
- start_services:
services: redis-master redis-replica1 redis-replica2 redis-sentinel1 redis-sentinel2 redis-sentinel3
- run_tests
test_acl_unix:
executor:
name: ubuntu_vm
working_directory: ~/project
environment:
CONFIG_QUEUES_MASTER_NAME: unix://run/redis.sock
CONFIG_QUEUES_USERNAME: porta
CONFIG_QUEUES_PASSWORD: sup3rS3cre1!
CONFIG_REDIS_PROXY: unix://run/redis.sock
CONFIG_REDIS_USERNAME: porta
CONFIG_REDIS_PASSWORD: sup3rS3cre1!
steps:
- *attach-to-workspace
- start_services:
services: tls-redis-master
- run_tests
test_tls:
executor:
name: ubuntu_vm
30 changes: 28 additions & 2 deletions lib/3scale/backend/async_redis/client.rb
Original file line number Diff line number Diff line change
@@ -16,6 +16,19 @@ class << self
# @param opts [Hash] Redis connection options
# @return [Async::Redis::Client]
def call(opts)
return connect_tcp(opts) if url_present?(opts[:url])

connect_unix(opts)
end
alias :connect :call

private

def url_present?(url)
!url.to_s.strip.empty?
end

def connect_tcp(opts)
uri = URI(opts[:url])

credentials = [ uri.user || opts[:username], uri.password || opts[:password]]
@@ -28,11 +41,24 @@ def call(opts)
else
host = uri.host || EndpointHelpers::DEFAULT_HOST
port = uri.port || EndpointHelpers::DEFAULT_PORT
endpoint = EndpointHelpers.prepare_endpoint(host, port, opts[:ssl], opts[:ssl_params])
endpoint = EndpointHelpers.prepare_endpoint(host: host, port: port, ssl: opts[:ssl], ssl_params: opts[:ssl_params])
Async::Redis::Client.new(endpoint, protocol: protocol, limit: opts[:max_connections])
end
end

def connect_unix(opts)
path = opts[:path]

credentials = [opts[:username], opts[:password]]
protocol = Protocol::ExtendedRESP2.new(credentials: credentials)

if opts.key? :sentinels
raise InvalidURI.new(path, 'unix paths are not supported for sentinels')
else
endpoint = EndpointHelpers.prepare_endpoint(path: path, ssl: opts[:ssl], ssl_params: opts[:ssl_params])
Async::Redis::Client.new(endpoint, protocol: protocol, limit: opts[:max_connections])
end
end
alias :connect :call
end
end
end
34 changes: 28 additions & 6 deletions lib/3scale/backend/async_redis/endpoint_helpers.rb
Original file line number Diff line number Diff line change
@@ -1,6 +1,7 @@
# frozen_string_literal: true

require 'async/io'
require 'async/io/unix_endpoint'

module ThreeScale
module Backend
@@ -14,20 +15,37 @@ class << self

# @param host [String]
# @param port [Integer]
# @param path [String]
# @param ssl [Boolean]
# @param ssl_params [Hash]
# @return [Async::IO::Endpoint::Generic]
def prepare_endpoint(host, port, ssl = false, ssl_params = nil)
def prepare_endpoint(**kwargs)
host_present?(kwargs[:host]) ? prepare_tcp_endpoint(**kwargs) : prepare_unix_endpoint(**kwargs)
end

private

def prepare_tcp_endpoint(host: nil, port: nil, ssl: false, ssl_params: nil)
tcp_endpoint = Async::IO::Endpoint.tcp(host, port)

if ssl
ssl_context = OpenSSL::SSL::SSLContext.new
ssl_context.set_params(format_ssl_params(ssl_params)) if ssl_params
return Async::IO::SSLEndpoint.new(tcp_endpoint, ssl_context: ssl_context)
end
return prepare_ssl_endpoint(endpoint: tcp_endpoint, ssl_params: ssl_params) if ssl

tcp_endpoint
end

def prepare_unix_endpoint(path: '', ssl: false, ssl_params: nil)
unix_endpoint = Async::IO::Endpoint.unix(path, Socket::PF_UNIX)
return unix_endpoint unless ssl

prepare_ssl_endpoint(endpoint: unix_endpoint, ssl_params: ssl_params)
end

def prepare_ssl_endpoint(endpoint: nil, ssl_params: nil)
ssl_context = OpenSSL::SSL::SSLContext.new
ssl_context.set_params(format_ssl_params(ssl_params)) if ssl_params
Async::IO::SSLEndpoint.new(endpoint, ssl_context: ssl_context)
end

def format_ssl_params(ssl_params)
cert = ssl_params[:cert].to_s.strip
key = ssl_params[:key].to_s.strip
@@ -39,6 +57,10 @@ def format_ssl_params(ssl_params)

updated_ssl_params
end

def host_present?(host)
!host.to_s.strip.empty?
end
end
end
end
6 changes: 3 additions & 3 deletions lib/3scale/backend/async_redis/sentinels_client_acl_tls.rb
Original file line number Diff line number Diff line change
@@ -10,7 +10,7 @@ class SentinelsClientACLTLS < Async::Redis::SentinelsClient
def initialize(uri, protocol = Async::Redis::Protocol::RESP2, config, **options)
@master_name = uri.host
@sentinel_endpoints = config[:sentinels].map do |sentinel|
EndpointHelpers.prepare_endpoint(sentinel[:host], sentinel[:port], config[:ssl], config[:ssl_params])
EndpointHelpers.prepare_endpoint(host: sentinel[:host], port: sentinel[:port], ssl: config[:ssl], ssl_params: config[:ssl_params])
end
@role = config[:role] || :master

@@ -32,7 +32,7 @@ def resolve_master
next
end

return EndpointHelpers.prepare_endpoint(address[0], address[1], @config[:ssl], @config[:ssl_params]) if address
return EndpointHelpers.prepare_endpoint(host: address[0], port: address[1], ssl:@config[:ssl], ssl_params: @config[:ssl_params]) if address
end

nil
@@ -52,7 +52,7 @@ def resolve_slave
next if slaves.empty?

slave = select_slave(slaves)
return EndpointHelpers.prepare_endpoint(slave['ip'], slave['port'], @config[:ssl], @config[:ssl_params])
return EndpointHelpers.prepare_endpoint(host: slave['ip'], port: slave['port'], ssl: @config[:ssl], ssl_params: @config[:ssl_params])
end

nil
2 changes: 2 additions & 0 deletions script/config/examples/tls/master.conf
Original file line number Diff line number Diff line change
@@ -1,4 +1,6 @@
port 0
unixsocket /var/run/redis/redis.sock
unixsocketperm 777
tls-port 46380
tls-cert-file /etc/redis.crt
tls-key-file /etc/redis.key
5 changes: 4 additions & 1 deletion script/config/podman-compose.yml
Original file line number Diff line number Diff line change
@@ -4,7 +4,9 @@ services:
image: redis:6.2-alpine
container_name: redis-master
network_mode: host
command: [ redis-server, --port, "6379" ]
volumes:
- ./run:/var/run/redis:z
command: [ redis-server, --port, "6379", --unixsocket, "/var/run/redis/redis.sock", --unixsocketperm, "777" ]

redis-replica1:
image: redis:6.2-alpine
@@ -47,6 +49,7 @@ services:
container_name: tls-redis-master
network_mode: host
volumes:
- ./run:/var/run/redis:z
- ./master.conf:/etc/redis.conf:z
- ./circleci.crt:/etc/redis.crt:z
- ./circleci.key:/etc/redis.key:z
24 changes: 17 additions & 7 deletions test/unit/storage_async_test.rb
Original file line number Diff line number Diff line change
@@ -25,6 +25,12 @@ def test_redis_url
assert_client_config(config_obj, storage)
end

def test_redis_unix
config_obj = url('unix:///tmp/redis_unix.6379.sock')
storage = StorageAsync::Client.send :new, config_obj
assert_client_config(config_obj, storage)
end

def test_redis_protected_url
assert_nothing_raised do
StorageAsync::Client.send :new, url('redis://user:[email protected]:6379/0')
@@ -303,13 +309,17 @@ def create_certs(alg)
def assert_client_config(conf, conn, test_cert_type = nil)
client = conn.instance_variable_get(:@inner).instance_variable_get(:@redis_async)

url = URI(conf[:url])
host, port = client.endpoint.address
assert_equal url.host, host
assert_equal url.port, port

db = client.protocol.instance_variable_get(:@db)
assert_equal conf[:db], db
if conf[:url].to_s.strip.empty?
path = conf[:path]
assert_equal path, client.endpoint.path
else
url = URI(conf[:url])
host, port = client.endpoint.address
assert_equal url.host, host
assert_equal url.port, port
db = client.protocol.instance_variable_get(:@db)
assert_equal conf[:db], db
end

assert_acl_credentials(conf, client)
assert_tls_certs(conf, client, test_cert_type)

0 comments on commit 57c5a2d

Please sign in to comment.