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.
161 lines
5.7 KiB
161 lines
5.7 KiB
7 years ago
|
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
|
||
|
|