Initial managed-container HA resource agent baseline
This commit is contained in:
Executable
+209
@@ -0,0 +1,209 @@
|
||||
# Shared OCF scoring wrappers; application policy is supplied by the plugin.
|
||||
|
||||
# Promotion scores are scoped by Pacemaker to OCF_RESOURCE_INSTANCE and the
|
||||
# executing node. Do not construct a legacy attribute name or cache locally:
|
||||
# querying attrd on every observation also repairs a lost transient attribute.
|
||||
mc_promotion_score_set()
|
||||
{
|
||||
local score="$1" current
|
||||
local resource="${MC_PROMOTION_RESOURCE_INSTANCE:-}"
|
||||
|
||||
if [ -z "${resource}" ]; then
|
||||
ocf_log warn "Cannot publish promotion score without OCF_RESOURCE_INSTANCE"
|
||||
return 1
|
||||
fi
|
||||
|
||||
case "${score}" in
|
||||
1000|100|50|-INFINITY) ;;
|
||||
*) return 1 ;;
|
||||
esac
|
||||
|
||||
current="$(
|
||||
timeout --kill-after=1s 2s crm_attribute \
|
||||
--promotion="${resource}" --lifetime=reboot \
|
||||
--query --quiet 2>/dev/null
|
||||
)" || current=""
|
||||
|
||||
[ "${current}" = "${score}" ] && return 0
|
||||
|
||||
if ! timeout --kill-after=1s 2s crm_attribute \
|
||||
--promotion="${resource}" --lifetime=reboot \
|
||||
--update="${score}" >/dev/null 2>&1
|
||||
then
|
||||
ocf_log err "Unable to publish promotion score ${score} for ${resource}; prior score may remain"
|
||||
return 1
|
||||
fi
|
||||
return 0
|
||||
}
|
||||
|
||||
mc_promotion_score_from_monitor()
|
||||
{
|
||||
local monitor_rc="$1" score=-INFINITY
|
||||
|
||||
case "${monitor_rc}" in
|
||||
"${OCF_RUNNING_PROMOTED}") score=1000 ;;
|
||||
"${OCF_SUCCESS}")
|
||||
score="$(mc_application_standby_score)" || score=-INFINITY
|
||||
;;
|
||||
esac
|
||||
case "${score}" in
|
||||
1000|100|50|-INFINITY) ;;
|
||||
*) score=-INFINITY ;;
|
||||
esac
|
||||
mc_promotion_score_set "${score}"
|
||||
}
|
||||
|
||||
# managed-containerd is authoritative for recurring monitor/status results.
|
||||
# The legacy application monitor remains temporarily available as a shadow
|
||||
# comparison only. Promotion scoring is still supplied by the existing
|
||||
# application scoring hook during this migration stage.
|
||||
mc_promotion_monitor()
|
||||
{
|
||||
local monitor_rc legacy_rc proxy_result proxy_rc cached_rc
|
||||
|
||||
proxy_result="$(mc_proxy_monitor)"
|
||||
proxy_rc=$?
|
||||
|
||||
if [ "${proxy_rc}" -ne 0 ]; then
|
||||
|
||||
case "${proxy_rc}" in
|
||||
"${MC_PROXY_RC_TRANSPORT}")
|
||||
# Transport loss is a control-plane failure, not proof that
|
||||
# the managed application itself has failed.
|
||||
cached_rc="$(mc_proxy_cached_monitor 2>/dev/null)" || cached_rc=""
|
||||
|
||||
if [ -n "${cached_rc}" ]; then
|
||||
monitor_rc="${cached_rc}"
|
||||
|
||||
case "${monitor_rc}" in
|
||||
"${OCF_SUCCESS}")
|
||||
# A standby with an unavailable control plane must
|
||||
# never remain promotion-eligible during grace.
|
||||
mc_promotion_score_set -INFINITY || true
|
||||
;;
|
||||
|
||||
"${OCF_RUNNING_PROMOTED}")
|
||||
# Preserve the established primary during a brief
|
||||
# bounded transport outage.
|
||||
;;
|
||||
esac
|
||||
|
||||
ocf_log warn \
|
||||
"managed-containerd unavailable; using recent cached authoritative rc=${monitor_rc} for bounded control-plane grace"
|
||||
|
||||
mc_application_monitor
|
||||
legacy_rc=$?
|
||||
|
||||
mc_proxy_legacy_shadow_monitor \
|
||||
"${monitor_rc}" \
|
||||
"${legacy_rc}" || true
|
||||
|
||||
return "${monitor_rc}"
|
||||
fi
|
||||
|
||||
mc_promotion_score_set -INFINITY || true
|
||||
ocf_exit_reason \
|
||||
"managed-containerd authoritative monitor transport failure and no valid control-plane grace observation exists"
|
||||
return "${OCF_ERR_GENERIC}"
|
||||
;;
|
||||
|
||||
*)
|
||||
# Protocol/result/configuration/client failures are hard.
|
||||
# Never conceal them behind cached authoritative health.
|
||||
mc_proxy_monitor_cache_clear || true
|
||||
mc_promotion_score_set -INFINITY || true
|
||||
ocf_exit_reason \
|
||||
"managed-containerd authoritative monitor hard failure; cached grace is not permitted"
|
||||
return "${OCF_ERR_GENERIC}"
|
||||
;;
|
||||
esac
|
||||
fi
|
||||
|
||||
monitor_rc="${proxy_result%%|*}"
|
||||
|
||||
case "${monitor_rc}" in
|
||||
"${OCF_SUCCESS}"|\
|
||||
"${OCF_ERR_GENERIC}"|\
|
||||
"${OCF_NOT_RUNNING}"|\
|
||||
"${OCF_RUNNING_PROMOTED}")
|
||||
;;
|
||||
*)
|
||||
mc_promotion_score_set -INFINITY || true
|
||||
ocf_exit_reason "managed-containerd returned invalid monitor rc ${monitor_rc}"
|
||||
return "${OCF_ERR_GENERIC}"
|
||||
;;
|
||||
esac
|
||||
|
||||
ocf_log info "managed-containerd authoritative monitor: resource=${OCF_RESOURCE_INSTANCE:-unknown} proxy=${proxy_result}"
|
||||
|
||||
# Legacy PostgreSQL monitoring remains observational only.
|
||||
mc_application_monitor
|
||||
legacy_rc=$?
|
||||
|
||||
mc_proxy_legacy_shadow_monitor "${monitor_rc}" "${legacy_rc}" || true
|
||||
|
||||
mc_promotion_score_from_monitor "${monitor_rc}" || true
|
||||
return "${monitor_rc}"
|
||||
}
|
||||
|
||||
# Lifecycle functions retain their original checks, commands and return codes.
|
||||
# Withdraw the previous score before any transition (including validation
|
||||
# failure), then reassess only after success. Their internal monitor calls do
|
||||
# not publish scores, so they cannot restore a positive score mid-transition.
|
||||
mc_promotion_action()
|
||||
{
|
||||
local action="$1" action_rc monitor_rc
|
||||
|
||||
case "${action}" in
|
||||
start|stop|promote|demote|rejoin) ;;
|
||||
*) return "${OCF_ERR_UNIMPLEMENTED}" ;;
|
||||
esac
|
||||
|
||||
# Any lifecycle mutation invalidates the previous daemon-observed role.
|
||||
# A fresh daemon monitor must establish the next cache entry.
|
||||
mc_proxy_monitor_cache_clear
|
||||
|
||||
mc_promotion_score_set -INFINITY || true
|
||||
if [ "${action}" != stop ]; then
|
||||
mc_promotion_validate
|
||||
action_rc=$?
|
||||
[ "${action_rc}" -eq "${OCF_SUCCESS}" ] || return "${action_rc}"
|
||||
fi
|
||||
|
||||
mc_application_action "${action}"
|
||||
action_rc=$?
|
||||
if [ "${action_rc}" -eq "${OCF_SUCCESS}" ] && [ "${action}" != stop ]; then
|
||||
mc_application_monitor
|
||||
monitor_rc=$?
|
||||
mc_promotion_score_from_monitor "${monitor_rc}" || true
|
||||
fi
|
||||
return "${action_rc}"
|
||||
}
|
||||
|
||||
mc_promotion_validate()
|
||||
{
|
||||
local utility
|
||||
|
||||
if ! [[ "${OCF_RESKEY_proxy_failure_grace_seconds:-15}" =~ ^(0|[1-9][0-9]{0,2})$ ]]; then
|
||||
ocf_exit_reason "proxy_failure_grace_seconds must be an integer from 0 to 999 seconds"
|
||||
return "${OCF_ERR_CONFIGURED}"
|
||||
fi
|
||||
|
||||
if [ "${OCF_RESKEY_proxy_failure_grace_seconds:-15}" -gt 300 ]; then
|
||||
ocf_exit_reason "proxy_failure_grace_seconds must be between 0 and 300 seconds"
|
||||
return "${OCF_ERR_CONFIGURED}"
|
||||
fi
|
||||
|
||||
if ! [[ "${OCF_RESKEY_disconnected_max_age:-300}" =~ ^(0|[1-9][0-9]{0,4})$ ]]; then
|
||||
ocf_exit_reason "disconnected_max_age must be an integer from 0 to 99999 seconds"
|
||||
return "${OCF_ERR_CONFIGURED}"
|
||||
fi
|
||||
|
||||
for utility in crm_attribute timeout python3; do
|
||||
if ! command -v "${utility}" >/dev/null 2>&1; then
|
||||
ocf_exit_reason "Required promotion scoring command '${utility}' is not installed"
|
||||
return "${OCF_ERR_INSTALLED}"
|
||||
fi
|
||||
done
|
||||
mc_application_validate
|
||||
}
|
||||
Reference in New Issue
Block a user