Commit b087dd1d authored by Yossi Gottlieb's avatar Yossi Gottlieb
Browse files

TLS: Connections refactoring and TLS support.

* Introduce a connection abstraction layer for all socket operations and
integrate it across the code base.
* Provide an optional TLS connections implementation based on OpenSSL.
* Pull a newer version of hiredis with TLS support.
* Tests, redis-cli updates for TLS support.
parent f4d37173
...@@ -4,6 +4,7 @@ ...@@ -4,6 +4,7 @@
# are preseved across iterations. # are preseved across iterations.
source "../tests/includes/init-tests.tcl" source "../tests/includes/init-tests.tcl"
source "../../../tests/support/cli.tcl"
test "Create a 5 nodes cluster" { test "Create a 5 nodes cluster" {
create_cluster 5 5 create_cluster 5 5
...@@ -79,6 +80,7 @@ test "Cluster consistency during live resharding" { ...@@ -79,6 +80,7 @@ test "Cluster consistency during live resharding" {
--cluster-to $target \ --cluster-to $target \
--cluster-slots 100 \ --cluster-slots 100 \
--cluster-yes \ --cluster-yes \
{*}[rediscli_tls_config "../../../tests"] \
| [info nameofexecutable] \ | [info nameofexecutable] \
../tests/helpers/onlydots.tcl \ ../tests/helpers/onlydots.tcl \
&] 0] &] 0]
......
...@@ -5,6 +5,7 @@ ...@@ -5,6 +5,7 @@
# other masters have slaves. # other masters have slaves.
source "../tests/includes/init-tests.tcl" source "../tests/includes/init-tests.tcl"
source "../../../tests/support/cli.tcl"
# Create a cluster with 5 master and 15 slaves, to make sure there are no # Create a cluster with 5 master and 15 slaves, to make sure there are no
# empty masters and make rebalancing simpler to handle during the test. # empty masters and make rebalancing simpler to handle during the test.
...@@ -33,7 +34,9 @@ test "Resharding all the master #0 slots away from it" { ...@@ -33,7 +34,9 @@ test "Resharding all the master #0 slots away from it" {
set output [exec \ set output [exec \
../../../src/redis-cli --cluster rebalance \ ../../../src/redis-cli --cluster rebalance \
127.0.0.1:[get_instance_attrib redis 0 port] \ 127.0.0.1:[get_instance_attrib redis 0 port] \
{*}[rediscli_tls_config "../../../tests"] \
--cluster-weight ${master0_id}=0 >@ stdout ] --cluster-weight ${master0_id}=0 >@ stdout ]
} }
test "Master #0 should lose its replicas" { test "Master #0 should lose its replicas" {
...@@ -51,6 +54,7 @@ test "Resharding back some slot to master #0" { ...@@ -51,6 +54,7 @@ test "Resharding back some slot to master #0" {
set output [exec \ set output [exec \
../../../src/redis-cli --cluster rebalance \ ../../../src/redis-cli --cluster rebalance \
127.0.0.1:[get_instance_attrib redis 0 port] \ 127.0.0.1:[get_instance_attrib redis 0 port] \
{*}[rediscli_tls_config "../../../tests"] \
--cluster-weight ${master0_id}=.01 \ --cluster-weight ${master0_id}=.01 \
--cluster-use-empty-masters >@ stdout] --cluster-use-empty-masters >@ stdout]
} }
......
source tests/support/redis.tcl source tests/support/redis.tcl
source tests/support/util.tcl source tests/support/util.tcl
set ::tlsdir "tests/tls"
# This function sometimes writes sometimes blocking-reads from lists/sorted # This function sometimes writes sometimes blocking-reads from lists/sorted
# sets. There are multiple processes like this executing at the same time # sets. There are multiple processes like this executing at the same time
# so that we have some chance to trap some corner condition if there is # so that we have some chance to trap some corner condition if there is
...@@ -8,8 +10,8 @@ source tests/support/util.tcl ...@@ -8,8 +10,8 @@ source tests/support/util.tcl
# space to just a few elements, and balance the operations so that it is # space to just a few elements, and balance the operations so that it is
# unlikely that lists and zsets just get more data without ever causing # unlikely that lists and zsets just get more data without ever causing
# blocking. # blocking.
proc bg_block_op {host port db ops} { proc bg_block_op {host port db ops tls} {
set r [redis $host $port] set r [redis $host $port 0 $tls]
$r select $db $r select $db
for {set j 0} {$j < $ops} {incr j} { for {set j 0} {$j < $ops} {incr j} {
...@@ -49,4 +51,4 @@ proc bg_block_op {host port db ops} { ...@@ -49,4 +51,4 @@ proc bg_block_op {host port db ops} {
} }
} }
bg_block_op [lindex $argv 0] [lindex $argv 1] [lindex $argv 2] [lindex $argv 3] bg_block_op [lindex $argv 0] [lindex $argv 1] [lindex $argv 2] [lindex $argv 3] [lindex $argv 4]
source tests/support/redis.tcl source tests/support/redis.tcl
source tests/support/util.tcl source tests/support/util.tcl
proc bg_complex_data {host port db ops} { set ::tlsdir "tests/tls"
set r [redis $host $port]
proc bg_complex_data {host port db ops tls} {
set r [redis $host $port 0 $tls]
$r select $db $r select $db
createComplexDataset $r $ops createComplexDataset $r $ops
} }
bg_complex_data [lindex $argv 0] [lindex $argv 1] [lindex $argv 2] [lindex $argv 3] bg_complex_data [lindex $argv 0] [lindex $argv 1] [lindex $argv 2] [lindex $argv 3] [lindex $argv 4]
source tests/support/redis.tcl source tests/support/redis.tcl
proc gen_write_load {host port seconds} { set ::tlsdir "tests/tls"
proc gen_write_load {host port seconds tls} {
set start_time [clock seconds] set start_time [clock seconds]
set r [redis $host $port 1] set r [redis $host $port 0 $tls]
$r select 9 $r select 9
while 1 { while 1 {
$r set [expr rand()] [expr rand()] $r set [expr rand()] [expr rand()]
...@@ -12,4 +14,4 @@ proc gen_write_load {host port seconds} { ...@@ -12,4 +14,4 @@ proc gen_write_load {host port seconds} {
} }
} }
gen_write_load [lindex $argv 0] [lindex $argv 1] [lindex $argv 2] gen_write_load [lindex $argv 0] [lindex $argv 1] [lindex $argv 2] [lindex $argv 3]
...@@ -17,6 +17,7 @@ source ../support/test.tcl ...@@ -17,6 +17,7 @@ source ../support/test.tcl
set ::verbose 0 set ::verbose 0
set ::valgrind 0 set ::valgrind 0
set ::tls 0
set ::pause_on_error 0 set ::pause_on_error 0
set ::simulate_error 0 set ::simulate_error 0
set ::failed 0 set ::failed 0
...@@ -69,7 +70,19 @@ proc spawn_instance {type base_port count {conf {}}} { ...@@ -69,7 +70,19 @@ proc spawn_instance {type base_port count {conf {}}} {
# Write the instance config file. # Write the instance config file.
set cfgfile [file join $dirname $type.conf] set cfgfile [file join $dirname $type.conf]
set cfg [open $cfgfile w] set cfg [open $cfgfile w]
puts $cfg "port $port" if {$::tls} {
puts $cfg "tls-port $port"
puts $cfg "tls-replication yes"
puts $cfg "tls-cluster yes"
puts $cfg "port 0"
puts $cfg [format "tls-cert-file %s/../../tls/redis.crt" [pwd]]
puts $cfg [format "tls-key-file %s/../../tls/redis.key" [pwd]]
puts $cfg [format "tls-dh-params-file %s/../../tls/redis.dh" [pwd]]
puts $cfg [format "tls-ca-cert-file %s/../../tls/ca.crt" [pwd]]
puts $cfg "loglevel debug"
} else {
puts $cfg "port $port"
}
puts $cfg "dir ./$dirname" puts $cfg "dir ./$dirname"
puts $cfg "logfile log.txt" puts $cfg "logfile log.txt"
# Add additional config files # Add additional config files
...@@ -88,7 +101,7 @@ proc spawn_instance {type base_port count {conf {}}} { ...@@ -88,7 +101,7 @@ proc spawn_instance {type base_port count {conf {}}} {
} }
# Push the instance into the right list # Push the instance into the right list
set link [redis 127.0.0.1 $port] set link [redis 127.0.0.1 $port 0 $::tls]
$link reconnect 1 $link reconnect 1
lappend ::${type}_instances [list \ lappend ::${type}_instances [list \
pid $pid \ pid $pid \
...@@ -148,6 +161,13 @@ proc parse_options {} { ...@@ -148,6 +161,13 @@ proc parse_options {} {
set ::simulate_error 1 set ::simulate_error 1
} elseif {$opt eq {--valgrind}} { } elseif {$opt eq {--valgrind}} {
set ::valgrind 1 set ::valgrind 1
} elseif {$opt eq {--tls}} {
package require tls 1.6
::tls::init \
-cafile "$::tlsdir/ca.crt" \
-certfile "$::tlsdir/redis.crt" \
-keyfile "$::tlsdir/redis.key"
set ::tls 1
} elseif {$opt eq "--help"} { } elseif {$opt eq "--help"} {
puts "Hello, I'm sentinel.tcl and I run Sentinel unit tests." puts "Hello, I'm sentinel.tcl and I run Sentinel unit tests."
puts "\nOptions:" puts "\nOptions:"
...@@ -492,7 +512,7 @@ proc restart_instance {type id} { ...@@ -492,7 +512,7 @@ proc restart_instance {type id} {
} }
# Connect with it with a fresh link # Connect with it with a fresh link
set link [redis 127.0.0.1 $port] set link [redis 127.0.0.1 $port 0 $::tls]
$link reconnect 1 $link reconnect 1
set_instance_attrib $type $id link $link set_instance_attrib $type $id link $link
......
...@@ -13,8 +13,9 @@ tags {"aof"} { ...@@ -13,8 +13,9 @@ tags {"aof"} {
# cleaned after a child responsible for an AOF rewrite exited. This buffer # cleaned after a child responsible for an AOF rewrite exited. This buffer
# was subsequently appended to the new AOF, resulting in duplicate commands. # was subsequently appended to the new AOF, resulting in duplicate commands.
start_server_aof [list dir $server_path] { start_server_aof [list dir $server_path] {
set client [redis [srv host] [srv port]] set client [redis [srv host] [srv port] 0 $::tls]
set bench [open "|src/redis-benchmark -q -p [srv port] -c 20 -n 20000 incr foo" "r+"] set bench [open "|src/redis-benchmark -q -s [srv unixsocket] -c 20 -n 20000 incr foo" "r+"]
after 100 after 100
# Benchmark should be running by now: start background rewrite # Benchmark should be running by now: start background rewrite
...@@ -29,7 +30,7 @@ tags {"aof"} { ...@@ -29,7 +30,7 @@ tags {"aof"} {
# Restart server to replay AOF # Restart server to replay AOF
start_server_aof [list dir $server_path] { start_server_aof [list dir $server_path] {
set client [redis [srv host] [srv port]] set client [redis [srv host] [srv port] 0 $::tls]
assert_equal 20000 [$client get foo] assert_equal 20000 [$client get foo]
} }
} }
...@@ -52,7 +52,7 @@ tags {"aof"} { ...@@ -52,7 +52,7 @@ tags {"aof"} {
assert_equal 1 [is_alive $srv] assert_equal 1 [is_alive $srv]
} }
set client [redis [dict get $srv host] [dict get $srv port]] set client [redis [dict get $srv host] [dict get $srv port] 0 $::tls]
test "Truncated AOF loaded: we expect foo to be equal to 5" { test "Truncated AOF loaded: we expect foo to be equal to 5" {
assert {[$client get foo] eq "5"} assert {[$client get foo] eq "5"}
...@@ -69,7 +69,7 @@ tags {"aof"} { ...@@ -69,7 +69,7 @@ tags {"aof"} {
assert_equal 1 [is_alive $srv] assert_equal 1 [is_alive $srv]
} }
set client [redis [dict get $srv host] [dict get $srv port]] set client [redis [dict get $srv host] [dict get $srv port] 0 $::tls]
test "Truncated AOF loaded: we expect foo to be equal to 6 now" { test "Truncated AOF loaded: we expect foo to be equal to 6 now" {
assert {[$client get foo] eq "6"} assert {[$client get foo] eq "6"}
...@@ -170,7 +170,7 @@ tags {"aof"} { ...@@ -170,7 +170,7 @@ tags {"aof"} {
} }
test "Fixed AOF: Keyspace should contain values that were parseable" { test "Fixed AOF: Keyspace should contain values that were parseable" {
set client [redis [dict get $srv host] [dict get $srv port]] set client [redis [dict get $srv host] [dict get $srv port] 0 $::tls]
wait_for_condition 50 100 { wait_for_condition 50 100 {
[catch {$client ping} e] == 0 [catch {$client ping} e] == 0
} else { } else {
...@@ -194,7 +194,7 @@ tags {"aof"} { ...@@ -194,7 +194,7 @@ tags {"aof"} {
} }
test "AOF+SPOP: Set should have 1 member" { test "AOF+SPOP: Set should have 1 member" {
set client [redis [dict get $srv host] [dict get $srv port]] set client [redis [dict get $srv host] [dict get $srv port] 0 $::tls]
wait_for_condition 50 100 { wait_for_condition 50 100 {
[catch {$client ping} e] == 0 [catch {$client ping} e] == 0
} else { } else {
...@@ -218,7 +218,7 @@ tags {"aof"} { ...@@ -218,7 +218,7 @@ tags {"aof"} {
} }
test "AOF+SPOP: Set should have 1 member" { test "AOF+SPOP: Set should have 1 member" {
set client [redis [dict get $srv host] [dict get $srv port]] set client [redis [dict get $srv host] [dict get $srv port] 0 $::tls]
wait_for_condition 50 100 { wait_for_condition 50 100 {
[catch {$client ping} e] == 0 [catch {$client ping} e] == 0
} else { } else {
...@@ -241,7 +241,7 @@ tags {"aof"} { ...@@ -241,7 +241,7 @@ tags {"aof"} {
} }
test "AOF+EXPIRE: List should be empty" { test "AOF+EXPIRE: List should be empty" {
set client [redis [dict get $srv host] [dict get $srv port]] set client [redis [dict get $srv host] [dict get $srv port] 0 $::tls]
wait_for_condition 50 100 { wait_for_condition 50 100 {
[catch {$client ping} e] == 0 [catch {$client ping} e] == 0
} else { } else {
......
...@@ -2,9 +2,9 @@ ...@@ -2,9 +2,9 @@
# Unlike stream operations such operations are "pop" style, so they consume # Unlike stream operations such operations are "pop" style, so they consume
# the list or sorted set, and must be replicated correctly. # the list or sorted set, and must be replicated correctly.
proc start_bg_block_op {host port db ops} { proc start_bg_block_op {host port db ops tls} {
set tclsh [info nameofexecutable] set tclsh [info nameofexecutable]
exec $tclsh tests/helpers/bg_block_op.tcl $host $port $db $ops & exec $tclsh tests/helpers/bg_block_op.tcl $host $port $db $ops $tls &
} }
proc stop_bg_block_op {handle} { proc stop_bg_block_op {handle} {
...@@ -18,9 +18,9 @@ start_server {tags {"repl"}} { ...@@ -18,9 +18,9 @@ start_server {tags {"repl"}} {
set master_port [srv -1 port] set master_port [srv -1 port]
set slave [srv 0 client] set slave [srv 0 client]
set load_handle0 [start_bg_block_op $master_host $master_port 9 100000] set load_handle0 [start_bg_block_op $master_host $master_port 9 100000 $::tls]
set load_handle1 [start_bg_block_op $master_host $master_port 9 100000] set load_handle1 [start_bg_block_op $master_host $master_port 9 100000 $::tls]
set load_handle2 [start_bg_block_op $master_host $master_port 9 100000] set load_handle2 [start_bg_block_op $master_host $master_port 9 100000 $::tls]
test {First server should have role slave after SLAVEOF} { test {First server should have role slave after SLAVEOF} {
$slave slaveof $master_host $master_port $slave slaveof $master_host $master_port
......
...@@ -18,6 +18,7 @@ start_server {} { ...@@ -18,6 +18,7 @@ start_server {} {
set R($j) [srv [expr 0-$j] client] set R($j) [srv [expr 0-$j] client]
set R_host($j) [srv [expr 0-$j] host] set R_host($j) [srv [expr 0-$j] host]
set R_port($j) [srv [expr 0-$j] port] set R_port($j) [srv [expr 0-$j] port]
set R_unixsocket($j) [srv [expr 0-$j] unixsocket]
if {$debug_msg} {puts "Log file: [srv [expr 0-$j] stdout]"} if {$debug_msg} {puts "Log file: [srv [expr 0-$j] stdout]"}
} }
...@@ -36,7 +37,7 @@ start_server {} { ...@@ -36,7 +37,7 @@ start_server {} {
} }
set cycle_start_time [clock milliseconds] set cycle_start_time [clock milliseconds]
set bench_pid [exec src/redis-benchmark -p $R_port(0) -n 10000000 -r 1000 incr __rand_int__ > /dev/null &] set bench_pid [exec src/redis-benchmark -s $R_unixsocket(0) -n 10000000 -r 1000 incr __rand_int__ > /dev/null &]
while 1 { while 1 {
set elapsed [expr {[clock milliseconds]-$cycle_start_time}] set elapsed [expr {[clock milliseconds]-$cycle_start_time}]
if {$elapsed > $duration*1000} break if {$elapsed > $duration*1000} break
......
source tests/support/cli.tcl
start_server {tags {"cli"}} { start_server {tags {"cli"}} {
proc open_cli {} { proc open_cli {} {
set ::env(TERM) dumb set ::env(TERM) dumb
set fd [open [format "|src/redis-cli -p %d -n 9" [srv port]] "r+"] set cmdline [rediscli [srv port] "-n 9"]
set fd [open "|$cmdline" "r+"]
fconfigure $fd -buffering none fconfigure $fd -buffering none
fconfigure $fd -blocking false fconfigure $fd -blocking false
fconfigure $fd -translation binary fconfigure $fd -translation binary
...@@ -54,8 +57,8 @@ start_server {tags {"cli"}} { ...@@ -54,8 +57,8 @@ start_server {tags {"cli"}} {
} }
proc _run_cli {opts args} { proc _run_cli {opts args} {
set cmd [format "src/redis-cli -p %d -n 9 $args" [srv port]] set cmd [rediscli [srv port] [list -n 9 {*}$args]]
foreach {key value} $opts { foreach {key value} $args {
if {$key eq "pipe"} { if {$key eq "pipe"} {
set cmd "sh -c \"$value | $cmd\"" set cmd "sh -c \"$value | $cmd\""
} }
......
...@@ -29,6 +29,9 @@ start_server {tags {"repl"}} { ...@@ -29,6 +29,9 @@ start_server {tags {"repl"}} {
$slave slaveof $master_host $master_port $slave slaveof $master_host $master_port
test {Slave enters handshake} { test {Slave enters handshake} {
if {$::tls} {
fail "TLS with repl-diskless-sync not supported yet."
}
wait_for_condition 50 1000 { wait_for_condition 50 1000 {
[string match *handshake* [$slave role]] [string match *handshake* [$slave role]]
} else { } else {
...@@ -184,6 +187,10 @@ start_server {tags {"repl"}} { ...@@ -184,6 +187,10 @@ start_server {tags {"repl"}} {
} }
foreach mdl {no yes} { foreach mdl {no yes} {
if {$::tls && $mdl eq "yes"} {
puts "** Skipping test: TLS with repl-diskless-sync not supported yet."
continue
}
foreach sdl {disabled swapdb} { foreach sdl {disabled swapdb} {
start_server {tags {"repl"}} { start_server {tags {"repl"}} {
set master [srv 0 client] set master [srv 0 client]
...@@ -320,6 +327,9 @@ start_server {tags {"repl"}} { ...@@ -320,6 +327,9 @@ start_server {tags {"repl"}} {
} }
test {slave fails full sync and diskless load swapdb recoveres it} { test {slave fails full sync and diskless load swapdb recoveres it} {
if {$::tls} {
fail ""
}
start_server {tags {"repl"}} { start_server {tags {"repl"}} {
set slave [srv 0 client] set slave [srv 0 client]
set slave_host [srv 0 host] set slave_host [srv 0 host]
...@@ -387,6 +397,10 @@ test {slave fails full sync and diskless load swapdb recoveres it} { ...@@ -387,6 +397,10 @@ test {slave fails full sync and diskless load swapdb recoveres it} {
} }
test {diskless loading short read} { test {diskless loading short read} {
if {$::tls} {
fail "TLS with repl-diskless-sync not supported yet."
}
start_server {tags {"repl"}} { start_server {tags {"repl"}} {
set replica [srv 0 client] set replica [srv 0 client]
set replica_host [srv 0 host] set replica_host [srv 0 host]
......
# Test conditions where an instance is considered to be down # Test conditions where an instance is considered to be down
source "../tests/includes/init-tests.tcl" source "../tests/includes/init-tests.tcl"
source "../../../tests/support/cli.tcl"
proc ensure_master_up {} { proc ensure_master_up {} {
wait_for_condition 1000 50 { wait_for_condition 1000 50 {
...@@ -28,7 +29,7 @@ test "Crash the majority of Sentinels to prevent failovers for this unit" { ...@@ -28,7 +29,7 @@ test "Crash the majority of Sentinels to prevent failovers for this unit" {
test "SDOWN is triggered by non-responding but not crashed instance" { test "SDOWN is triggered by non-responding but not crashed instance" {
lassign [S 4 SENTINEL GET-MASTER-ADDR-BY-NAME mymaster] host port lassign [S 4 SENTINEL GET-MASTER-ADDR-BY-NAME mymaster] host port
ensure_master_up ensure_master_up
exec ../../../src/redis-cli -h $host -p $port debug sleep 10 > /dev/null & exec ../../../src/redis-cli -h $host -p $port {*}[rediscli_tls_config "../../../tests"] debug sleep 10 > /dev/null &
ensure_master_down ensure_master_down
ensure_master_up ensure_master_up
} }
......
proc rediscli_tls_config {testsdir} {
set tlsdir [file join $testsdir tls]
set cert [file join $tlsdir redis.crt]
set key [file join $tlsdir redis.key]
set cacert [file join $tlsdir ca.crt]
if {$::tls} {
return [list --tls --cert $cert --key $key --cacert $cacert]
} else {
return {}
}
}
proc rediscli {port {opts {}}} {
set cmd [list src/redis-cli -p $port]
lappend cmd {*}[rediscli_tls_config "tests"]
lappend cmd {*}$opts
return $cmd
}
...@@ -62,7 +62,7 @@ proc ::redis_cluster::__method__refresh_nodes_map {id} { ...@@ -62,7 +62,7 @@ proc ::redis_cluster::__method__refresh_nodes_map {id} {
lassign [split $ip_port :] start_host start_port lassign [split $ip_port :] start_host start_port
if {[catch { if {[catch {
set r {} set r {}
set r [redis $start_host $start_port] set r [redis $start_host $start_port 0 $::tls]
set nodes_descr [$r cluster nodes] set nodes_descr [$r cluster nodes]
$r close $r close
} e]} { } e]} {
...@@ -107,7 +107,7 @@ proc ::redis_cluster::__method__refresh_nodes_map {id} { ...@@ -107,7 +107,7 @@ proc ::redis_cluster::__method__refresh_nodes_map {id} {
# Connect to the node # Connect to the node
set link {} set link {}
catch {set link [redis $host $port]} catch {set link [redis $host $port 0 $::tls]}
# Build this node description as an hash. # Build this node description as an hash.
set node [dict create \ set node [dict create \
......
...@@ -39,8 +39,17 @@ array set ::redis::callback {} ...@@ -39,8 +39,17 @@ array set ::redis::callback {}
array set ::redis::state {} ;# State in non-blocking reply reading array set ::redis::state {} ;# State in non-blocking reply reading
array set ::redis::statestack {} ;# Stack of states, for nested mbulks array set ::redis::statestack {} ;# Stack of states, for nested mbulks
proc redis {{server 127.0.0.1} {port 6379} {defer 0}} { proc redis {{server 127.0.0.1} {port 6379} {defer 0} {tls 0}} {
set fd [socket $server $port] if {$tls} {
package require tls
::tls::init \
-cafile "$::tlsdir/ca.crt" \
-certfile "$::tlsdir/redis.crt" \
-keyfile "$::tlsdir/redis.key"
set fd [::tls::socket $server $port]
} else {
set fd [socket $server $port]
}
fconfigure $fd -translation binary fconfigure $fd -translation binary
set id [incr ::redis::id] set id [incr ::redis::id]
set ::redis::fd($id) $fd set ::redis::fd($id) $fd
...@@ -48,6 +57,7 @@ proc redis {{server 127.0.0.1} {port 6379} {defer 0}} { ...@@ -48,6 +57,7 @@ proc redis {{server 127.0.0.1} {port 6379} {defer 0}} {
set ::redis::blocking($id) 1 set ::redis::blocking($id) 1
set ::redis::deferred($id) $defer set ::redis::deferred($id) $defer
set ::redis::reconnect($id) 0 set ::redis::reconnect($id) 0
set ::redis::tls $tls
::redis::redis_reset_state $id ::redis::redis_reset_state $id
interp alias {} ::redis::redisHandle$id {} ::redis::__dispatch__ $id interp alias {} ::redis::redisHandle$id {} ::redis::__dispatch__ $id
} }
...@@ -72,7 +82,11 @@ proc ::redis::__dispatch__raw__ {id method argv} { ...@@ -72,7 +82,11 @@ proc ::redis::__dispatch__raw__ {id method argv} {
# Reconnect the link if needed. # Reconnect the link if needed.
if {$fd eq {}} { if {$fd eq {}} {
lassign $::redis::addr($id) host port lassign $::redis::addr($id) host port
set ::redis::fd($id) [socket $host $port] if {$::redis::tls} {
set ::redis::fd($id) [::tls::socket $host $port]
} else {
set ::redis::fd($id) [socket $host $port]
}
fconfigure $::redis::fd($id) -translation binary fconfigure $::redis::fd($id) -translation binary
set fd $::redis::fd($id) set fd $::redis::fd($id)
} }
......
...@@ -92,7 +92,11 @@ proc is_alive config { ...@@ -92,7 +92,11 @@ proc is_alive config {
proc ping_server {host port} { proc ping_server {host port} {
set retval 0 set retval 0
if {[catch { if {[catch {
set fd [socket $host $port] if {$::tls} {
set fd [::tls::socket $host $port]
} else {
set fd [socket $host $port]
}
fconfigure $fd -translation binary fconfigure $fd -translation binary
puts $fd "PING\r\n" puts $fd "PING\r\n"
flush $fd flush $fd
...@@ -136,7 +140,6 @@ proc tags {tags code} { ...@@ -136,7 +140,6 @@ proc tags {tags code} {
uplevel 1 $code uplevel 1 $code
set ::tags [lrange $::tags 0 end-[llength $tags]] set ::tags [lrange $::tags 0 end-[llength $tags]]
} }
proc start_server {options {code undefined}} { proc start_server {options {code undefined}} {
# If we are running against an external server, we just push the # If we are running against an external server, we just push the
# host/port pair in the stack the first time # host/port pair in the stack the first time
...@@ -145,7 +148,7 @@ proc start_server {options {code undefined}} { ...@@ -145,7 +148,7 @@ proc start_server {options {code undefined}} {
set srv {} set srv {}
dict set srv "host" $::host dict set srv "host" $::host
dict set srv "port" $::port dict set srv "port" $::port
set client [redis $::host $::port] set client [redis $::host $::port 0 $::tls]
dict set srv "client" $client dict set srv "client" $client
$client select 9 $client select 9
...@@ -178,6 +181,13 @@ proc start_server {options {code undefined}} { ...@@ -178,6 +181,13 @@ proc start_server {options {code undefined}} {
set data [split [exec cat "tests/assets/$baseconfig"] "\n"] set data [split [exec cat "tests/assets/$baseconfig"] "\n"]
set config {} set config {}
if {$::tls} {
dict set config "tls-cert-file" [format "%s/tests/tls/redis.crt" [pwd]]
dict set config "tls-key-file" [format "%s/tests/tls/redis.key" [pwd]]
dict set config "tls-dh-params-file" [format "%s/tests/tls/redis.dh" [pwd]]
dict set config "tls-ca-cert-file" [format "%s/tests/tls/ca.crt" [pwd]]
dict set config "loglevel" "debug"
}
foreach line $data { foreach line $data {
if {[string length $line] > 0 && [string index $line 0] ne "#"} { if {[string length $line] > 0 && [string index $line 0] ne "#"} {
set elements [split $line " "] set elements [split $line " "]
...@@ -192,7 +202,17 @@ proc start_server {options {code undefined}} { ...@@ -192,7 +202,17 @@ proc start_server {options {code undefined}} {
# start every server on a different port # start every server on a different port
set ::port [find_available_port [expr {$::port+1}]] set ::port [find_available_port [expr {$::port+1}]]
dict set config port $::port if {$::tls} {
dict set config "port" 0
dict set config "tls-port" $::port
dict set config "tls-cluster" "yes"
dict set config "tls-replication" "yes"
} else {
dict set config port $::port
}
set unixsocket [file normalize [format "%s/%s" [dict get $config "dir"] "socket"]]
dict set config "unixsocket" $unixsocket
# apply overrides from global space and arguments # apply overrides from global space and arguments
foreach {directive arguments} [concat $::global_overrides $overrides] { foreach {directive arguments} [concat $::global_overrides $overrides] {
...@@ -254,10 +274,11 @@ proc start_server {options {code undefined}} { ...@@ -254,10 +274,11 @@ proc start_server {options {code undefined}} {
} }
# setup properties to be able to initialize a client object # setup properties to be able to initialize a client object
set port_param [expr $::tls ? {"tls-port"} : {"port"}]
set host $::host set host $::host
set port $::port set port $::port
if {[dict exists $config bind]} { set host [dict get $config bind] } if {[dict exists $config bind]} { set host [dict get $config bind] }
if {[dict exists $config port]} { set port [dict get $config port] } if {[dict exists $config $port_param]} { set port [dict get $config $port_param] }
# setup config dict # setup config dict
dict set srv "config_file" $config_file dict set srv "config_file" $config_file
...@@ -267,6 +288,7 @@ proc start_server {options {code undefined}} { ...@@ -267,6 +288,7 @@ proc start_server {options {code undefined}} {
dict set srv "port" $port dict set srv "port" $port
dict set srv "stdout" $stdout dict set srv "stdout" $stdout
dict set srv "stderr" $stderr dict set srv "stderr" $stderr
dict set srv "unixsocket" $unixsocket
# if a block of code is supplied, we wait for the server to become # if a block of code is supplied, we wait for the server to become
# available, create a client object and kill the server afterwards # available, create a client object and kill the server afterwards
......
...@@ -395,7 +395,7 @@ proc colorstr {color str} { ...@@ -395,7 +395,7 @@ proc colorstr {color str} {
# of seconds to the specified Redis instance. # of seconds to the specified Redis instance.
proc start_write_load {host port seconds} { proc start_write_load {host port seconds} {
set tclsh [info nameofexecutable] set tclsh [info nameofexecutable]
exec $tclsh tests/helpers/gen_write_load.tcl $host $port $seconds & exec $tclsh tests/helpers/gen_write_load.tcl $host $port $seconds $::tls &
} }
# Stop a process generating write load executed with start_write_load. # Stop a process generating write load executed with start_write_load.
...@@ -423,7 +423,7 @@ proc lshuffle {list} { ...@@ -423,7 +423,7 @@ proc lshuffle {list} {
# of ops to the specified Redis instance. # of ops to the specified Redis instance.
proc start_bg_complex_data {host port db ops} { proc start_bg_complex_data {host port db ops} {
set tclsh [info nameofexecutable] set tclsh [info nameofexecutable]
exec $tclsh tests/helpers/bg_complex_data.tcl $host $port $db $ops & exec $tclsh tests/helpers/bg_complex_data.tcl $host $port $db $ops $::tls &
} }
# Stop a process generating write load executed with start_bg_complex_data. # Stop a process generating write load executed with start_bg_complex_data.
......
...@@ -63,6 +63,7 @@ set ::all_tests { ...@@ -63,6 +63,7 @@ set ::all_tests {
unit/lazyfree unit/lazyfree
unit/wait unit/wait
unit/pendingquerybuf unit/pendingquerybuf
unit/tls
} }
# Index to the next test to run in the ::all_tests list. # Index to the next test to run in the ::all_tests list.
set ::next_test 0 set ::next_test 0
...@@ -71,6 +72,7 @@ set ::host 127.0.0.1 ...@@ -71,6 +72,7 @@ set ::host 127.0.0.1
set ::port 21111 set ::port 21111
set ::traceleaks 0 set ::traceleaks 0
set ::valgrind 0 set ::valgrind 0
set ::tls 0
set ::stack_logging 0 set ::stack_logging 0
set ::verbose 0 set ::verbose 0
set ::quiet 0 set ::quiet 0
...@@ -92,6 +94,7 @@ set ::dont_clean 0 ...@@ -92,6 +94,7 @@ set ::dont_clean 0
set ::wait_server 0 set ::wait_server 0
set ::stop_on_failure 0 set ::stop_on_failure 0
set ::loop 0 set ::loop 0
set ::tlsdir "tests/tls"
# Set to 1 when we are running in client mode. The Redis test uses a # Set to 1 when we are running in client mode. The Redis test uses a
# server-client model to run tests simultaneously. The server instance # server-client model to run tests simultaneously. The server instance
...@@ -146,7 +149,7 @@ proc reconnect {args} { ...@@ -146,7 +149,7 @@ proc reconnect {args} {
set host [dict get $srv "host"] set host [dict get $srv "host"]
set port [dict get $srv "port"] set port [dict get $srv "port"]
set config [dict get $srv "config"] set config [dict get $srv "config"]
set client [redis $host $port] set client [redis $host $port 0 $::tls]
dict set srv "client" $client dict set srv "client" $client
# select the right db when we don't have to authenticate # select the right db when we don't have to authenticate
...@@ -166,7 +169,7 @@ proc redis_deferring_client {args} { ...@@ -166,7 +169,7 @@ proc redis_deferring_client {args} {
} }
# create client that defers reading reply # create client that defers reading reply
set client [redis [srv $level "host"] [srv $level "port"] 1] set client [redis [srv $level "host"] [srv $level "port"] 1 $::tls]
# select the right db and read the response (OK) # select the right db and read the response (OK)
$client select 9 $client select 9
...@@ -204,7 +207,7 @@ proc test_server_main {} { ...@@ -204,7 +207,7 @@ proc test_server_main {} {
if {!$::quiet} { if {!$::quiet} {
puts "Starting test server at port $port" puts "Starting test server at port $port"
} }
socket -server accept_test_clients -myaddr 127.0.0.1 $port socket -server accept_test_clients -myaddr 127.0.0.1 $port
# Start the client instances # Start the client instances
set ::clients_pids {} set ::clients_pids {}
...@@ -450,6 +453,7 @@ proc print_help_screen {} { ...@@ -450,6 +453,7 @@ proc print_help_screen {} {
"--stop Blocks once the first test fails." "--stop Blocks once the first test fails."
"--loop Execute the specified set of tests forever." "--loop Execute the specified set of tests forever."
"--wait-server Wait after server is started (so that you can attach a debugger)." "--wait-server Wait after server is started (so that you can attach a debugger)."
"--tls Run tests in TLS mode."
"--help Print this help screen." "--help Print this help screen."
} "\n"] } "\n"]
} }
...@@ -486,6 +490,13 @@ for {set j 0} {$j < [llength $argv]} {incr j} { ...@@ -486,6 +490,13 @@ for {set j 0} {$j < [llength $argv]} {incr j} {
} }
} elseif {$opt eq {--quiet}} { } elseif {$opt eq {--quiet}} {
set ::quiet 1 set ::quiet 1
} elseif {$opt eq {--tls}} {
package require tls 1.6
set ::tls 1
::tls::init \
-cafile "$::tlsdir/ca.crt" \
-certfile "$::tlsdir/redis.crt" \
-keyfile "$::tlsdir/redis.key"
} elseif {$opt eq {--host}} { } elseif {$opt eq {--host}} {
set ::external 1 set ::external 1
set ::host $arg set ::host $arg
...@@ -565,7 +576,11 @@ if {[llength $::single_tests] > 0} { ...@@ -565,7 +576,11 @@ if {[llength $::single_tests] > 0} {
} }
proc attach_to_replication_stream {} { proc attach_to_replication_stream {} {
set s [socket [srv 0 "host"] [srv 0 "port"]] if {$::tls} {
set s [::tls::socket [srv 0 "host"] [srv 0 "port"]]
} else {
set s [socket [srv 0 "host"] [srv 0 "port"]]
}
fconfigure $s -translation binary fconfigure $s -translation binary
puts -nonewline $s "SYNC\r\n" puts -nonewline $s "SYNC\r\n"
flush $s flush $s
......
start_server {tags {"limits"} overrides {maxclients 10}} { start_server {tags {"limits"} overrides {maxclients 10}} {
if {$::tls} {
set expected_code "*I/O error*"
} else {
set expected_code "*ERR max*reached*"
}
test {Check if maxclients works refusing connections} { test {Check if maxclients works refusing connections} {
set c 0 set c 0
catch { catch {
...@@ -12,5 +17,5 @@ start_server {tags {"limits"} overrides {maxclients 10}} { ...@@ -12,5 +17,5 @@ start_server {tags {"limits"} overrides {maxclients 10}} {
} e } e
assert {$c > 8 && $c <= 10} assert {$c > 8 && $c <= 10}
set e set e
} {*ERR max*reached*} } $expected_code
} }
Markdown is supported
0% or .
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment