b3c51851dc
* don't use bashism * enquote variables Closes-Bug: #1588400 Change-Id: I27869af311b2c193fa50908bf3dc3ce14c9ba031
413 lines
13 KiB
Bash
413 lines
13 KiB
Bash
#!/bin/bash
|
|
#
|
|
#
|
|
# An OCF RA for conntrackd in namespace
|
|
# http://conntrack-tools.netfilter.org/
|
|
#
|
|
# Originaly created by Dominik Klein
|
|
#
|
|
# Patched by Mirantis
|
|
#
|
|
# This program is free software; you can redistribute it and/or modify
|
|
# it under the terms of version 2 of the GNU General Public License as
|
|
# published by the Free Software Foundation.
|
|
#
|
|
# This program is distributed in the hope that it would be useful, but
|
|
# WITHOUT ANY WARRANTY; without even the implied warranty of
|
|
# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.
|
|
#
|
|
# Further, this software is distributed without any warranty that it is
|
|
# free of the rightful claim of any third person regarding infringement
|
|
# or the like. Any license provided herein, whether implied or
|
|
# otherwise, applies only to this software file. Patent licenses, if
|
|
# any, provided herein do not apply to combinations of this program with
|
|
# other software, or any other product whatsoever.
|
|
#
|
|
# You should have received a copy of the GNU General Public License
|
|
# along with this program; if not, write the Free Software Foundation,
|
|
# Inc., 59 Temple Place - Suite 330, Boston MA 02111-1307, USA.
|
|
#
|
|
|
|
#######################################################################
|
|
# Initialization:
|
|
|
|
: ${OCF_FUNCTIONS_DIR=${OCF_ROOT}/lib/heartbeat}
|
|
. ${OCF_FUNCTIONS_DIR}/ocf-shellfuncs
|
|
|
|
#######################################################################
|
|
|
|
OCF_RESKEY_binary_default=conntrackd
|
|
OCF_RESKEY_config_default=/etc/conntrackd/conntrackd.conf
|
|
OCF_RESKEY_ns_default=vrouter
|
|
OCF_RESKEY_bridge_default=br-mgmt
|
|
OCF_RESKEY_host_interface_default=mgmt-conntrd
|
|
OCF_RESKEY_ns_interface_default=conntrd
|
|
|
|
: ${HA_LOGTAG="ocf-ns_conntrackd"}
|
|
: ${HA_LOGFACILITY="daemon"}
|
|
# For users of versions prior to 1.2:
|
|
# Map renamed parameter "conntrackd" to "binary" if in use
|
|
: ${OCF_RESKEY_binary=${OCF_RESKEY_conntrackd-${OCF_RESKEY_binary_default}}}
|
|
: ${OCF_RESKEY_config=${OCF_RESKEY_config_default}}
|
|
: ${OCF_RESKEY_ns=${OCF_RESKEY_ns_default}}
|
|
: ${OCF_RESKEY_bridge=${OCF_RESKEY_bridge_default}}
|
|
: ${OCF_RESKEY_host_interface=${OCF_RESKEY_host_interface_default}}
|
|
: ${OCF_RESKEY_ns_interface=${OCF_RESKEY_ns_interface_default}}
|
|
|
|
meta_data() {
|
|
cat <<END
|
|
<?xml version="1.0"?>
|
|
<!DOCTYPE resource-agent SYSTEM "ra-api-1.dtd">
|
|
<resource-agent name="conntrackd">
|
|
<version>1.2</version>
|
|
|
|
<longdesc lang="en">
|
|
Master/Slave OCF Resource Agent for conntrackd
|
|
</longdesc>
|
|
|
|
<shortdesc lang="en">This resource agent manages conntrackd</shortdesc>
|
|
|
|
<parameters>
|
|
<parameter name="binary">
|
|
<longdesc lang="en">Name of the conntrackd executable.
|
|
If conntrackd is installed and available in the default PATH, it is sufficient to configure the name of the binary
|
|
For example "my-conntrackd-binary-version-0.9.14"
|
|
If conntrackd is installed somewhere else, you may also give a full path
|
|
For example "/packages/conntrackd-0.9.14/sbin/conntrackd"
|
|
</longdesc>
|
|
<shortdesc lang="en">Name of the conntrackd executable</shortdesc>
|
|
<content type="string" default="$OCF_RESKEY_binary_default"/>
|
|
</parameter>
|
|
|
|
<parameter name="config">
|
|
<longdesc lang="en">Full path to the conntrackd.conf file.
|
|
For example "/packages/conntrackd-0.9.14/etc/conntrackd/conntrackd.conf"</longdesc>
|
|
<shortdesc lang="en">Path to conntrackd.conf</shortdesc>
|
|
<content type="string" default="$OCF_RESKEY_config_default"/>
|
|
</parameter>
|
|
|
|
<parameter name="ns">
|
|
<longdesc lang="en">Network namespace in which ns_interface
|
|
will be configured.
|
|
</longdesc>
|
|
<shortdesc lang="en">Network namespace.</shortdesc>
|
|
<content type="string" default="$OCF_RESKEY_ns_default"/>
|
|
</parameter>
|
|
|
|
<parameter name="bridge">
|
|
<longdesc lang="en">Bridge to which host_interface will be added.</longdesc>
|
|
<shortdesc lang="en">Bridge to which host_interface will be added.</shortdesc>
|
|
<content type="string" default="$OCF_RESKEY_bridge_default"/>
|
|
</parameter>
|
|
|
|
<parameter name="host_interface">
|
|
<longdesc lang="en">Host interface in veth pair.</longdesc>
|
|
<shortdesc lang="en">Host interface in veth pair.</shortdesc>
|
|
<content type="string" default="$OCF_RESKEY_host_interface_default"/>
|
|
</parameter>
|
|
|
|
<parameter name="ns_interface">
|
|
<longdesc lang="en">Network namespace interface in veth pair.
|
|
This is the interface used to send synchronization messges.
|
|
</longdesc>
|
|
<shortdesc lang="en">Network namespace interface in veth pair</shortdesc>
|
|
<content type="string" default="$OCF_RESKEY_ns_interface_default"/>
|
|
</parameter>
|
|
</parameters>
|
|
|
|
<actions>
|
|
<action name="start" timeout="30" />
|
|
<action name="promote" timeout="30" />
|
|
<action name="demote" timeout="30" />
|
|
<action name="notify" timeout="30" />
|
|
<action name="stop" timeout="30" />
|
|
<action name="monitor" timeout="20" interval="20" role="Slave" />
|
|
<action name="monitor" timeout="20" interval="10" role="Master" />
|
|
<action name="meta-data" timeout="5" />
|
|
<action name="validate-all" timeout="30" />
|
|
</actions>
|
|
</resource-agent>
|
|
END
|
|
}
|
|
|
|
meta_expect()
|
|
{
|
|
local what=$1 whatvar=OCF_RESKEY_CRM_meta_${1//-/_} op=$2 expect=$3
|
|
local val=${!whatvar}
|
|
if [ -n "$val" ]; then
|
|
# [, not [[, or it won't work ;)
|
|
[ $val $op $expect ] && return
|
|
fi
|
|
ocf_exit_reason "meta parameter misconfigured, expected $what $op $expect, but found ${val:-unset}."
|
|
exit $OCF_ERR_CONFIGURED
|
|
}
|
|
|
|
conntrackd_is_master() {
|
|
# You can't query conntrackd whether it is master or slave. It can be both at the same time.
|
|
# This RA creates a statefile during promote and enforces master-max=1 and clone-node-max=1
|
|
ha_pseudo_resource $statefile monitor
|
|
}
|
|
|
|
conntrackd_set_master_score() {
|
|
${HA_SBIN_DIR}/crm_master -Q -l reboot -v $1
|
|
}
|
|
|
|
add_to_bridge() {
|
|
brctl show $OCF_RESKEY_bridge | grep $OCF_RESKEY_host_interface
|
|
if [ "$rc" -ne 0 ]; then
|
|
ocf_run brctl addif $OCF_RESKEY_bridge $OCF_RESKEY_host_interface
|
|
ocf_run ifconfig $OCF_RESKEY_host_interface 0.0.0.0
|
|
fi
|
|
}
|
|
|
|
get_veth_pair() {
|
|
if ! ip netns exec "$OCF_RESKEY_ns" ip link show dev lo up | grep -wq 'lo:'; then
|
|
ip netns add "$OCF_RESKEY_ns"
|
|
ip netns exec "$OCF_RESKEY_ns" ip link set up dev lo
|
|
fi
|
|
|
|
ocf_run ip netns exec $OCF_RESKEY_ns ip link show $OCF_RESKEY_ns_interface 2>/dev/null
|
|
rc=$?
|
|
|
|
# create pair (tail's can't be alone) and attach tail to the net.namespace
|
|
if [ "$rc" -ne 0 ]; then
|
|
local last_octet=$(ifconfig $OCF_RESKEY_bridge 2>/dev/null|awk '/inet addr:/ {print $2}'|sed 's/addr://' | awk -F. '{print $NF}')
|
|
local bridge_mtu=$(cat /sys/class/net/${OCF_RESKEY_bridge}/mtu)
|
|
|
|
ocf_run ip link add $OCF_RESKEY_host_interface type veth peer name $OCF_RESKEY_ns_interface
|
|
ocf_run ip link set dev $OCF_RESKEY_ns_interface netns $OCF_RESKEY_ns
|
|
ocf_run ip netns exec $OCF_RESKEY_ns ip link set up dev $OCF_RESKEY_ns_interface mtu $bridge_mtu
|
|
ocf_run ip link set up dev $OCF_RESKEY_host_interface mtu $bridge_mtu
|
|
ocf_run ip netns exec $OCF_RESKEY_ns ip addr add 240.1.0.${last_octet}/24 dev $OCF_RESKEY_ns_interface
|
|
fi
|
|
|
|
add_to_bridge
|
|
|
|
return 0
|
|
}
|
|
|
|
conntrackd_monitor() {
|
|
|
|
get_veth_pair
|
|
|
|
rc=$OCF_NOT_RUNNING
|
|
# It does not write a PID file, so check the socket exists after
|
|
# extracting its path from the configuration file
|
|
local conntrack_socket=$(awk '/^[ \t]*UNIX[ \t]*{/,/^[ \t]*}/ { if ($1 == "Path") { print $2 } }' $OCF_RESKEY_config)
|
|
[ -S "$conntrack_socket" ] && rc=$OCF_SUCCESS
|
|
if [ "$rc" -eq "$OCF_SUCCESS" ]; then
|
|
# conntrackd is running
|
|
# now see if it acceppts queries
|
|
if ! ip netns exec $OCF_RESKEY_ns $OCF_RESKEY_binary -C $OCF_RESKEY_config -s > /dev/null 2>&1; then
|
|
rc=$OCF_ERR_GENERIC
|
|
ocf_exit_reason "conntrackd is running but not responding to queries"
|
|
fi
|
|
if conntrackd_is_master; then
|
|
rc=$OCF_RUNNING_MASTER
|
|
# Restore master setting on probes
|
|
if [ $OCF_RESKEY_CRM_meta_interval -eq 0 ]; then
|
|
conntrackd_set_master_score $master_score
|
|
fi
|
|
else
|
|
# Restore master setting on probes
|
|
if [ $OCF_RESKEY_CRM_meta_interval -eq 0 ]; then
|
|
conntrackd_set_master_score $slave_score
|
|
fi
|
|
fi
|
|
fi
|
|
return $rc
|
|
}
|
|
|
|
conntrackd_start() {
|
|
rc=$OCF_ERR_GENERIC
|
|
|
|
# Keep trying to start the resource;
|
|
# wait for the CRM to time us out if this fails
|
|
while :; do
|
|
conntrackd_monitor
|
|
status=$?
|
|
case "$status" in
|
|
$OCF_SUCCESS)
|
|
conntrackd_set_master_score $slave_score
|
|
# -n = request resync from the others
|
|
if ! ip netns exec $OCF_RESKEY_ns $OCF_RESKEY_binary -C $OCF_RESKEY_config -n; then
|
|
ocf_exit_reason "$OCF_RESKEY_binary -C $OCF_RESKEY_config -n failed during start."
|
|
rc=$OCF_ERR_GENERIC
|
|
else
|
|
rc=$OCF_SUCCESS
|
|
fi
|
|
break
|
|
;;
|
|
$OCF_NOT_RUNNING)
|
|
ocf_log info "Starting conntrackd"
|
|
ip netns exec $OCF_RESKEY_ns $OCF_RESKEY_binary -C $OCF_RESKEY_config -d
|
|
;;
|
|
$OCF_RUNNING_MASTER)
|
|
ocf_log warn "conntrackd already in master mode, demoting."
|
|
ha_pseudo_resource $statefile stop
|
|
;;
|
|
$OCF_ERR_GENERIC)
|
|
ocf_exit_reason "conntrackd start failed"
|
|
rc=$OCF_ERR_GENERIC
|
|
break
|
|
;;
|
|
esac
|
|
done
|
|
return $rc
|
|
}
|
|
|
|
conntrackd_stop() {
|
|
rc=$OCF_ERR_GENERIC
|
|
|
|
# Keep trying to bring down the resource;
|
|
# wait for the CRM to time us out if this fails
|
|
while :; do
|
|
conntrackd_monitor
|
|
status=$?
|
|
case "$status" in
|
|
$OCF_SUCCESS|$OCF_ERR_GENERIC)
|
|
ocf_log info "Stopping conntrackd"
|
|
ip netns exec $OCF_RESKEY_ns $OCF_RESKEY_binary -C $OCF_RESKEY_config -k
|
|
;;
|
|
$OCF_NOT_RUNNING)
|
|
rc=$OCF_SUCCESS
|
|
break
|
|
;;
|
|
$OCF_RUNNING_MASTER)
|
|
ocf_log warn "conntrackd still master"
|
|
;;
|
|
esac
|
|
done
|
|
return $rc
|
|
|
|
}
|
|
|
|
conntrackd_validate_all() {
|
|
check_binary "$OCF_RESKEY_binary"
|
|
if ! [ -e "$OCF_RESKEY_config" ]; then
|
|
ocf_exit_reason "Config FILE $OCF_RESKEY_config does not exist"
|
|
return $OCF_ERR_INSTALLED
|
|
fi
|
|
meta_expect master-node-max = 1
|
|
meta_expect master-max = 1
|
|
meta_expect clone-node-max = 1
|
|
|
|
return $OCF_SUCCESS
|
|
}
|
|
|
|
conntrackd_promote() {
|
|
rc=$OCF_SUCCESS
|
|
if ! conntrackd_is_master; then
|
|
# -c = Commit the external cache to the kernel
|
|
# -f = Flush internal and external cache
|
|
# -R = resync with the kernel table
|
|
# -B = send a bulk update on the line
|
|
for parm in c f R B; do
|
|
if ! ip netns exec $OCF_RESKEY_ns $OCF_RESKEY_binary -C $OCF_RESKEY_config -$parm; then
|
|
ocf_exit_reason "$OCF_RESKEY_binary -C $OCF_RESKEY_config -$parm failed during promote."
|
|
rc=$OCF_ERR_GENERIC
|
|
break
|
|
fi
|
|
done
|
|
ha_pseudo_resource $statefile start
|
|
conntrackd_set_master_score $master_score
|
|
fi
|
|
return $rc
|
|
}
|
|
|
|
conntrackd_demote() {
|
|
rc=$OCF_SUCCESS
|
|
if conntrackd_is_master; then
|
|
# -t = shorten kernel timers to remove zombies
|
|
# -n = request a resync from the others
|
|
for parm in t n; do
|
|
if ! ip netns exec $OCF_RESKEY_ns $OCF_RESKEY_binary -C $OCF_RESKEY_config -$parm; then
|
|
ocf_exit_reason "$OCF_RESKEY_binary -C $OCF_RESKEY_config -$parm failed during demote."
|
|
rc=$OCF_ERR_GENERIC
|
|
break
|
|
fi
|
|
done
|
|
ha_pseudo_resource $statefile stop
|
|
conntrackd_set_master_score $slave_score
|
|
fi
|
|
return $rc
|
|
}
|
|
|
|
conntrackd_notify() {
|
|
hostname=$(hostname)
|
|
# OCF_RESKEY_CRM_meta_notify_master_uname is a whitespace separated list of master hostnames
|
|
for master in $OCF_RESKEY_CRM_meta_notify_master_uname; do
|
|
# if we are the master and an instance was just started on another node:
|
|
# send a bulk update to allow failback
|
|
if [ "$hostname" = "$master" -a "$OCF_RESKEY_CRM_meta_notify_type" = "post" -a "$OCF_RESKEY_CRM_meta_notify_operation" = "start" -a "$OCF_RESKEY_CRM_meta_notify_start_uname" != "$hostname" ]; then
|
|
ocf_log info "Sending bulk update in post start to peers to allow failback"
|
|
ip netns exec $OCF_RESKEY_ns $OCF_RESKEY_binary -C $OCF_RESKEY_config -B
|
|
fi
|
|
done
|
|
for tobepromoted in $OCF_RESKEY_CRM_meta_notify_promote_uname; do
|
|
# if there is a promote action to be executed on another node:
|
|
# send a bulk update to allow failback
|
|
if [ "$hostname" != "$tobepromoted" -a "$OCF_RESKEY_CRM_meta_notify_type" = "pre" -a "$OCF_RESKEY_CRM_meta_notify_operation" = "promote" ]; then
|
|
ocf_log info "Sending bulk update in pre promote to peers to allow failback"
|
|
ip netns exec $OCF_RESKEY_ns $OCF_RESKEY_binary -C $OCF_RESKEY_config -B
|
|
fi
|
|
done
|
|
}
|
|
|
|
conntrackd_usage() {
|
|
cat <<EOF
|
|
usage: $0 {start|stop|promote|demote|monitor|validate-all|meta-data}
|
|
Expects to have a fully populated OCF RA-compliant environment set.
|
|
EOF
|
|
}
|
|
|
|
statefile=conntrackd.${OCF_RESOURCE_INSTANCE//:[0-9]*}.master
|
|
|
|
master_score=1000
|
|
slave_score=100
|
|
|
|
if [ $# -ne 1 ]; then
|
|
conntrackd_usage
|
|
exit $OCF_ERR_ARGS
|
|
fi
|
|
|
|
case $__OCF_ACTION in
|
|
meta-data)
|
|
meta_data
|
|
exit $OCF_SUCCESS
|
|
;;
|
|
usage)
|
|
conntrackd_usage
|
|
exit $OCF_SUCCESS
|
|
esac
|
|
|
|
# Everything except usage and meta-data must pass the validate test
|
|
conntrackd_validate_all || exit
|
|
|
|
case $__OCF_ACTION in
|
|
start)
|
|
conntrackd_start
|
|
;;
|
|
stop)
|
|
conntrackd_stop
|
|
;;
|
|
promote)
|
|
conntrackd_promote
|
|
;;
|
|
demote)
|
|
conntrackd_demote
|
|
;;
|
|
status|monitor)
|
|
conntrackd_monitor
|
|
;;
|
|
notify)
|
|
conntrackd_notify
|
|
;;
|
|
validate-all)
|
|
;;
|
|
*)
|
|
conntrackd_usage
|
|
exit $OCF_ERR_UNIMPLEMENTED
|
|
esac
|
|
# exit code is the exit code (return code) of the last command (shell function)
|