diff --git a/checksums/SHA256SUMS b/checksums/SHA256SUMS index c1e207a..695e3a9 100644 --- a/checksums/SHA256SUMS +++ b/checksums/SHA256SUMS @@ -7,7 +7,7 @@ bcfde96b98f4727a8c97d42a39b7c6ec925b1b89d17ef67cc58eb7bd67afbfae ocf/loxthelion 957a5a72ed277d0216e070abb80733483be3d421b9fa488e27fdd75bb2919548 ocf/loxthelion/managed-container.d/applications/postgresql/peer_config.sh 99bb3478931eced9471a8f054c14d152780aec73801449d1a6b2f09a4b656bec ocf/loxthelion/managed-container.d/applications/postgresql/plugin.sh c1d878dabf22ad3928d66a5542bda3c150e5e9b039926629e7c5fd3401d29be4 ocf/loxthelion/managed-container.d/applications/postgresql/postgres.sh -f482853a0c7992981e59b4ad78d1ee69851d5d60fdec1f695673228017dd8244 ocf/loxthelion/managed-container.d/applications/postgresql/promote.sh +78b32fd6354bec61375ee73a31898059b21d51949a906cc6c7f23419a79670d6 ocf/loxthelion/managed-container.d/applications/postgresql/promote.sh 5166fc3370f49ab14cd975ded4b03a74b9bd7dbff5762b41a15552c42f934ea7 ocf/loxthelion/managed-container.d/applications/postgresql/promotion_state.py b0ebad749ed736f08ec748a693f12e8dc2541430e0d3db75bbb6b2b7e517f84b ocf/loxthelion/managed-container.d/applications/postgresql/rejoin.sh 0d3017fdca92b2dc5dba406065bc269622ce5140e3fce4a959ca95ce4a78e755 ocf/loxthelion/managed-container.d/applications/postgresql/replication.sh @@ -23,13 +23,14 @@ a42bb59a058ffeb59c1baa96e403856910bbbaea98f9104ff93daf4b5970c780 postgres-host/ 957a5a72ed277d0216e070abb80733483be3d421b9fa488e27fdd75bb2919548 postgres-host/postgres-ha-peer-config.sh deb09e3ae40629f43b262ba4f9a7ebf59a1dca3da9d8c94478f670aea28bd0e1 quadlet/postgres.container 04a125068677bbee6e71d313ca9d95d35faa32851b79de781cd7b9f466561445 quadlet/postgres.env.example -a4bedb1c423294e4cafe4c93e9daff3d2b774a8f8e4a6b989322acbc2b842a04 tests/run-all.sh +ac72a62381a686dbc7dcebf2f81bd3f96e84e83ba63ff956440546a8026037fb tests/run-all.sh a373c0560391a2d8f63c3ba31609ab16b219d9b532b4ab9f8aea6dc45de10555 tests/test-demote-database-gate.sh 688eeb756c7f346e7e55acc555004ba12b48bc7c3d309073658d5e84a6e5e348 tests/test-demote-database-parameter.sh 22d3eb56e8cd3ae1a58e2616f44abd3818f79d7e5df55c1c158e36dca7c77f42 tests/test-demote-database-shadow.sh 5e5d4fdd2b6c7e0b8b146de7aad06c1f96b221a10fec525b00d40e0d85709fb0 tests/test-entrypoint-structure.sh 2faee72cf2fdcbfa667c3e1c2a7aabc053b96a9b8127ff7440ddb717fd2dc314 tests/test-notify-daemon-shadow.sh 9150004af86a819d7d1b5ae2b3fa9d4ddd0480f55babd094137052109864b057 tests/test-notify-target-shadow.sh +dd7ad3d1c06cac922c026b6bc30db5a5e66aa5d82948ebed983384c7b0bbba33 tests/test-promote-database-shadow.sh b83f0415c09f0be34c51722370e5b07c51b9a9756d305d3b3f50827f484aa4dd tests/test-proxy-client-actions.py cc4482d229805c64d7df258a8a82984f244128d27fff4ea43b36caa004b56bef tests/test-proxy-client-parameters.py c3b988d7b2b1b138bb2530df9172f96bb0f5edc2f1561f38f0055695f4126134 tests/test-proxy-protocol.sh diff --git a/ocf/loxthelion/managed-container.d/applications/postgresql/promote.sh b/ocf/loxthelion/managed-container.d/applications/postgresql/promote.sh index 0068a6f..a38b57e 100644 --- a/ocf/loxthelion/managed-container.d/applications/postgresql/promote.sh +++ b/ocf/loxthelion/managed-container.d/applications/postgresql/promote.sh @@ -1,5 +1,63 @@ # Sourced by managed-container; uses the shared OCF and parameter environment. +mc_pg_promote_database_shadow() +{ + local socket_path resource response rc + + socket_path="${MC_PROXY_SOCKET:-/run/user/1000/managed-containerd/managed-containerd.sock}" + resource="${OCF_RESOURCE_INSTANCE:-}" + resource="${resource%%:*}" + + # Standalone/resource-agent tests may not have a real resource identity. + [ -n "${resource}" ] || return 0 + + if response="$( + timeout --kill-after=1s 5s \ + python3 \ + "${MC_PROXY_CLIENT:-/usr/lib/ocf/resource.d/loxthelion/managed-container.d/proxy_client.py}" \ + "${socket_path}" \ + "${resource}" \ + "promote.database" \ + 10 \ + 11 + )"; then + rc=0 + else + rc=$? + fi + + if [ "${rc}" -ne 0 ]; then + ocf_log warn \ + "managed-containerd promote.database shadow unavailable rc=${rc}" + return 0 + fi + + if MC_DAEMON_RESPONSE="${response}" python3 -c ' +import json +import os + +response = json.loads(os.environ["MC_DAEMON_RESPONSE"]) + +if ( + response.get("ocf_rc") != 0 + or response.get("ready") is not True + or response.get("mutation") is not False +): + raise SystemExit(1) +'; then + ocf_log info \ + "managed-containerd promote.database shadow: comparison=MATCH response=${response}" + else + ocf_log err \ + "managed-containerd promote.database shadow MISMATCH response=${response}" + fi + + # Shadow-only milestone: daemon disagreement must not alter the + # authoritative native promotion result yet. + return 0 +} + + managed_promote() { local monitor_rc role i @@ -58,6 +116,11 @@ managed_promote() ocf_log info \ "Promoting PostgreSQL standby inside ${CONTAINER_NAME}" + # Independent managed-containerd promotion preflight. + # Shadow-only for now: disagreement is logged but does not block + # the authoritative native PostgreSQL promotion. + mc_pg_promote_database_shadow + if ! pg_command ' BINDIR="$(pg_config --bindir)" || exit 1 exec "$BINDIR/pg_ctl" \ diff --git a/tests/run-all.sh b/tests/run-all.sh index 175c6ed..cd8fc2d 100755 --- a/tests/run-all.sh +++ b/tests/run-all.sh @@ -27,6 +27,7 @@ python3 ./tests/test-proxy-client-parameters.py ./tests/test-notify-daemon-shadow.sh ./tests/test-notify-target-shadow.sh ./tests/test-demote-database-shadow.sh +./tests/test-promote-database-shadow.sh ./tests/test-demote-database-gate.sh ./tests/test-demote-database-parameter.sh diff --git a/tests/test-promote-database-shadow.sh b/tests/test-promote-database-shadow.sh new file mode 100755 index 0000000..2c2d772 --- /dev/null +++ b/tests/test-promote-database-shadow.sh @@ -0,0 +1,30 @@ +#!/usr/bin/env bash +set -euo pipefail + +ROOT="$(CDPATH= cd -- "$(dirname -- "$0")/.." && pwd)" +FILE="$ROOT/ocf/loxthelion/managed-container.d/applications/postgresql/promote.sh" + +grep -q '^mc_pg_promote_database_shadow()' "$FILE" +grep -q '"promote.database"' "$FILE" +grep -q 'response.get("ready") is not True' "$FILE" +grep -q 'response.get("mutation") is not False' "$FILE" +grep -q 'comparison=MATCH' "$FILE" +grep -q 'promote.database shadow MISMATCH' "$FILE" + +SHADOW_LINE="$( + grep -n '^[[:space:]]*mc_pg_promote_database_shadow$' "$FILE" | + tail -1 | + cut -d: -f1 +)" + +PROMOTE_LINE="$( + grep -n 'exec "\$BINDIR/pg_ctl"' "$FILE" | + head -1 | + cut -d: -f1 +)" + +[ -n "$SHADOW_LINE" ] +[ -n "$PROMOTE_LINE" ] +[ "$SHADOW_LINE" -lt "$PROMOTE_LINE" ] + +echo "PROMOTE_DATABASE_SHADOW_TEST_PASS=1"