You can not select more than 25 topics
Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.
160 lines
5.7 KiB
160 lines
5.7 KiB
From 273963331bd303f595e820ca6da17cd63f5514db Mon Sep 17 00:00:00 2001 |
|
From: Damien Ciabrini <dciabrin@redhat.com> |
|
Date: Sat, 2 Dec 2017 11:53:56 +0100 |
|
Subject: [PATCH] redis: add support for tunneling replication traffic |
|
|
|
Add parameters in the resource agent to assign specific redis port to |
|
each pacemaker node. When redis slave wants to connect to a redis |
|
master, it will instead connect to a tunnel host, on the port assigned |
|
to the targeted redis master. |
|
|
|
This makes it possible for redis replication traffic to go through |
|
pre-existing tunnels. This can be used to encrypt such traffic. |
|
--- |
|
heartbeat/redis | 89 +++++++++++++++++++++++++++++++++++++++++++++++++++++++-- |
|
1 file changed, 86 insertions(+), 3 deletions(-) |
|
|
|
diff --git a/heartbeat/redis b/heartbeat/redis |
|
index fcd8c234..d9e29e2c 100755 |
|
--- a/heartbeat/redis |
|
+++ b/heartbeat/redis |
|
@@ -38,6 +38,7 @@ |
|
: ${OCF_RESKEY_pidfile_name:=redis-server.pid} |
|
: ${OCF_RESKEY_socket_name:=redis.sock} |
|
: ${OCF_RESKEY_port:=6379} |
|
+: ${OCF_RESKEY_tunnel_host:=127.0.0.1} |
|
|
|
if [ -z "$OCF_RESKEY_config" ]; then |
|
if [ -f "/etc/redis.conf" ]; then |
|
@@ -156,6 +157,39 @@ Port for replication client to connect to on remote server |
|
<content type="string" default="${OCF_RESKEY_port}"/> |
|
</parameter> |
|
|
|
+<parameter name="tunnel_host" unique="0" required="0"> |
|
+<longdesc lang="en"> |
|
+When replication traffic is tunnelled, this is the host to target |
|
+to forward outgoing traffic to the redis master. The resource |
|
+agent configures the redis slave to target the master via |
|
+tunnel_host:tunnel_port. |
|
+ |
|
+Note that in order to enable replication traffic tunneling, |
|
+parameter {tunnel_port_map} must be populated. |
|
+</longdesc> |
|
+<shortdesc lang="en">Tunnel host for replication traffic</shortdesc> |
|
+<content type="string" default="${OCF_RESKEY_tunnel_host}"/> |
|
+</parameter> |
|
+ |
|
+<parameter name="tunnel_port_map" unique="0" required="0"> |
|
+<longdesc lang="en"> |
|
+A mapping of pacemaker node names to redis port number. |
|
+ |
|
+To be used when redis servers need to tunnel replication traffic. |
|
+On every node where the redis resource is running, the redis server |
|
+listens to a different port. Each redis server can access its peers |
|
+for replication traffic via a tunnel accessible at {tunnel_host}:port. |
|
+ |
|
+The mapping the form of: |
|
+pcmk1-name:port-for-redis1;pcmk2-name:port-for-redis2;pcmk3-name:port-for-redis3 |
|
+ |
|
+where the redis resource started on node pcmk1-name would listen on |
|
+port port-for-redis1 |
|
+</longdesc> |
|
+<shortdesc lang="en">Mapping of Redis server name to redis port</shortdesc> |
|
+<content type="string" default=""/> |
|
+</parameter> |
|
+ |
|
<parameter name="wait_last_known_master" unique="0" required="0"> |
|
<longdesc lang="en"> |
|
During redis cluster bootstrap, wait for the last known master to be |
|
@@ -291,6 +325,8 @@ simple_status() { |
|
|
|
function monitor() { |
|
local res |
|
+ local master_name |
|
+ local last_known_master_port |
|
|
|
simple_status |
|
res=$? |
|
@@ -334,14 +370,48 @@ redis_monitor() { |
|
return $OCF_ERR_GENERIC |
|
fi |
|
if [[ "${info[master_host]}" != "$(last_known_master)" ]]; then |
|
- ocf_log err "monitor: Slave mode current master does not match running master. current=${info[master_host]}, running=$(last_known_master)" |
|
- return $OCF_ERR_GENERIC |
|
+ if [ -n "${OCF_RESKEY_tunnel_port_map}" ]; then |
|
+ master_name=$(port_to_redis_node ${info[master_port]}) |
|
+ last_known_master_port=$(redis_node_to_port $(last_known_master)) |
|
+ if [[ "${info[master_host]}" != "${OCF_RESKEY_tunnel_host}" ]] || |
|
+ [[ "${info[master_port]}" != "${last_known_master_port}" ]]; then |
|
+ ocf_log err "monitor: Slave mode current tunnelled connection to redis server does not match running master. tunnelled='${info[master_host]}:${info[master_port]} (${master_name})', running='$(last_known_master)'" |
|
+ return $OCF_ERR_GENERIC |
|
+ fi |
|
+ else |
|
+ ocf_log err "monitor: Slave mode current master does not match running master. current=${info[master_host]}, running=$(last_known_master)" |
|
+ return $OCF_ERR_GENERIC |
|
+ fi |
|
fi |
|
fi |
|
fi |
|
return $OCF_SUCCESS |
|
} |
|
|
|
+redis_node_to_port() |
|
+{ |
|
+ local node=$1 |
|
+ echo "$OCF_RESKEY_tunnel_port_map" | tr ';' '\n' | tr -d ' ' | sed 's/:/ /' | awk -F' ' '$1=="'"$node"'" {print $2;exit}' |
|
+} |
|
+ |
|
+port_to_redis_node() |
|
+{ |
|
+ local port=$1 |
|
+ echo "$OCF_RESKEY_tunnel_port_map" | tr ';' '\n' | tr -d ' ' | sed 's/:/ /' | awk -F' ' '$2=="'"$port"'" {print $1;exit}' |
|
+} |
|
+ |
|
+get_tunnel_port_from_master() |
|
+{ |
|
+ local master_name=$1 |
|
+ crm_attribute --node "$master_name" -l forever --name ${INSTANCE_ATTR_NAME}-tunnel-port --query -q 2>/dev/null |
|
+} |
|
+ |
|
+get_master_from_tunnel_port() |
|
+{ |
|
+ local master_name=$1 |
|
+ crm_attribute --node "$master_name" -l forever --name ${INSTANCE_ATTR_NAME}-tunnel-port --query -q 2>/dev/null |
|
+} |
|
+ |
|
function check_dump_file() |
|
{ |
|
if ! have_binary "$REDIS_CHECK_DUMP"; then |
|
@@ -479,6 +549,7 @@ redis_promote() { |
|
function demote() { |
|
local master_host |
|
local master_port |
|
+ local tunnel_port |
|
|
|
# client kill is only supported in Redis 2.8.12 or greater |
|
version=$(redis_client -v | awk '{print $NF}') |
|
@@ -512,7 +583,19 @@ redis_demote() { |
|
master_host="no-such-master" |
|
fi |
|
|
|
- ocf_log info "demote: Setting master to '$master_host'" |
|
+ if [ -n "${OCF_RESKEY_tunnel_port_map}" ]; then |
|
+ # master_host can be the special marker "no-such-master" |
|
+ # while a master is being selected. In this case, no |
|
+ # tunnel port is returned, but this is not fatal. |
|
+ tunnel_port=$(redis_node_to_port "$master_host") |
|
+ if [ -n "$tunnel_port" ]; then |
|
+ ocf_log info "demote: Setting master to '$master_host' via local tunnel '${OCF_RESKEY_tunnel_host}' on port '$tunnel_port'" |
|
+ master_host="${OCF_RESKEY_tunnel_host}" |
|
+ master_port="$tunnel_port" |
|
+ fi |
|
+ else |
|
+ ocf_log info "demote: Setting master to '$master_host'" |
|
+ fi |
|
|
|
redis_client slaveof "$master_host" "$master_port" |
|
|
|
-- |
|
2.14.3 |
|
|
|
|