#!/usr/bin/bash
#
# Copyright: 2021 ZENETYS
# Author: Benoit DOLEZ <bdolez@zenetys.com>
# License: MIT License (http://opensource.org/licenses/MIT)
# Version: 0.1
#

[[ $XDEBUG == 1 ]] && set -x

export LC_ALL=C
shopt -s nullglob
set -o pipefail

PROGNAME=${0##*/}
USAGE="${PROGNAME} [OPTIONS] ACTION [...]"

function info() {
    local i;
    local d=$(date +%Y-%m-%dT%H:%M:%S.%3N%z);
    local l=info
    [[ ${1:0:2} == -- ]] && l=${1:2} && shift
    for i in "$@"; do
        printf '%s%s%s: %s\n' "${C[$l]}" "${l^^}" "${C[reset]}" "$i" >&2
    done
}

function fatal() {
    local usage=0
    [[ $1 == --usage ]] && usage=1 && shift
    info --${FUNCNAME[0]} "$@"
    (( $usage )) && usage
    trap "" EXIT
    exit 127
}

function error() {
    info --${FUNCNAME[0]} "$@"
}

function warning() {
    info --${FUNCNAME[0]} "$@"
}

function debug() {
    local debug=0

    [[ ${1:0:1} == - ]] && debug=${1:1} && shift
    (( DEBUG < $debug )) && return 0
    info --${FUNCNAME[0]} "$@"
}

function usage() {
  local IFS=$'\t'
  exec >&2
  if [[ $0 == "-bash" ]] ; then return 1 ; fi
  [[ $# -gt 0 ]] && echo "ERROR: $*"
  version
  echo "Usage: $USAGE"
  echo "Options:"
  sed -nr "s/^[[:space:]]*## ([^:]*): /\1\t/p" -- "$0" |
    while read OPT DESC ; do
      printf " %-20s %s\n" "$OPT" "$DESC"
    done
  echo

  echo "<ACTION> is one of :"
  sed -nr "s/^# X-ACTION ([^:]*): /\1\t/p" -- "$0" |
    while read OPT DESC ; do
      printf " %s\n     %s\n" "$OPT" "$DESC"
    done
  echo

  return 0
}

function version() {
  local PROGFILE=$0
  local VERSION=$(sed -n 's/^# Version: //p' $PROGFILE)
  local AUTHOR=$(sed -n 's/^# Author: //p' $PROGFILE)
  local LICENSE=$(sed -n 's/^# License: //p' $PROGFILE)

  echo "${PROGFILE##*/} $VERSION - $AUTHOR - $LICENSE"
}

function dump_nagios_simple_object() {
  local type=$1; shift
  local attr value

  echo "define $type {"
  for field in "$@"; do
    attr="${field%%=*}"
    value="${field#*=}"
    printf "  %-20s %s\n" "${attr}" "${value}"
  done
  echo "}"
}

function add_nagios_template_snmp() {
  version=${version:-2c}
  community=${community:-public}
  secname=${secname:-username}
  seclevel=${seclevel:-authPriv}
  aproto=${aproto:-SHA}
  apass=${apass:-password}
  pproto=${pproto:-AES}
  ppass=${ppass:-password}
  timeout=${timeout:-3}
  retries=${retries:-1}

  local attrs=(
    name="_cred_snmp_$name"
    __CRED_SNMP_COMMUNITY="$community"
    __CRED_SNMP_CENTREON="--snmp-version '$version' \\
                --snmp-community '$community' \\
                --snmp-username '$secname' \\
                --authprotocol '$aproto' \\
                --authpassphrase '$apass' \\
                --privprotocol '$pproto' \\
                --privpassphrase '$ppass' \\
                --snmp-timeout '$timeout' \\
                --snmp-retries '$retries'"
    __CRED_SNMP_NAGIOS="--protocol '$version' \\
                --community '$community' \\
                --seclevel '$seclevel' \\
                --secname '$secname' \\
                --authproto '$aproto' \\
                --authpass '$apass' \\
                --privproto '$pproto' \\
                --privpass '$ppass' \\
                --timeout '$timeout' \\
                --retries '$retries'"
    __CRED_SNMP_SNMPCMD="-v $version \\
                -c '$community' \\
                -l '$seclevel' \\
                -u '$secname' \\
                -a '$aproto' \\
                -A '$apass' \\
                -x '$pproto' \\
                -X '$ppass' \\
                -t '$timeout' \\
                -r '$retries'"
  )
  dump_nagios_simple_object host "${attrs[@]}"
}

function add_snmpv2() {
  local community
  local version=2c
  while (( $# > 0 )); do
    case $1 in
      -c) community=$2; shift ;;
      -*) usage "undefined option '$1'" && exit 1 ;;
      *)  usage "bad argument '$1'" && exit 1 ;;
    esac
    shift
  done

  [[ -e $CFGDIR/$name.cfg ]] &&
    fatal "credential '$name' already exists, remove first"
  add_nagios_template_snmp > $CFGDIR/$name.cfg
}

function add_snmpv3() {
  local pproto ppass
  local aproto apass
  local secname seclevel
  local version=3

  while (( $# > 0 )); do
    case $1 in
      -a) aproto=$2; shift ;;
      -A) apass=$2; shift ;;
      -x) pproto=$2; shift ;;
      -X) ppass=$2; shift ;;
      -l) seclevel=$2; shift ;;
      -u) secname=$2; shift ;;
      -t) timeout=$2; shift ;;
      -r) retries=$2; shift ;;
      -*) usage "undefined option '$1'" && exit 1 ;;
      *)  usage "bad argument '$1'" && exit 1 ;;
    esac
    shift
  done

  [[ -e $CFGDIR/$name.cfg ]] &&
    fatal "credential '$name' already exists, remove first"
  add_nagios_template_snmp > $CFGDIR/$name.cfg
}

# X-ACTION add <NAME> <TYPE> ...: add credential NAME of type TYPE with definition
function do_add() {
  local name=$1; shift
  local type=$1; shift

  case $type in
    snmpv2) add_snmpv2 "$@" ;;
    snmpv3) add_snmpv3 "$@" ;;
    "") usage "empty credential type" && exit 1 ;;
    *) usage "undefined credential type '$type'" ;;
  esac
  return 0
}

# X-ACTION del <NAME>: remove redential identifier by NAME
function do_del() {
  local name=$1; shift
  [[ -e $CFGDIR/$name.cfg ]] && rm $CFGDIR/$name.cfg
  return 0
}

# X-ACTION list: list all credentials
function do_list() {
  for file in ${CFGDIR}/*.cfg; do
    file=${file##*/} ; file=${file%.cfg}
    echo "${file}"
  done
  return 0
}

declare VERBOSE=${VERBOSE:-1}
declare CFGDIR=${CFGDIR:-/etc/kompot/nagios/credentials}

(( ${#BASH_SOURCE[@]} > 1 )) && return

while (( $# > 0 )); do
  case "$1" in
    ## -h, --help: This help
    -h|--help) usage && exit 0 ;;
    ## -V, --version: Show version
    -V|--version) version && exit 0 ;;
    ## --x-debug: Enable bash debug mode
    --x-debug)    XDEBUG=1 ;;
    ## -v, --verbose: Define verbose level (must be repeat)
    -v|--verbose) ((VERBOSE++)) ;;
    ## -q, --quiet: Set verbose level to 0
    -q|--quiet) ((VERBOSE=0)) ;;
    --) shift ; break ;;
    -*) usage "Unknown parameter '$1'" && exit 1 ;;
    *) ARGS+=( "$1" ) ;;
  esac
  shift
done

ARGS+=( "$@" )

[[ $XDEBUG == 1 ]] && set -x

####################################################
## main program starts here
####################################################

case ${ARGS[0]} in
  # FIXME
  list) do_list "${ARGS[@]:1}" ;;
  add) do_add "${ARGS[@]:1}" ;;
  del) do_del "${ARGS[@]:1}" ;;
  *) usage "unknown command '${ARGS[0]}'" && exit 1 ;;
esac

exit $?

