#!/bin/bash # # Copyright 2015 Mirantis, Inc. # # Licensed under the Apache License, Version 2.0 (the "License"); you may # not use this file except in compliance with the License. You may obtain # a copy of the License at # # http://www.apache.org/licenses/LICENSE-2.0 # # Unless required by applicable law or agreed to in writing, software # distributed under the License is distributed on an "AS IS" BASIS, WITHOUT # WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the # License for the specific language governing permissions and limitations # under the License. # # Shared resource script for common functions (ocf-fuel-funcs) # # Authors: Alex Schultz # ########################################################### # Attempts to kill a process with retries and checks procfs # to make sure the process is stopped. # # Globals: # LL # Arguments: # $1 - pid of the process to try and kill # $2 - service name used for logging and match-based kill, if the pid is "none" # $3 - signal to use, defaults to SIGTERM # $4 - number of retries, defaults to 5 # $5 - time to sleep between retries, defaults to 2 # Returns: # 0 - if successful # 1 - if process is still running according to procfs # 2 - if invalid parameters passed in ########################################################### proc_kill() { local pid="${1}" local service_name="${2}" local signal="${3:-SIGTERM}" local count="${4:-5}" local process_sleep="${5:-2}" local LH="${LL} proc_kill():" local pgrp="$(ps -o pgid= ${pid} 2>/dev/null | tr -d '[[:space:]]')" if [ "${pid}" -a "${pgrp}" = "1" ] ; then ocf_log err "${LH} shall not kill by the bad pid 1 (init)!" return 2 fi if [ "${pid}" = "none" ]; then local matched matched="$(pgrep -fla ${service_name})" if [ -z "${matched}" ] ; then ocf_log err "${LH} cannot find any processes matching the ${service_name}!" return 2 fi ocf_log debug "${LH} no pid provided, will try the ${service_name}, matched list: ${matched}" while [ $count -gt 0 ]; do if [ -z "${matched}" ]; then break else matched="$(pgrep -fla ${service_name})" ocf_log debug "${LH} Stopping ${service_name} with ${signal}..." ocf_run pkill -f -"${signal}" "${service_name}" fi sleep $process_sleep count=$(( count-1 )) done pgrep -f "${service_name}" > /dev/null if [ $? -ne 0 ] ; then ocf_log debug "${LH} Stopped ${service_name} with ${signal}" return 0 else ocf_log warn "${LH} Failed to stop ${service_name} with ${signal}" return 1 fi else # pid is not none while [ $count -gt 0 ]; do if [ ! -d "/proc/${pid}" ]; then break else ocf_log debug "${LH} Stopping ${service_name} with ${signal}..." ocf_run pkill -"${signal}" -g "${pgrp}" fi sleep $process_sleep count=$(( count-1 )) done # Check if the process ended after the last sleep if [ ! -d "/proc/${pid}" ] ; then ocf_log debug "${LH} Stopped ${service_name} with ${signal}" return 0 fi ocf_log warn "${LH} Failed to stop ${service_name} with ${signal}" return 1 fi } ########################################################### # Attempts to kill a process with the given pid or pid file # using proc_kill and will retry with sigkill if sigterm is # unsuccessful. # # Globals: # OCF_ERR_GENERIC # OCF_SUCCESS # LL # Arguments: # $1 - pidfile or pid # $2 - service name used for logging # $3 - stop process timeout (in sec), used to determine how many times we try # SIGTERM and an upper limit on how long this function should try and # stop the process. Defaults to 15. # Returns: # OCF_SUCCESS - if successful # OCF_ERR_GENERIC - if process is still running according to procfs ########################################################### proc_stop() { local pid_param="${1}" local service_name="${2}" local timeout="${3:-15}" local LH="${LL} proc_stop():" local i local pid local pidfile # check if provide just a number echo "${pid_param}" | egrep -q '^[0-9]+$' if [ $? -eq 0 ]; then pid="${pid_param}" elif [ -e "${pid_param}" ]; then # check if passed in a pid file pidfile="${pid_param}" pid=$(cat "${pidfile}" 2>/dev/null | tr -s " " "\n" | sort -u) else ocf_log warn "${LH} pid param ${pid_param} is not a file or a number, try match by ${service_name}" pid="none" fi # number of times to try a SIGTEM is (timeout - 5 seconds) / 2 seconds local stop_count=$(( ($timeout-5)/2 )) # make sure we stop at least once if [ $stop_count -le 0 ]; then stop_count=1 fi if [ -z "${pid}" ] ; then ocf_log warn "${LH} unable to get PID from ${pidfile}, try match by ${service_name}" pid="none" fi if [ -n "${pid}" ]; then for i in ${pid} ; do [ "${i}" ] || break ocf_log info "${LH} Stopping ${service_name} by PID ${i}" proc_kill "${i}" "${service_name}" SIGTERM $stop_count if [ $? -ne 0 ]; then # SIGTERM failed, send a single SIGKILL proc_kill "${i}" "${service_name}" SIGKILL 1 2 if [ $? -ne 0 ]; then ocf_log err "${LH} ERROR: could not stop ${service_name}" return "${OCF_ERR_GENERIC}" fi fi done fi # Remove the pid file here which will remove empty pid files as well if [ -n "${pidfile}" ]; then rm -f "${pidfile}" fi ocf_log info "${LH} Stopped ${service_name}" return "${OCF_SUCCESS}" } ########################################################### # Runs a process as root via su to get the whole PAM stack # executed. # # Globals: # none # Arguments: # $* - ocf_run arguments # Returns: # Return code of the ocf_run invocation. ########################################################### ocf_run_as_root() { ocf_run su - root -c "$(printf '%q ' "$@")" } ########################################################### # Validate a port according to RFC 793 # # Globals: # LL # Arguments: # $1 - port for validation # Returns: # 0 - if port valid # 1 - if port invalid # 2 - if invalid parameters passed in ########################################################### validate_port() { local port=$1 local LH="${LL} validate_port():" if [ -z "${port}" ]; then ocf_log info "${LH} Port provided is empty" return 2 fi case ${port} in *[^0-9]*) ocf_log info "${LH}: invalid port specified: $port" return 1 ;; esac # $port contains only digits, check if it's in the correct range if [ $port -gt 65535 ] || [ $port -lt 1 ]; then ocf_log err "${LH}: invalid port specified: $port" return 1 else ocf_log debug "${LH} got a valid port: $port" return 0 fi } # vim: set ts=4 sw=4 tw=0 et :