#!/bin/sh # # Description: Manages a PostrgreSQL Server as an OCF High-Availability # resource under Heartbeat/LinuxHA control # # # Author: Serge Dubrouski (sergeyfd@gmail.com) # Copyright 2006 Serge Dubrouski # License: GNU General Public License (GPL) # # OCF parameters: # OCF_RESKEY_pgctl - Path to pg_ctl. Default /usr/bin/pg_ctl # OCF_RESKEY_start_opt - Startup options, options passed to postgress with -o # OCF_RESKEY_ctl_opt - Additional options for pg_ctl (-w, -W etc...) # OCF_RESKEY_psql - Path to psql. Default is /usr/bin/psql # OCF_RESKEY_pgdata - PGDATA directory. Default is /var/lib/pgsql/data # OCF_RESKEY_pgdba - userID that manages DB. Default is postgres # OCF_RESKEY_pghost - Host/IP Address where PostgreSQL is listening # OCF_RESKEY_pgport - Port where PostgreSQL is listening # OCF_RESKEY_pgdb - database to monitor. Default is template1 # OCF_RESKEY_logfile - Path to PostgreSQL log file. Default is /dev/null # OCF_RESKEY_stop_escalate - Stop waiting time. Default is 30 ############################################################################### # Initialization: . ${OCF_ROOT}/resource.d/heartbeat/.ocf-shellfuncs unset LC_ALL; export LC_ALL unset LANGUAGE; export LANGUAGE usage() { cat <<-! >&1 usage: $0 start|stop|status|monitor|meta-data|validate-all|methods $0 manages a PostgreSQL Server as an HA resource. The 'start' operation starts the PostgreSQL server. The 'stop' operation stops the PostgreSQL server. The 'status' operation reports whether the PostgreSQL is up. The 'monitor' operation reports whether the PostgreSQL is running. The 'validate-all' operation reports whether the parameters are valid. The 'methods' operation reports on the methods $0 supports. ! return $OCF_ERR_ARGS } meta_data() { cat < 1.0 Resource script for PostgreSQL. It manages a PostgreSQL as an HA resource. pgsql resource agent Path to pg_ctl command. pgctl Start options (-o start_opt in pgi_ctl). "-i -p 5432" for example. start_opt Additional pg_ctl options (-w, -W etc..). Default is "" ctl_opt Path to psql command. psql Path PostgreSQL data directory. pgdata User that owns PostgreSQL. pgdba Hostname/IP Addreess where PosrgeSQL is listening pghost Port where PosrgeSQL is listening pgport Database that will be used for monitoring. pgdb Path to PostgreSQL server log output file. logfile Number of retries (using -m fast) before resorting to -m immediate stop escalation END } # # Run the given command in the Resource owner environment... # runasowner() { su $OCF_RESKEY_pgdba -c "$*" } # # methods: What methods/operations do we support? # pgsql_methods() { cat <<-! start stop status monitor methods meta-data validate-all ! } #pgsql_start: Starts PostgreSQL pgsql_start() { if pgsql_status then ocf_log info "PostgreSQL is already running. PID=`cat $PIDFILE`" return $OCF_SUCCESS fi if [ -x $OCF_RESKEY_pgctl ] then # Remove postmastre.pid if it exists rm -f $PIDFILE # Check if we need to create a log file if ! check_log_file $OCF_RESKEY_logfile then ocf_log err "PostgreSQL can't write to the log file: $OCF_RESKEY_logfile" return $OCF_ERR_GENERIC fi if runasowner "$OCF_RESKEY_pgctl $OCF_RESKEY_ctl_opt -D $OCF_RESKEY_pgdata -l $OCF_RESKEY_logfile -o "\'$OCF_RESKEY_start_opt\'" start > /dev/null 2>&1" then # Probably started..... ocf_log info "PostgreSQL start command sent." else ocf_log err "Can't start PostgreSQL."; return $OCF_ERR_GENERIC fi else ocf_log err "$OCF_RESKEY_pgctl not found!" return $OCF_ERR_GENERIC fi rc=$OCF_ERR_GENERIC while [ $rc -ne 0 ]; do pgsql_monitor rc=$? sleep 1 ocf_log debug "PostgreSQL still hasn't started yet. Waiting..." done return $OCF_SUCCESS } #pgsql_stop: Stop PostgreSQL pgsql_stop() { if ! pgsql_status then #Already stopped return $OCF_SUCCESS fi # Stop PostgreSQL do not wait for clients to disconnect runasowner "$OCF_RESKEY_pgctl -D $OCF_RESKEY_pgdata stop -m fast > /dev/null 2>&1" # stop waiting count=0 while [ $count -lt $OCF_RESKEY_stop_escalate ] do if ! pgsql_status then #PostgreSQL stopped break; fi count=`expr $count + 1` sleep 1 done if pgsql_status then #PostgreSQL is still up. Use another shutdown mode. ocf_log info "PostgreSQL failed to stop after ${OCF_RESKEY_stop_escalate}s using -m fast. Trying -m immediate..." runasowner "$OCF_RESKEY_pgctl -D $OCF_RESKEY_pgdata stop -m immediate > /dev/null 2>&1" fi rc=$OCF_ERR_GENERIC while [ $rc != $OCF_NOT_RUNNING ]; do pgsql_monitor rc=$? sleep 1 ocf_log debug "PostgreSQL still hasn't stopped yet. Waiting..." done # Remove postmastre.pid if it exists rm -f $PIDFILE return $OCF_SUCCESS } # # pgsql_status: is PostgreSQL up? # pgsql_status() { if [ -f $PIDFILE ] then PID=`head -n 1 $PIDFILE` kill -0 $PID >/dev/null 2>&1 && fuser $OCF_RESKEY_pgdata 2>&1 | grep $PID >/dev/null 2>&1 return $? fi # No PID file false } # # pgsql_monitor # pgsql_monitor() { if ! pgsql_status then ocf_log info "PostgreSQL is down" return $OCF_NOT_RUNNING fi if [ "x" = "x$OCF_RESKEY_pghost" ] then runasowner "$OCF_RESKEY_psql -p $OCF_RESKEY_pgport -U $OCF_RESKEY_pgdba $OCF_RESKEY_pgdb -c 'select now();' >/dev/null 2>&1" else runasowner "$OCF_RESKEY_psql -h $OCF_RESKEY_pghost -p $OCF_RESKEY_pgport -U $OCF_RESKEY_pgdba $OCF_RESKEY_pgdb -c 'select now();' >/dev/null 2>&1" fi if [ $? -ne 0 ] then ocf_log err "PostgreSQL $OCF_RESKEY_pgdb isn't running" return $OCF_ERR_GENERIC fi return $OCF_SUCCESS } # Validate most critical parameters pgsql_validate_all() { if ! have_binary $SH then return $OCF_ERR_INSTALLED fi if ! have_binary $OCF_RESKEY_pgctl then return $OCF_ERR_INSTALLED fi if ! have_binary $OCF_RESKEY_psql then return $OCF_ERR_INSTALLED fi return $OCF_SUCCESS } # # Check if we need to create a log file # check_log_file() { if [ ! -f "$1" ] then touch $1 > /dev/null 2>&1 chown $OCF_RESKEY_pgdba:$(getent passwd $OCF_RESKEY_pgdba | cut -d ":" -f 4) $1 fi #Check if $OCF_RESKEY_pgdba can write to the log file if ! runasowner "test -w $1" then return 1 fi return 0 } # # 'main' starts here... # if [ $# -ne 1 ] then usage exit $OCF_ERR_GENERIC fi : ${OCF_RESKEY_pgctl=/usr/bin/pg_ctl} : ${OCF_RESKEY_psql=/usr/bin/psql} : ${OCF_RESKEY_pgdata=/var/lib/pgsql/data} : ${OCF_RESKEY_pgdba=postgres} : ${OCF_RESKEY_pgport=5432} : ${OCF_RESKEY_start_opt="-p $OCF_RESKEY_pgport"} : ${OCF_RESKEY_pgdb=template1} : ${OCF_RESKEY_logfile=/dev/null} : ${OCF_RESKEY_stop_escalate=30} PIDFILE=${OCF_RESKEY_pgdata}/postmaster.pid case "$1" in methods) pgsql_methods exit $?;; meta-data) meta_data exit $OCF_SUCCESS;; validate-all) pgsql_validate_all exit $?;; esac if ! pgsql_validate_all then case "$1" in stop) exit $OCF_SUCCESS;; monitor) exit $OCF_NOT_RUNNING;; status) exit $OCF_NOT_RUNNING;; *) exit $OCF_ERR_INSTALLED;; esac fi US=`id -u -n` if [ $US != root -a $US != $OCF_RESKEY_pgdba ] then ocf_log err "$0 must be run as root or $OCF_RESKEY_pgdba" exit $OCF_ERR_GENERIC fi # What kind of method was invoked? case "$1" in status) if pgsql_status then ocf_log info "PostgreSQL is up" exit $OCF_SUCCESS else ocf_log info "PostgreSQL is down" exit $OCF_NOT_RUNNING fi;; monitor) pgsql_monitor exit $?;; start) pgsql_start exit $?;; stop) pgsql_stop exit $?;; esac usage