fuel-library/files/fuel-ha-utils/ocf/ns_conntrackd
dmburmistrov b3c51851dc Use safe conditions
* don't use bashism
* enquote variables

Closes-Bug: #1588400

Change-Id: I27869af311b2c193fa50908bf3dc3ce14c9ba031
2016-06-02 17:53:27 +03:00

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)