Initial managed-container HA resource agent baseline
This commit is contained in:
Executable
+372
@@ -0,0 +1,372 @@
|
||||
#!/bin/bash
|
||||
#
|
||||
# OCF resource agent for Linux IPVS connection synchronization
|
||||
#
|
||||
# Promoted = IPVS sync master
|
||||
# Unpromoted = IPVS sync backup
|
||||
#
|
||||
|
||||
OCF_SUCCESS=0
|
||||
OCF_ERR_GENERIC=1
|
||||
OCF_ERR_ARGS=2
|
||||
OCF_ERR_UNIMPLEMENTED=3
|
||||
OCF_ERR_PERM=4
|
||||
OCF_ERR_INSTALLED=5
|
||||
OCF_ERR_CONFIGURED=6
|
||||
OCF_NOT_RUNNING=7
|
||||
OCF_RUNNING_PROMOTED=8
|
||||
OCF_FAILED_PROMOTED=9
|
||||
|
||||
IPVSADM="${IPVSADM:-/usr/sbin/ipvsadm}"
|
||||
IP="${IP:-/usr/sbin/ip}"
|
||||
|
||||
# The IP is used only to discover the LAN interface.
|
||||
# Different nodes may have different interface names.
|
||||
OCF_RESKEY_probe_ip="${OCF_RESKEY_probe_ip:-192.168.1.1}"
|
||||
OCF_RESKEY_interface="${OCF_RESKEY_interface:-}"
|
||||
|
||||
meta_data()
|
||||
{
|
||||
cat <<'XML'
|
||||
<?xml version="1.0"?>
|
||||
<!DOCTYPE resource-agent SYSTEM "ra-api-1.dtd">
|
||||
<resource-agent name="ipvs-sync" version="1.0">
|
||||
<version>1.0</version>
|
||||
|
||||
<longdesc lang="en">
|
||||
Manages the Linux IPVS connection synchronization daemon as a
|
||||
Pacemaker promotable resource.
|
||||
|
||||
Unpromoted instances run the IPVS backup synchronization daemon.
|
||||
The promoted instance runs the IPVS master synchronization daemon.
|
||||
</longdesc>
|
||||
|
||||
<shortdesc lang="en">
|
||||
IPVS connection synchronization
|
||||
</shortdesc>
|
||||
|
||||
<parameters>
|
||||
<parameter name="probe_ip" unique="0" required="0">
|
||||
<longdesc lang="en">
|
||||
An IPv4 address reachable through the interface that should
|
||||
carry IPVS synchronization traffic. Used only for automatic
|
||||
interface discovery.
|
||||
</longdesc>
|
||||
<shortdesc lang="en">Interface discovery IP</shortdesc>
|
||||
<content type="string" default="192.168.1.1"/>
|
||||
</parameter>
|
||||
|
||||
<parameter name="interface" unique="0" required="0">
|
||||
<longdesc lang="en">
|
||||
Optional explicit synchronization interface. If omitted,
|
||||
the interface is discovered using the route to probe_ip.
|
||||
</longdesc>
|
||||
<shortdesc lang="en">Synchronization interface</shortdesc>
|
||||
<content type="string"/>
|
||||
</parameter>
|
||||
</parameters>
|
||||
|
||||
<actions>
|
||||
<action name="start" timeout="20s"/>
|
||||
<action name="stop" timeout="20s"/>
|
||||
<action name="monitor" timeout="10s" interval="10s"/>
|
||||
<action name="promote" timeout="20s"/>
|
||||
<action name="demote" timeout="20s"/>
|
||||
<action name="validate-all" timeout="10s"/>
|
||||
<action name="meta-data" timeout="5s"/>
|
||||
</actions>
|
||||
</resource-agent>
|
||||
XML
|
||||
}
|
||||
|
||||
get_iface()
|
||||
{
|
||||
if [ -n "$OCF_RESKEY_interface" ]; then
|
||||
printf '%s\n' "$OCF_RESKEY_interface"
|
||||
return 0
|
||||
fi
|
||||
|
||||
"$IP" route get "$OCF_RESKEY_probe_ip" 2>/dev/null |
|
||||
awk '
|
||||
{
|
||||
for (i=1; i<=NF; i++) {
|
||||
if ($i == "dev" && (i+1) <= NF) {
|
||||
print $(i+1)
|
||||
exit
|
||||
}
|
||||
}
|
||||
}'
|
||||
}
|
||||
|
||||
daemon_status()
|
||||
{
|
||||
"$IPVSADM" -L --daemon 2>/dev/null
|
||||
}
|
||||
|
||||
set_promotion_score()
|
||||
{
|
||||
/usr/sbin/crm_attribute --promotion --update 100 >/dev/null 2>&1 || true
|
||||
}
|
||||
|
||||
monitor_resource()
|
||||
{
|
||||
local output
|
||||
local have_master=0
|
||||
local have_backup=0
|
||||
|
||||
output="$(daemon_status)"
|
||||
|
||||
printf '%s\n' "$output" |
|
||||
grep -q '^master sync daemon' &&
|
||||
have_master=1
|
||||
|
||||
printf '%s\n' "$output" |
|
||||
grep -q '^backup sync daemon' &&
|
||||
have_backup=1
|
||||
|
||||
# Both roles simultaneously is an invalid state.
|
||||
if [ "$have_master" -eq 1 ] &&
|
||||
[ "$have_backup" -eq 1 ]; then
|
||||
return "$OCF_ERR_GENERIC"
|
||||
fi
|
||||
|
||||
if [ "$have_master" -eq 1 ]; then
|
||||
set_promotion_score
|
||||
return "$OCF_RUNNING_PROMOTED"
|
||||
fi
|
||||
|
||||
if [ "$have_backup" -eq 1 ]; then
|
||||
set_promotion_score
|
||||
return "$OCF_SUCCESS"
|
||||
fi
|
||||
|
||||
return "$OCF_NOT_RUNNING"
|
||||
}
|
||||
|
||||
stop_master()
|
||||
{
|
||||
"$IPVSADM" --stop-daemon master >/dev/null 2>&1 || true
|
||||
}
|
||||
|
||||
stop_backup()
|
||||
{
|
||||
"$IPVSADM" --stop-daemon backup >/dev/null 2>&1 || true
|
||||
}
|
||||
|
||||
start_master()
|
||||
{
|
||||
local iface
|
||||
|
||||
iface="$(get_iface)"
|
||||
|
||||
if [ -z "$iface" ]; then
|
||||
echo "ERROR: unable to determine synchronization interface" >&2
|
||||
return "$OCF_ERR_GENERIC"
|
||||
fi
|
||||
|
||||
"$IPVSADM" \
|
||||
--start-daemon master \
|
||||
--mcast-interface "$iface"
|
||||
}
|
||||
|
||||
start_backup()
|
||||
{
|
||||
local iface
|
||||
|
||||
iface="$(get_iface)"
|
||||
|
||||
if [ -z "$iface" ]; then
|
||||
echo "ERROR: unable to determine synchronization interface" >&2
|
||||
return "$OCF_ERR_GENERIC"
|
||||
fi
|
||||
|
||||
"$IPVSADM" \
|
||||
--start-daemon backup \
|
||||
--mcast-interface "$iface"
|
||||
}
|
||||
|
||||
start_resource()
|
||||
{
|
||||
monitor_resource
|
||||
rc=$?
|
||||
|
||||
case "$rc" in
|
||||
"$OCF_SUCCESS")
|
||||
# Already running correctly as backup.
|
||||
return "$OCF_SUCCESS"
|
||||
;;
|
||||
|
||||
"$OCF_RUNNING_PROMOTED")
|
||||
# A start operation must leave a promotable resource
|
||||
# in its unpromoted state.
|
||||
stop_master
|
||||
start_backup || return "$OCF_ERR_GENERIC"
|
||||
;;
|
||||
|
||||
"$OCF_NOT_RUNNING")
|
||||
start_backup || return "$OCF_ERR_GENERIC"
|
||||
;;
|
||||
|
||||
*)
|
||||
return "$OCF_ERR_GENERIC"
|
||||
;;
|
||||
esac
|
||||
|
||||
monitor_resource
|
||||
[ $? -eq "$OCF_SUCCESS" ] &&
|
||||
return "$OCF_SUCCESS"
|
||||
|
||||
return "$OCF_ERR_GENERIC"
|
||||
}
|
||||
|
||||
stop_resource()
|
||||
{
|
||||
stop_master
|
||||
stop_backup
|
||||
|
||||
monitor_resource
|
||||
rc=$?
|
||||
|
||||
[ "$rc" -eq "$OCF_NOT_RUNNING" ] &&
|
||||
return "$OCF_SUCCESS"
|
||||
|
||||
return "$OCF_ERR_GENERIC"
|
||||
}
|
||||
|
||||
promote_resource()
|
||||
{
|
||||
monitor_resource
|
||||
rc=$?
|
||||
|
||||
case "$rc" in
|
||||
"$OCF_RUNNING_PROMOTED")
|
||||
return "$OCF_SUCCESS"
|
||||
;;
|
||||
|
||||
"$OCF_SUCCESS")
|
||||
stop_backup
|
||||
|
||||
if ! start_master; then
|
||||
# Try to return to a safe unpromoted state.
|
||||
start_backup >/dev/null 2>&1 || true
|
||||
return "$OCF_ERR_GENERIC"
|
||||
fi
|
||||
;;
|
||||
|
||||
*)
|
||||
echo "ERROR: cannot promote IPVS sync resource from state rc=$rc" >&2
|
||||
return "$OCF_ERR_GENERIC"
|
||||
;;
|
||||
esac
|
||||
|
||||
monitor_resource
|
||||
[ $? -eq "$OCF_RUNNING_PROMOTED" ] &&
|
||||
return "$OCF_SUCCESS"
|
||||
|
||||
return "$OCF_ERR_GENERIC"
|
||||
}
|
||||
|
||||
demote_resource()
|
||||
{
|
||||
monitor_resource
|
||||
rc=$?
|
||||
|
||||
case "$rc" in
|
||||
"$OCF_SUCCESS")
|
||||
return "$OCF_SUCCESS"
|
||||
;;
|
||||
|
||||
"$OCF_RUNNING_PROMOTED")
|
||||
stop_master
|
||||
|
||||
if ! start_backup; then
|
||||
return "$OCF_ERR_GENERIC"
|
||||
fi
|
||||
;;
|
||||
|
||||
"$OCF_NOT_RUNNING")
|
||||
# Be defensive: demote should result in a running
|
||||
# unpromoted instance.
|
||||
start_backup || return "$OCF_ERR_GENERIC"
|
||||
;;
|
||||
|
||||
*)
|
||||
return "$OCF_ERR_GENERIC"
|
||||
;;
|
||||
esac
|
||||
|
||||
monitor_resource
|
||||
[ $? -eq "$OCF_SUCCESS" ] &&
|
||||
return "$OCF_SUCCESS"
|
||||
|
||||
return "$OCF_ERR_GENERIC"
|
||||
}
|
||||
|
||||
validate_all()
|
||||
{
|
||||
if [ ! -x "$IPVSADM" ]; then
|
||||
echo "ERROR: ipvsadm not found at $IPVSADM" >&2
|
||||
return "$OCF_ERR_INSTALLED"
|
||||
fi
|
||||
|
||||
if [ ! -x "$IP" ]; then
|
||||
echo "ERROR: ip command not found at $IP" >&2
|
||||
return "$OCF_ERR_INSTALLED"
|
||||
fi
|
||||
|
||||
iface="$(get_iface)"
|
||||
|
||||
if [ -z "$iface" ]; then
|
||||
echo "ERROR: unable to determine synchronization interface" >&2
|
||||
return "$OCF_ERR_ARGS"
|
||||
fi
|
||||
|
||||
if ! "$IP" link show dev "$iface" >/dev/null 2>&1; then
|
||||
echo "ERROR: interface '$iface' does not exist" >&2
|
||||
return "$OCF_ERR_ARGS"
|
||||
fi
|
||||
|
||||
return "$OCF_SUCCESS"
|
||||
}
|
||||
|
||||
case "$1" in
|
||||
meta-data)
|
||||
meta_data
|
||||
exit "$OCF_SUCCESS"
|
||||
;;
|
||||
|
||||
validate-all)
|
||||
validate_all
|
||||
exit $?
|
||||
;;
|
||||
|
||||
start)
|
||||
start_resource
|
||||
exit $?
|
||||
;;
|
||||
|
||||
stop)
|
||||
stop_resource
|
||||
exit $?
|
||||
;;
|
||||
|
||||
monitor|status)
|
||||
monitor_resource
|
||||
exit $?
|
||||
;;
|
||||
|
||||
promote)
|
||||
promote_resource
|
||||
exit $?
|
||||
;;
|
||||
|
||||
demote)
|
||||
demote_resource
|
||||
exit $?
|
||||
;;
|
||||
|
||||
*)
|
||||
echo "Usage: $0 {start|stop|monitor|promote|demote|validate-all|meta-data}" >&2
|
||||
exit "$OCF_ERR_UNIMPLEMENTED"
|
||||
;;
|
||||
esac
|
||||
Reference in New Issue
Block a user