#!/bin/sh # # Resource script for Postfix # # Description: Manages Postfix as an OCF resource in # an high-availability setup. # # Author: Raoul Bhatia : Original Author # License: GNU General Public License (GPL) # Note: If you want to run multiple Postfix instances, please see # http://amd.co.at/adminwiki/Postfix#Adding_a_Second_Postfix_Instance_on_one_Server # http://www.postfix.org/postconf.5.html # # # usage: $0 {start|stop|reload|monitor|validate-all|meta-data} # # The "start" arg starts a Postfix instance # # The "stop" arg stops it. # # OCF parameters: # OCF_RESKEY_binary # OCF_RESKEY_config_dir # OCF_RESKEY_parameters # ########################################################################## # Initialization: : ${OCF_FUNCTIONS_DIR=${OCF_ROOT}/lib/heartbeat} . ${OCF_FUNCTIONS_DIR}/ocf-shellfuncs # Parameter defaults OCF_RESKEY_binary_default="/usr/sbin/postfix" OCF_RESKEY_config_dir_default="" OCF_RESKEY_parameters_default="" : ${OCF_RESKEY_binary=${OCF_RESKEY_binary_default}} : ${OCF_RESKEY_config_dir=${OCF_RESKEY_config_dir_default}} : ${OCF_RESKEY_parameters=${OCF_RESKEY_parameters_default}} USAGE="Usage: $0 {start|stop|reload|monitor|validate-all|meta-data}"; ########################################################################## usage() { echo $USAGE >&2 } meta_data() { cat < 0.1 This script manages Postfix as an OCF resource in a high-availability setup. Manages a highly available Postfix mail server instance Full path to the Postfix binary. For example, "/usr/sbin/postfix". Full path to Postfix binary Full path to a Postfix configuration directory. For example, "/etc/postfix". Full path to configuration directory The Postfix daemon may be called with additional parameters. Specify any of them here. END } postfix_running() { local loglevel loglevel=${1:-err} # run Postfix status if available if ocf_is_true $status_support; then $binary $OPTION_CONFIG_DIR status 2>&1 ret=$? if [ $ret -ne 0 ]; then ocf_log $loglevel "Postfix status: " $ret fi return $ret fi # manually check Postfix's pid PIDFILE=${queue_dir}/pid/master.pid if [ -f $PIDFILE ]; then PID=`head -n 1 $PIDFILE` kill -s 0 $PID >/dev/null 2>&1 && [ `ps -p $PID | grep master | wc -l` -eq 1 ] return $? fi # Postfix is not running false } postfix_start() { # if Postfix is running return success if postfix_running info; then ocf_log info "Postfix already running." return $OCF_SUCCESS fi # start Postfix $binary $OPTIONS start >/dev/null 2>&1 ret=$? if [ $ret -ne 0 ]; then ocf_exit_reason "Postfix returned error: $ret" return $OCF_ERR_GENERIC fi # grant some time for startup/forking the sub processes # and loop initial monitoring until success or timeout while true; do sleep 1 # break if postfix is up and running; log failure otherwise postfix_running info && break ocf_log info "Postfix failed initial monitor action: " $ret done ocf_log info "Postfix started." return $OCF_SUCCESS } postfix_stop() { # if Postfix is not running return success if ! postfix_running info; then ocf_log info "Postfix already stopped." return $OCF_SUCCESS fi # stop Postfix $binary $OPTIONS stop >/dev/null 2>&1 ret=$? if [ $ret -ne 0 ]; then ocf_exit_reason "Postfix returned an error while stopping: $ret" return $OCF_ERR_GENERIC fi # grant some time for shutdown and recheck 5 times for i in 1 2 3 4 5; do if postfix_running info; then sleep 1 else break fi done # escalate to abort if we did not stop by now # @TODO shall we loop here too? if postfix_running info; then ocf_exit_reason "Postfix failed to stop. Escalating to 'abort'." $binary $OPTIONS abort >/dev/null 2>&1; ret=$? sleep 5 # postfix abort did not succeed if postfix_running; then ocf_exit_reason "Postfix failed to abort." return $OCF_ERR_GENERIC fi fi ocf_log info "Postfix stopped." return $OCF_SUCCESS } postfix_reload() { if postfix_running; then ocf_log info "Reloading Postfix." $binary $OPTIONS reload fi } postfix_monitor() { local status_loglevel="err" # Set loglevel to info during probe if ocf_is_probe; then status_loglevel="info" fi if postfix_running $status_loglevel; then return $OCF_SUCCESS fi return $OCF_NOT_RUNNING } postfix_validate_all() { # check that the Postfix binaries exist and can be executed check_binary "$binary" check_binary "postconf" # if true, run in-depth directory checks dir_check=true # check config_dir and alternate_config_directories parameter if [ "x$config_dir" != "x" ]; then if [ ! -d "$config_dir" ]; then if ocf_is_probe; then ocf_log info "Postfix configuration directory '$config_dir' not readable during probe." # skip in-depth directory checks if config file isn't readable during probe dir_check=false else ocf_exit_reason "Postfix configuration directory '$config_dir' does not exist or is not readable." return $OCF_ERR_INSTALLED fi fi alternate_config_directories=`postconf -h alternate_config_directories 2>/dev/null | grep "$config_dir/\?"` if [ "x$alternate_config_directories" = "x" ]; then ocf_exit_reason "Postfix main configuration must contain correct 'alternate_config_directories' parameter." return $OCF_ERR_INSTALLED fi fi # check spool/queue and data directories (if applicable) # this is required because "postfix check" does not catch all errors if ocf_is_true $dir_check; then if [ ! -d "$queue_dir" ]; then if ocf_is_probe; then ocf_log info "Postfix queue directory '$queue_dir' not readable during probe." else ocf_exit_reason "Postfix queue directory '$queue_dir' does not exist or is not readable." return $OCF_ERR_INSTALLED fi fi if ocf_is_true $status_support; then data_dir=`postconf $OPTION_CONFIG_DIR -h data_directory 2>/dev/null` data_dir_count=`echo "$data_dir" | tr ',' ' ' | wc -w` if [ $data_dir_count -gt 1 ]; then ocf_exit_reason "Postfix data directory '$orig_data_dir' cannot be set to multiple directories." return $OCF_ERR_INSTALLED fi if [ ! -d "$data_dir" ]; then if ocf_is_probe; then ocf_log info "Postfix data directory '$data_dir' not readable during probe." else ocf_exit_reason "Postfix data directory '$data_dir' does not exist or is not readable." return $OCF_ERR_INSTALLED fi fi fi # check directory permissions if ocf_is_true $status_support; then user=`postconf $OPTION_CONFIG_DIR -h mail_owner 2>/dev/null` for dir in $data_dir; do if ! su -s /bin/sh - $user -c "test -w $dir"; then if ocf_is_probe; then ocf_log info "Directory '$dir' is not writable by user '$user' during probe." else ocf_exit_reason "Directory '$dir' is not writable by user '$user'." return $OCF_ERR_PERM; fi fi done fi fi # run Postfix internal check, if not probing if ! ocf_is_probe; then $binary $OPTIONS check >/dev/null 2>&1 ret=$? if [ $ret -ne 0 ]; then ocf_exit_reason "Postfix 'check' failed: $ret" return $OCF_ERR_GENERIC fi fi return $OCF_SUCCESS } # # Main # if [ $# -ne 1 ]; then usage exit $OCF_ERR_ARGS fi binary=$OCF_RESKEY_binary config_dir=$OCF_RESKEY_config_dir parameters=$OCF_RESKEY_parameters # handle parameters case $1 in meta-data) meta_data exit $OCF_SUCCESS ;; usage|help) usage exit $OCF_SUCCESS ;; esac # build Postfix options string *outside* to access from each method OPTIONS='' OPTION_CONFIG_DIR='' # check for Postfix's postconf binary check_binary "postconf" # check if the Postfix config_dir exist if [ "x$config_dir" != "x" ]; then # remove all trailing slashes to ease "postconf alternate_config_directories" match config_dir=`echo $config_dir | sed 's/\/*$//'` # reset config_dir if it equals Postfix's default config_directory postconf -h config_directory 2>/dev/null | grep -q "^$config_dir/\?$" if [ $? -eq 0 ]; then config_dir="" fi # set OPTIONS if config_dir is still set # save OPTION_CONFIG_DIR seperatly if [ "x$config_dir" != "x" ]; then OPTION_CONFIG_DIR="-c $config_dir" OPTIONS=$OPTION_CONFIG_DIR fi fi # add all additional parameters to options string if [ "x$parameters" != "x" ]; then OPTIONS="$OPTIONS $parameters" fi # important directories, used in different methods queue_dir=`postconf $OPTION_CONFIG_DIR -h queue_directory 2>/dev/null` # check Postfix version and status support status_support=false postfix_version=`postconf -h mail_version 2>/dev/null` ocf_version_cmp "$postfix_version" "2.5.0" ret=$? # we need Postfix 2.5.0 or greater for status/data_directory support if [ $ret -eq 1 -o $ret -eq 2 ]; then status_support=true fi postfix_validate_all ret=$? LSB_STATUS_STOPPED=3 if [ $ret -ne $OCF_SUCCESS ]; then case $1 in stop) exit $OCF_SUCCESS ;; *) exit $ret;; esac fi case $1 in monitor) postfix_monitor exit $? ;; start) postfix_start exit $? ;; stop) postfix_stop exit $? ;; reload) postfix_reload exit $? ;; validate-all) exit $OCF_SUCCESS ;; *) usage exit $OCF_ERR_UNIMPLEMENTED ;; esac