# Sourced by managed-container; uses the shared OCF and parameter environment. pg_command() { local command="$1" as_service_user \ podman exec \ --user "${PG_OS_USER}" \ "${CONTAINER_NAME}" \ sh -c "${command}" } pgdata_path() { pg_command ' if [ -z "$PGDATA" ]; then exit 1 fi printf "%s\n" "$PGDATA" ' } pg_running() { pg_command ' BINDIR="$(pg_config --bindir)" || exit 1 "$BINDIR/pg_ctl" status -D "$PGDATA" >/dev/null 2>&1 ' } pg_ready() { as_service_user \ podman exec \ --user "${PG_OS_USER}" \ "${CONTAINER_NAME}" \ pg_isready -q \ -U "${DB_USER}" \ -d "${DB_NAME}" } pg_role() { as_service_user \ podman exec \ --user "${PG_OS_USER}" \ "${CONTAINER_NAME}" \ psql \ -U "${DB_USER}" \ -d "${DB_NAME}" \ -Atqc 'SELECT pg_is_in_recovery();' } pg_wal_receiver_status() { as_service_user \ podman exec \ --user "${PG_OS_USER}" \ "${CONTAINER_NAME}" \ psql \ -U "${DB_USER}" \ -d "${DB_NAME}" \ -Atqc "SELECT status FROM pg_stat_wal_receiver LIMIT 1;" } managed_monitor() { local role if ! service_running; then ocf_log debug "User service ${SERVICE_NAME} is not active" return "${OCF_NOT_RUNNING}" fi if ! container_running; then ocf_log warn \ "Service ${SERVICE_NAME} is active but container ${CONTAINER_NAME} is not running" return "${OCF_NOT_RUNNING}" fi if ! pg_running; then ocf_log debug \ "Container ${CONTAINER_NAME} is running but PostgreSQL is stopped" return "${OCF_NOT_RUNNING}" fi if ! pg_ready; then ocf_exit_reason \ "PostgreSQL process exists but pg_isready failed" return "${OCF_ERR_GENERIC}" fi role="$(pg_role 2>/dev/null)" || { ocf_exit_reason \ "PostgreSQL is accepting connections but role query failed" return "${OCF_ERR_GENERIC}" } case "${role}" in f) ocf_log debug \ "PostgreSQL healthy: role=primary (promoted)" return "${OCF_RUNNING_PROMOTED}" ;; t) ocf_log debug \ "PostgreSQL healthy: role=standby (unpromoted)" return "${OCF_SUCCESS}" ;; *) ocf_exit_reason \ "Unexpected pg_is_in_recovery() result: '${role}'" return "${OCF_ERR_GENERIC}" ;; esac } managed_start() { local i monitor_rc managed_monitor monitor_rc=$? case "${monitor_rc}" in "${OCF_SUCCESS}") ocf_log info \ "PostgreSQL resource already running unpromoted" return "${OCF_SUCCESS}" ;; "${OCF_RUNNING_PROMOTED}") ocf_exit_reason \ "Refusing start: PostgreSQL is already primary; promotion must occur through promote()" return "${OCF_ERR_GENERIC}" ;; "${OCF_NOT_RUNNING}") # Expected for a stopped resource. Continue. ;; *) ocf_exit_reason \ "Cannot start unhealthy PostgreSQL instance (monitor rc=${monitor_rc})" return "${monitor_rc}" ;; esac ocf_log info \ "Ensuring container service ${SERVICE_NAME} is running" if ! service_running; then if ! as_service_user \ systemctl --user start "${SERVICE_NAME}" then ocf_exit_reason \ "Failed to start ${SERVICE_NAME}" return "${OCF_ERR_GENERIC}" fi fi for i in $(seq 1 20); do container_running && break sleep 0.5 done if ! container_running; then ocf_exit_reason \ "Container ${CONTAINER_NAME} did not become running" return "${OCF_ERR_GENERIC}" fi if ! pg_running; then # # OCF promotable-resource rule: # start() must produce an Unpromoted instance. # # A PostgreSQL data directory without standby.signal would start # writable/primary, so never start it from this action. # if ! pg_command ' test -f "$PGDATA/standby.signal" ' then ocf_exit_reason \ "Refusing start: PGDATA is not configured as a standby (standby.signal missing)" return "${OCF_ERR_GENERIC}" fi ocf_log info \ "Starting PostgreSQL as an unpromoted standby inside ${CONTAINER_NAME}" if ! pg_command ' BINDIR="$(pg_config --bindir)" || exit 1 exec "$BINDIR/pg_ctl" \ -D "$PGDATA" \ -l "$PGDATA/postgresql.log" \ start -w ' then ocf_exit_reason "pg_ctl start failed" return "${OCF_ERR_GENERIC}" fi fi managed_monitor monitor_rc=$? case "${monitor_rc}" in "${OCF_SUCCESS}") ocf_log info \ "PostgreSQL start completed in unpromoted state" return "${OCF_SUCCESS}" ;; "${OCF_RUNNING_PROMOTED}") ocf_exit_reason \ "PostgreSQL became primary during start; stopping it to preserve OCF role semantics" pg_command ' BINDIR="$(pg_config --bindir)" || exit 1 exec "$BINDIR/pg_ctl" \ -D "$PGDATA" \ stop -m fast -w ' >/dev/null 2>&1 || true return "${OCF_ERR_GENERIC}" ;; *) return "${monitor_rc}" ;; esac } managed_stop() { local i if container_running && pg_running; then ocf_log info \ "Stopping PostgreSQL cleanly inside ${CONTAINER_NAME}" if ! pg_command ' BINDIR="$(pg_config --bindir)" || exit 1 exec "$BINDIR/pg_ctl" \ -D "$PGDATA" \ stop -m fast -w ' then ocf_exit_reason "pg_ctl stop failed" return "${OCF_ERR_GENERIC}" fi fi if service_running; then ocf_log info \ "Stopping container service ${SERVICE_NAME}" if ! as_service_user \ systemctl --user stop "${SERVICE_NAME}" then ocf_exit_reason \ "Failed to stop ${SERVICE_NAME}" return "${OCF_ERR_GENERIC}" fi fi for i in $(seq 1 20); do if ! service_running && ! container_running; then return "${OCF_SUCCESS}" fi sleep 0.5 done if service_running; then ocf_exit_reason \ "${SERVICE_NAME} remained active after stop" return "${OCF_ERR_GENERIC}" fi if container_running; then ocf_exit_reason \ "${CONTAINER_NAME} remained running after stop" return "${OCF_ERR_GENERIC}" fi return "${OCF_SUCCESS}" }