Blame SOURCES/bz1544483-redis-add-support-for-tunneling-replication-traffic.patch

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