Extract PostgreSQL, Podman runtime and systemd lifecycle adapters while preserving existing lifecycle and scoring behavior. Update RPM layout and add guarded operator-run lab harnesses. Record successful manual stop/start, promotion, demotion and rewind-only rejoin with pinned installed hashes. The unfenced lab does not validate automatic failover, Pacemaker-managed transitions or divergent-data rewind. Validation: 103 offline tests, original-function differential checks, checksum manifest and whitespace checks passed.
114 lines
3.4 KiB
Bash
114 lines
3.4 KiB
Bash
# 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}"
|
|
}
|
|
|
|
# Score publication must not change OCF role detection or its return code.
|
|
mc_promotion_monitor()
|
|
{
|
|
local monitor_rc
|
|
|
|
mc_application_monitor
|
|
monitor_rc=$?
|
|
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
|
|
|
|
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_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
|
|
}
|