#!/bin/bash
#    Copyright 2016 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.
#
# See usage() function below for more details ...
#
# OCF instance parameters:
#   OCF_RESKEY_binary
#   OCF_RESKEY_config
#   OCF_RESKEY_ns
#######################################################################
# Initialization:

: "${OCF_FUNCTIONS_DIR=${OCF_ROOT}/lib/heartbeat}"
. "${OCF_FUNCTIONS_DIR}/ocf-shellfuncs"

#######################################################################

# Fill in some defaults if no values are specified

SERVICE_NAME="Nagios"

OCF_RESKEY_binary_default="/usr/sbin/nagios3"
OCF_RESKEY_config_default="/etc/nagios3/nagios.cfg"
OCF_RESKEY_ns_default=

: ${OCF_RESKEY_binary=${OCF_RESKEY_binary_default}}
: ${OCF_RESKEY_config=${OCF_RESKEY_config_default}}
: ${OCF_RESKEY_ns=${OCF_RESKEY_ns_default}}

if [ -z "${OCF_RESKEY_ns}" ] ; then
    RUN=''
else
    RUN_IN_NS="ip netns exec $OCF_RESKEY_ns "
    RUN="$RUN_IN_NS "
fi
NAGIOS_PID_FILE="/var/run/nagios3/nagios3.pid"

#######################################################################

usage() {
    cat <<UEND
        usage: $0 (start|stop|validate-all|meta-data|status|monitor)

        $0 manages the ${SERVICE_NAME} process as an HA resource

        The 'start' operation starts the ${SERVICE_NAME}
        The 'stop' operation stops the ${SERVICE_NAME}
        The 'validate-all' operation reports whether the parameters are valid
        The 'meta-data' operation reports this RA's meta-data information
        The 'status' operation reports whether the ${SERVICE_NAME} is running
        The 'monitor' operation reports whether the ${SERVICE_NAME} is running

UEND
}

meta_data() {
    cat <<END
<?xml version="1.0"?>
<!DOCTYPE resource-agent SYSTEM "ra-api-1.dtd">
<resource-agent name="nagios">
<version>1.0</version>

<longdesc lang="en">
Manages the Nagios daemon in a network namespace as a Pacemaker Resource.
</longdesc>
<shortdesc lang="en">Manages Nagios</shortdesc>
<parameters>

<parameter name="binary" unique="0" required="0">
<longdesc lang="en">
Path of the Nagios binary file that will be run.
</longdesc>
<shortdesc lang="en">Nagios binary file</shortdesc>
<content type="string" default="${OCF_RESKEY_binary_default}" />
</parameter>

<parameter name="config" unique="0" required="0">
<longdesc lang="en">
Path to the Nagios configuration file
</longdesc>
<shortdesc lang="en">Nagios configuration</shortdesc>
<content type="string" default="${OCF_RESKEY_config_default}" />
</parameter>

<parameter name="ns" unique="0" required="0">
<longdesc lang="en">
Network namespace in which Nagios will be run
</longdesc>
<shortdesc lang="en">Nagios namespace</shortdesc>
<content type="string" default="${OCF_RESKEY_ns_default}" />
</parameter>

</parameters>

<actions>
<action name="start" timeout="20" />
<action name="stop" timeout="20" />
<action name="status" timeout="20" />
<action name="monitor" timeout="30" interval="20" />
<action name="validate-all" timeout="5" />
<action name="meta-data" timeout="5" />
</actions>
</resource-agent>
END
}

#######################################################################
# Functions invoked by resource manager actions

service_validate() {
    local rc

    check_binary "$OCF_RESKEY_binary"

    if [[ ! -f $OCF_RESKEY_config ]]; then
        ocf_log err "Config $OCF_RESKEY_config doesn't exist"
        return "$OCF_ERR_INSTALLED"
    fi

    if [ -n "${OCF_RESKEY_ns}" ]; then
         if ! ip netns pids "$OCF_RESKEY_ns" > /dev/null 2>&1; then
             # The network namespace needs to be created first
             ocf_run ip netns add $OCF_RESKEY_ns
             rc=$?
             if [ $rc -ne 0 ]; then
                 ocf_log err "Namespace $OCF_RESKEY_ns can't be created (error=$rc)"
                 return "$OCF_ERR_INSTALLED"
             fi
             # This is required for Linux kernels >= 3.19. Previously the
             # net.ipv4.ip_nonlocal_bind setting was global to all namespaces but
             # starting with this version, it is per namespace.
             ocf_run ${RUN_IN_NS} /sbin/sysctl -w net.ipv4.ip_nonlocal_bind=1
             ocf_run ${RUN_IN_NS} ip link set up dev lo
         fi
    fi

    # Make sure that the Nagios run directory exists and has the appropriate ownership
    local nagios_dir
    nagios_dir="$(dirname ${NAGIOS_PID_FILE})"
    mkdir -p "$nagios_dir"
    chown nagios:nagios "$nagios_dir"

    true
}

service_status() {
    local rc
    local pid

    if [ ! -f "$NAGIOS_PID_FILE" ]; then
        ocf_log info "Nagios is not running"
        return "$OCF_NOT_RUNNING"
    else
        pid=$(cat "$NAGIOS_PID_FILE")
    fi

    if [ -n "${pid}" ]; then
        ocf_run -warn kill -s 0 "$pid"
        rc=$?
        if [ $rc -ne 0 ]; then
            ocf_log info "Old PID file found, but Nagios process isn't running"
            return "$OCF_NOT_RUNNING"
        fi
    else
        ocf_log err "PID file ${NAGIOS_PID_FILE} is empty!"
        return "$OCF_ERR_GENERIC"
    fi

    return "$OCF_SUCCESS"
}

service_monitor() {
    local rc
    service_status
    rc=$?
    return $rc
}

service_start() {
    local rc

    service_monitor
    rc=$?
    if [ $rc -eq "$OCF_SUCCESS" ]; then
        ocf_log info "${SERVICE_NAME} is already running"
        return "$OCF_SUCCESS"
    fi

    if ! ocf_run  ${OCF_RESKEY_binary} -v ${OCF_RESKEY_config}; then
        ocf_log error "Nagios configuration is invalid"
        exit "$OCF_ERR_GENERIC"
    fi

    ocf_run ${RUN} ${OCF_RESKEY_binary} -d ${OCF_RESKEY_config}

    # Spin waiting for the server to come up
    while true; do
        service_monitor
        rc=$?
        [ $rc -eq "$OCF_SUCCESS" ] && break
        if [ $rc -ne "$OCF_NOT_RUNNING" ]; then
            ocf_log err "${SERVICE_NAME} start failed"
            exit "$OCF_ERR_GENERIC"
        fi
        sleep 3
    done

    ocf_log info "${SERVICE_NAME} started"
    return "$OCF_SUCCESS"
}

service_stop() {
    local rc
    local pid

    service_monitor
    rc=$?
    if [ $rc -eq "$OCF_NOT_RUNNING" ]; then
        ocf_log info "${SERVICE_NAME} is already stopped"
        return "$OCF_SUCCESS"
    fi

    # Try SIGTERM
    pid=$(cat "$NAGIOS_PID_FILE")
    ocf_run kill -s TERM "$pid"
    rc=$?
    if [ $rc -ne 0 ]; then
        ocf_log err "${SERVICE_NAME} couldn't be stopped"
        exit "$OCF_ERR_GENERIC"
    fi

    # stop waiting
    shutdown_timeout=15
    if [ -n "$OCF_RESKEY_CRM_meta_timeout" ]; then
        shutdown_timeout=$(( (OCF_RESKEY_CRM_meta_timeout/1000)-5 ))
    fi
    count=0
    while [ $count -lt $shutdown_timeout ]; do
        service_monitor
        rc=$?
        if [ $rc -eq "$OCF_NOT_RUNNING" ]; then
            break
        fi
        count=$(( count + 1))
        sleep 1
        ocf_log debug "${SERVICE_NAME} still hasn't stopped yet. Waiting ..."
    done

    service_monitor
    rc=$?
    if [ "${rc}" -ne "${OCF_NOT_RUNNING}" ]; then
        # SIGTERM didn't help either, try SIGKILL
        ocf_log info "${SERVICE_NAME} failed to stop after ${shutdown_timeout}s using SIGTERM. Trying SIGKILL ..."
        ocf_run kill -s KILL "${pid}"
    fi

    ocf_log info "${SERVICE_NAME} stopped"
    rm -f "${NAGIOS_PID_FILE}"

    return "${OCF_SUCCESS}"
}

#######################################################################

case "$1" in
  meta-data)    meta_data
                exit "$OCF_SUCCESS";;
  usage|help)   usage
                exit "$OCF_SUCCESS";;
esac

# Anything except meta-data and help must pass validation
service_validate || exit $?

# What kind of method was invoked?
case "$1" in
  start)        service_start;;
  stop)         service_stop;;
  status)       service_status;;
  monitor)      service_monitor;;
  validate-all) ;;
  *)            usage
                exit "$OCF_ERR_UNIMPLEMENTED";;
esac
