Add daemon-selected container monitor delegation

This commit is contained in:
Lyncoln
2026-09-18 14:09:46 -04:00
parent 3937de82dc
commit cbb865729a
6 changed files with 411 additions and 0 deletions
+174
View File
@@ -0,0 +1,174 @@
#!/usr/bin/env bash
set -u
OCF_SUCCESS=0
OCF_ERR_GENERIC=1
OCF_NOT_RUNNING=7
OCF_RUNNING_PROMOTED=8
MC_PROXY_RC_TRANSPORT=10
MC_PROXY_RC_HARD_FAILURE=11
OCF_RESOURCE_INSTANCE=postgresql-ha
OCF_RESKEY_container_runtime=podman
logs=()
exit_reason=""
score=""
cache_rc=""
application_rc=0
application_calls=0
proxy_result_value="delegate|container|podman"
# Load the real function under test first. Test doubles defined below then
# override its external dependencies, including promotion-score helpers.
source ocf/loxthelion/managed-container.d/common.sh
ocf_log()
{
logs+=("$*")
}
ocf_exit_reason()
{
exit_reason="$*"
}
mc_proxy_monitor()
{
printf '%s\n' "${proxy_result_value}"
return 0
}
mc_proxy_cached_monitor()
{
return 1
}
mc_proxy_monitor_cache_clear()
{
cache_rc="cleared"
return 0
}
mc_proxy_monitor_cache_write()
{
cache_rc="$1"
return 0
}
mc_proxy_legacy_shadow_monitor()
{
echo "ERROR: shadow monitor must not execute for delegation" >&2
return 99
}
mc_application_monitor()
{
application_calls=$((application_calls + 1))
return "${application_rc}"
}
mc_promotion_score_set()
{
score="$1"
return 0
}
mc_promotion_score_from_monitor()
{
case "$1" in
0|8)
score="healthy:$1"
;;
*)
score="-INFINITY"
;;
esac
return 0
}
echo "===== PODMAN DELEGATION SUCCESS ====="
application_rc=0
proxy_result_value="delegate|container|podman"
cache_rc=""
score=""
application_calls=0
mc_promotion_monitor
rc=$?
[ "$rc" -eq 0 ]
[ "$application_calls" -eq 1 ]
[ "$cache_rc" = 0 ]
[ "$score" = "healthy:0" ]
echo "podman_success accepted"
echo
echo "===== PROMOTED DELEGATION ====="
application_rc=8
proxy_result_value="delegate|container|podman"
cache_rc=""
score=""
application_calls=0
mc_promotion_monitor
rc=$?
[ "$rc" -eq 8 ]
[ "$application_calls" -eq 1 ]
[ "$cache_rc" = 8 ]
[ "$score" = "healthy:8" ]
echo "podman_promoted accepted"
echo
echo "===== RUNTIME MISMATCH ====="
application_rc=0
proxy_result_value="delegate|container|docker"
cache_rc=""
score=""
application_calls=0
mc_promotion_monitor
rc=$?
[ "$rc" -eq 1 ]
[ "$application_calls" -eq 0 ]
[ "$cache_rc" = "cleared" ]
[ "$score" = "-INFINITY" ]
echo "runtime_mismatch rejected"
echo
echo "===== MALFORMED DELEGATION ====="
proxy_result_value="delegate|container|podman|extra"
cache_rc=""
score=""
application_calls=0
mc_promotion_monitor
rc=$?
[ "$rc" -eq 1 ]
[ "$application_calls" -eq 0 ]
[ "$cache_rc" = "cleared" ]
[ "$score" = "-INFINITY" ]
echo "malformed_delegation rejected"
echo
echo "MONITOR_DELEGATION_SHELL_TEST_PASS=1"
+139
View File
@@ -0,0 +1,139 @@
#!/usr/bin/env python3
import importlib.util
from pathlib import Path
spec = importlib.util.spec_from_file_location(
"proxy_client",
Path(
"ocf/loxthelion/"
"managed-container.d/"
"proxy_client.py"
),
)
proxy = importlib.util.module_from_spec(spec)
spec.loader.exec_module(proxy)
print("===== NORMAL API MONITOR RESULT =====")
normal = {
"ha": {
"ocf_rc": 0,
"health": "healthy",
"ha_role": "unpromoted",
"state": "streaming",
"promotion_eligible": True,
},
"role": "standby",
"streaming": True,
"wal_receiver": {
"slot_name": "ha_pg_node1",
"sender_host": "192.0.2.10",
},
}
formatted = proxy.format_monitor_result(normal)
expected = (
"0|healthy|unpromoted|streaming|true|"
"standby|true|ha_pg_node1|192.0.2.10"
)
assert formatted == expected, formatted
print("api_monitor_format accepted")
print()
print("===== PODMAN DELEGATION =====")
delegated = {
"delegated": True,
"backend": "container",
"container_runtime": "podman",
}
formatted = proxy.format_monitor_result(delegated)
assert formatted == "delegate|container|podman", formatted
print("podman_delegation accepted")
print()
print("===== DOCKER DELEGATION =====")
delegated = {
"delegated": True,
"backend": "container",
"container_runtime": "docker",
}
formatted = proxy.format_monitor_result(delegated)
assert formatted == "delegate|container|docker", formatted
print("docker_delegation accepted")
print()
print("===== INVALID DELEGATED BACKEND =====")
bad = {
"delegated": True,
"backend": "api",
"container_runtime": "podman",
}
try:
proxy.format_monitor_result(bad)
except proxy.ProtocolFailure:
print("invalid_backend rejected")
else:
raise AssertionError(
"delegation with non-container backend was accepted"
)
print()
print("===== INVALID DELEGATED RUNTIME =====")
bad = {
"delegated": True,
"backend": "container",
"container_runtime": "lxc",
}
try:
proxy.format_monitor_result(bad)
except proxy.ProtocolFailure:
print("invalid_runtime rejected")
else:
raise AssertionError(
"delegation with invalid runtime was accepted"
)
print()
print("===== MALFORMED DELEGATION =====")
bad = {
"delegated": True,
"backend": "container",
}
try:
proxy.format_monitor_result(bad)
except proxy.ProtocolFailure:
print("missing_runtime rejected")
else:
raise AssertionError(
"delegation without runtime was accepted"
)
print()
print("PROXY_MONITOR_DELEGATION_TEST_PASS=1")
+8
View File
@@ -150,6 +150,13 @@ with conn:
elif mode == "bad_rc":
response["result"]["ha"]["ocf_rc"] = 42
elif mode == "delegate":
response["result"] = {
"delegated": True,
"backend": "container",
"container_runtime": "podman",
}
conn.sendall(
json.dumps(response).encode("utf-8") + b"\n"
)
@@ -248,6 +255,7 @@ PY_REFUSED
echo "===== PROXY PROTOCOL CLASSIFICATION ====="
run_case valid valid 0
run_case delegation delegate 0
run_case missing_protocol missing_protocol 11
run_case wrong_protocol wrong_protocol 11
run_case wrong_resource wrong_resource 11