238 lines
7.2 KiB
Bash
238 lines
7.2 KiB
Bash
#!/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 <aschultz@mirantis.com>
|
|
#
|
|
|
|
###########################################################
|
|
# 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 :
|