diff --git a/install.sh b/install.sh index b86a913..0e74e80 100755 --- a/install.sh +++ b/install.sh @@ -1,6 +1,7 @@ #!/bin/sh [ -z "$ZAF_DEBUG" ] && ZAF_DEBUG=1 +export ZAF_LOG_STDERR="-s" if [ -z "$ZAF_URL" ]; then # Runing as standalone install.sh. We have to download rest of files first. ZAF_URL="https://github.com/limosek/zaf/" @@ -8,20 +9,28 @@ fi [ -z "$ZAF_GITBRANCH" ] && ZAF_GITBRANCH=1.2 +ZAF_TMP_DIR="/tmp/zaf-installer" +ZAF_DIR="$ZAF_TMP_DIR/zaf" + # Lite version of zaf_fetch_url, full version will be loaded later zaf_fetch_url(){ - if [ -z "$ZAF_OFFLINE" ]; then - echo curl -f -k -s -L -o - "$1" >&2; curl -f -k -s -L -o - "$1" - else - echo "Offline mode wants to download $1. Exiting." >&2 - exit 2 - fi + echo curl -f -k -s -L -o - "$1" >&2; + curl -f -k -s -L -o - "$1" } -# Download tgz and extract to /tmp/zaf-installer +# Lite version of zaf_err, full version will be loaded later +zaf_err() { + logger ${ZAF_LOG_STDERR} -p user.err -t zaf-error -- $@ + logger ${ZAF_LOG_STDERR} -p user.err -t zaf-error "Exiting with error!" + exit 1 +} + +# Download tgz and extract to tmpdir zaf_download_files() { - rm -rf /tmp/zaf-installer - zaf_fetch_url $ZAF_URL/archive/$ZAF_GITBRANCH.tar.gz | tar -f - -C /tmp -zx && mv /tmp/zaf-$ZAF_GITBRANCH /tmp/zaf-installer + [ -n $ZAF_DIR ] && zaf_err "ZAF_DIR not set!" + rm -rf $ZAF_DIR + zaf_fetch_url $ZAF_URL/archive/$ZAF_GITBRANCH.tar.gz | tar -f - -C $ZAF_TMP_DIR -zx && mv $ZAF_TMP_DIR/zaf-$ZAF_GITBRANCH $ZAF_DIR \ + || zaf_err "Cannot download and unpack zaf!" } if ! [ -f README.md ]; then @@ -32,7 +41,7 @@ if ! [ -f README.md ]; then fi echo "Installing from url $url..." [ -z "$*" ] && auto=auto - zaf_download_files && cd /tmp/zaf-installer && exec ./install.sh $auto "$@" + zaf_download_files && cd $ZAF_DIR && exec ./install.sh $auto "$@" echo "Error downloading and runing installer!" >&2 exit 2 fi @@ -276,7 +285,7 @@ zaf_configure(){ } zaf_install_all() { - rm -rif ${ZAF_TMP_DIR} + rm -rf ${ZAF_TMP_DIR} mkdir -p ${ZAF_TMP_DIR} zaf_install_dir ${ZAF_LIB_DIR} for i in lib/zaf.lib.sh lib/plugin.lib.sh lib/os.lib.sh lib/ctrl.lib.sh lib/cache.lib.sh lib/zbxapi.lib.sh lib/JSON.sh README.md; do @@ -317,14 +326,15 @@ zaf_postconfigure() { if [ -f "${ZAF_CFG_FILE}" ]; then . "${ZAF_CFG_FILE}" fi -ZAF_TMP_DIR="/tmp/zaf-installer-tmp/" +ZAF_TMP_DIR="/tmp/zaf-installer/" +! [ -d "${ZAF_TMP_DIR}" ] && mkdir "${ZAF_TMP_DIR}" # If debug is on, do not remove tmp dir if [ "$ZAF_DEBUG" -le 3 ]; then - trap "rm -rif ${ZAF_TMP_DIR}" EXIT - trap "rm -rif /tmp/zaf-installer" EXIT + trap "rm -rf ${ZAF_TMP_DIR} " EXIT +else + trap 'zaf_wrn "Leaving $ZAF_TMP_DIR" contents due to ZAF_DEBUG.' EXIT fi -! [ -d "${ZAF_TMP_DIR}" ] && mkdir "${ZAF_TMP_DIR}" case $1 in interactive) diff --git a/lib/cache.lib.sh b/lib/cache.lib.sh index 0cc3285..9a7c985 100644 --- a/lib/cache.lib.sh +++ b/lib/cache.lib.sh @@ -9,7 +9,7 @@ zaf_cache_clean(){ fi mkdir -p "$ZAF_CACHE_DIR" if zaf_is_root; then - chmod g+rwx "$ZAF_CACHE_DIR" + chmod 770 "$ZAF_CACHE_DIR" chgrp zabbix "$ZAF_CACHE_DIR" fi } @@ -86,6 +86,7 @@ zaf_fromcache(){ local value key=$(zaf_cache_key "$1") if [ -f $ZAF_CACHE_DIR/$key ]; then + ! [ -f "$ZAF_CACHE_DIR/$key.info" ] && { return 3; } if [ "$ZAF_CACHE_DIR/$key.info" -nt "$ZAF_CACHE_DIR/$key" ]; then zaf_trc "Cache: serving $1($key) from cache" cat $ZAF_CACHE_DIR/$key diff --git a/lib/ctrl.lib.sh b/lib/ctrl.lib.sh index 275bd20..3790e8e 100644 --- a/lib/ctrl.lib.sh +++ b/lib/ctrl.lib.sh @@ -191,20 +191,28 @@ zaf_ctrl_generate_cfg() { local ikey local lock local cache + local tmpfile + local pname + local pdefault + local pregex + local prest + local zafparms items=$(zaf_ctrl_get_items <"$1") + tmpfile=$ZAF_TMP_DIR/gencfg$$ (set -e for i in $items; do iscript=$(zaf_stripctrl $i) - params=$(zaf_ctrl_get_item_option $1 $i "Parameters") - if [ -n "$params" ]; then + zaf_ctrl_get_item_option $1 $i "Parameters" >$tmpfile + if [ -s "$tmpfile" ]; then ikey="$2.$i[*]" args="" apos=1; - for p in $params; do + while read pname pdefault pregex prest; do + zafparams="$zafparams value=\"\$$apos\"; zaf_agentparm $pname $pdefault $pregex;" args="$args \$$apos" apos=$(expr $apos + 1) - done + done <$tmpfile else ikey="$2.$i" fi @@ -223,16 +231,18 @@ zaf_ctrl_generate_cfg() { preload="" fi if [ -n "$cmd" ]; then - printf "%s" "UserParameter=$ikey,${preload}${cache}${lock}${cmd}"; echo + printf "%s" "UserParameter=$ikey,export ITEM_KEY='$ikey'; ${preload}${cache}${lock}${cmd}"; echo continue fi cmd=$(zaf_ctrl_get_item_option $1 $i "Script") if [ -n "$cmd" ]; then - zaf_ctrl_get_item_option $1 $i "Script" | \ - zaf_far '{INCLUDES}' ". $ZAF_LIB_DIR/preload.sh; " \ - >${ZAF_TMP_DIR}/${iscript}.sh; + ( echo "#!/bin/sh" + echo ". $ZAF_LIB_DIR/preload.sh; " + echo "$zafparams" + zaf_ctrl_get_item_option $1 $i "Script" + ) >${ZAF_TMP_DIR}/${iscript}.sh; [ -z "$3" ] && zaf_install_bin ${ZAF_TMP_DIR}/${iscript}.sh ${ZAF_PLUGINS_DIR}/$2/ - printf "%s" "UserParameter=$ikey,${preload}${cache}${lock}${ZAF_PLUGINS_DIR}/$2/${iscript}.sh $args"; echo + printf "%s" "UserParameter=$ikey,export ITEM_KEY='$ikey'; ${preload}${cache}${lock}${ZAF_PLUGINS_DIR}/$2/${iscript}.sh $args"; echo continue; fi zaf_err "Item $i declared in control file but has no Cmd, Function or Script!" diff --git a/lib/plugin.lib.sh b/lib/plugin.lib.sh index 112335e..90ad655 100644 --- a/lib/plugin.lib.sh +++ b/lib/plugin.lib.sh @@ -218,6 +218,30 @@ zaf_list_plugin_items() { echo } +zaf_item_info() { + local plugin + local item + + plugin=$(echo $1 | cut -d '.' -f 1) + item=$(echo $1 | cut -d '.' -f 2-) + if zaf_is_plugin $plugin; then + if zaf_ctrl_get_items <$ZAF_PLUGINS_DIR/$plugin/control.zaf | grep -wq "$item"; then + echo "Item $1:" + echo -n "Cache: "; zaf_ctrl_get_item_option $ZAF_PLUGINS_DIR/$plugin/control.zaf "$item" "Cache"; echo + echo "Parameters:" + zaf_ctrl_get_item_option $ZAF_PLUGINS_DIR/$plugin/control.zaf "$item" "Parameters" ; echo + echo "Testparameters:" + zaf_ctrl_get_item_option $ZAF_PLUGINS_DIR/$plugin/control.zaf "$item" "Testparameters" ; echo + echo "Precache:" + zaf_ctrl_get_item_option $ZAF_PLUGINS_DIR/$plugin/control.zaf "$item" "Precache" ; echo + else + zaf_err "No such item $item." + fi + else + zaf_err "No such plugin $plugin." + fi +} + zaf_list_items() { for p in $(zaf_list_plugins); do echo $p: $(zaf_list_plugin_items $p) @@ -226,7 +250,7 @@ zaf_list_items() { zaf_get_item() { if which zabbix_get >/dev/null; then - zaf_dbg zabbix_get -s localhost -k "'$1'" + zaf_trc zabbix_get -s localhost -k "'$1'" (zabbix_get -s localhost -k "$1" | tr '\n' ' '; echo) || zaf_wrn "Cannot reach agent on localhost. Please localhost to Server list." return 11 else @@ -236,6 +260,7 @@ zaf_get_item() { } zaf_test_item() { + zaf_trc $ZAF_AGENT_BIN -t "'$1'" if $ZAF_AGENT_BIN -t "$1" | grep ZBX_NOTSUPPORTED; then return 1 else diff --git a/lib/preload.sh b/lib/preload.sh index ec182cf..d638215 100644 --- a/lib/preload.sh +++ b/lib/preload.sh @@ -2,27 +2,46 @@ . /etc/zaf.conf -[ -z "$ZAF_TMP_BASE" ] && ZAF_TMP_BASE=/tmp/zaf -ZAF_TMP_DIR="${ZAF_TMP_BASE}-${USER}" -[ -z "$ZAF_CACHE_DIR" ] && ZAF_CACHE_DIR=${ZAF_TMP_BASE}c - -trap "rm -rif ${ZAF_TMP_DIR}" EXIT -! [ -d "${ZAF_TMP_DIR}" ] && mkdir "${ZAF_TMP_DIR}" -! [ -d "${ZAF_CACHE_DIR}" ] && mkdir "${ZAF_CACHE_DIR}" -[ -z "$ZAF_DEBUG" ] && ZAF_DEBUG=1 - . ${ZAF_LIB_DIR}/zaf.lib.sh +. ${ZAF_LIB_DIR}/plugin.lib.sh . ${ZAF_LIB_DIR}/ctrl.lib.sh . ${ZAF_LIB_DIR}/os.lib.sh . ${ZAF_LIB_DIR}/zbxapi.lib.sh . ${ZAF_LIB_DIR}/cache.lib.sh +[ -z "$ZAF_TMP_BASE" ] && ZAF_TMP_BASE=/tmp/zaf +[ -z "$ZAF_TMP_DIR" ] && ZAF_TMP_DIR="${ZAF_TMP_BASE}-$(zaf_random)" +[ -z "$ZAF_CACHE_DIR" ] && ZAF_CACHE_DIR=${ZAF_TMP_BASE}c + +rm -rf "${ZAF_TMP_DIR}" + +if ! [ -d "${ZAF_TMP_DIR}" ]; then + mkdir "${ZAF_TMP_DIR}" +fi + +! [ -d "${ZAF_CACHE_DIR}" ] && mkdir "${ZAF_CACHE_DIR}" +[ -z "$ZAF_DEBUG" ] && ZAF_DEBUG=1 + +if [ "$ZAF_DEBUG" -le 3 ]; then + trap "rm -rf ${ZAF_TMP_DIR}" EXIT +else + trap 'zaf_wrn "Leaving $ZAF_TMP_DIR" contents due to ZAF_DEBUG.' EXIT +fi + +#trap 'touch /tmp/aaaa' ALARM + export ZAF_LIB_DIR export ZAF_TMP_DIR export ZAF_CACHE_DIR export ZAF_PLUGINS_DIR +export ZAF_DEBUG +unset ZAF_LOG_STDERR +export PATH=$ZAF_LIB_DIR:$ZAF_BIN_DIR:$PATH -[ "$(basename $0)" = "preload.sh" ] && [ -n "$*" ] && $@ - +if [ "$(basename $0)" = "preload.sh" ] && [ -n "$*" ]; then + tmpf=$(zaf_tmpfile preload) + $@ 2>$tmpf + [ -s $tmpf ] && zaf_wrn <$tmpf +fi diff --git a/lib/zaf.lib.sh b/lib/zaf.lib.sh index 1856134..19566db 100644 --- a/lib/zaf.lib.sh +++ b/lib/zaf.lib.sh @@ -11,17 +11,17 @@ zaf_msg() { echo $@ } zaf_trc() { - [ "$ZAF_DEBUG" -ge "3" ] && logger -p user.info -s -t zaf-trace -- $@ + [ "$ZAF_DEBUG" -ge "3" ] && logger -p user.info ${ZAF_LOG_STDERR} -t zaf-trace -- $@ } zaf_dbg() { - [ "$ZAF_DEBUG" -ge "2" ] && logger -p user.debug -s -t zaf-debug -- $@ + [ "$ZAF_DEBUG" -ge "2" ] && logger -p user.debug ${ZAF_LOG_STDERR} -t zaf-debug -- $@ } zaf_wrn() { - [ "$ZAF_DEBUG" -ge "1" ] && logger -p user.warn -s -t zaf-warning -- $@ + [ "$ZAF_DEBUG" -ge "1" ] && logger -p user.warn ${ZAF_LOG_STDERR} -t zaf-warning -- $@ } zaf_err() { - logger -s -p user.err -t zaf-error -- $@ - logger -s -p user.err -t zaf-error "Exiting with error!" + logger ${ZAF_LOG_STDERR} -p user.err -t zaf-error -- $@ + logger ${ZAF_LOG_STDERR} -p user.err -t zaf-error "Exiting with error!" exit 1 } # Help option @@ -43,6 +43,31 @@ zaf_version(){ echo $ZAF_VERSION } +# Add parameter for agent check +# $1 parameter name (will be set to var) +# $2 if nonempty, it is default value. If empty, parameter is mandatory +# $3 if nonempty, regexp to test +zaf_agentparm(){ + local name + local default + local regexp + + name="$1" + default="$2" + regexp="$3" + + [ -z "$value" ] && [ -z "$default" ] && zaf_err "$ITEM_KEY: Missing mandatory parameter $name." + if [ -z "$value" ]; then + value="$default" + else + if [ -n "$regexp" ]; then + echo "$value" | grep -qE "$regexp" || zaf_err "$ITEM_KEY: Bad parameter '$name' value '$value' (not in regexp '$regexp')." + fi + fi + eval $name=$value + zaf_trc "$ITEM_KEY: Param $name set to $value" +} + # Fetch url to stdout # $1 url # It supports real file, file:// and other schemes known by curl @@ -211,3 +236,14 @@ zaf_date_add() { date -d "$1 seconds" "+%Y-%m-%d %H:%M:%S" 2>/dev/null || date -d "$(expr $(date +%s) + $1)" -D %s "+%Y-%m-%d %H:%M:%S" } +# Create temp file and return its name +# $1 prefix or empty +zaf_tmpfile() { + echo "$ZAF_TMP_DIR/tmp$1" +} + +# return random number +zaf_random() { + hexdump -n 2 -e '/2 "%u"' /dev/urandom +} + diff --git a/lib/zafcache b/lib/zafcache index 0a98c2d..3fc3c24 100644 --- a/lib/zafcache +++ b/lib/zafcache @@ -10,8 +10,25 @@ seconds=$1 shift [ -z "$*" ] && help -parms=$(echo $*|tr -d ' ') -if ! zaf_fromcache "$parms"; then - $@ | zaf_tocache_stdin "$parms" "$seconds" +zaf_trc "zafcache($seconds): $ITEM_KEY,'$2' '$3' '$4' '$5' '$6' '$7' '$8' '$9'" + +if [ -z "$ITEM_KEY" ]; then + key=$(echo $*|tr ' ' '_') +else + key="$(echo ${ITEM_KEY}|cut -d '[' -f 1)[$(shift; echo $*|tr ' ' ',')]" +fi + +if ! zaf_fromcache "$key"; then + zaf_fromcache "$key" >/dev/null 2>/dev/null + [ $? -eq 3 ] && { zaf_err "Operation $key already in progress."; } + if which at >/dev/null 2>/dev/null; then + at -M now >/dev/null 2>/dev/null <"\$tmpf" | zaf_tocache_stdin "$key" "$seconds" ; [ -s \$tmpf ] && zaf_wrn <\$tmpf +EOF + else + tmpf=$(zaf_tmpfile cache) + $@ 2>"$tmpf" | zaf_tocache_stdin "$key" "$seconds" + [ -s $tmpf ] && zaf_wrn <$tmpf + fi fi diff --git a/lib/zaflock b/lib/zaflock index a983f94..04d3575 100644 --- a/lib/zaflock +++ b/lib/zaflock @@ -13,7 +13,7 @@ shift [ -z "${ZAF_LOCK_SECONDS}" ] && seconds=5 [ -z "${ZAF_LOCK_FORCE}" ] && force=1 -lockfile="${ZAF_TMP_DIR}/zaflock_${lkey}" +lockfile="/tmp/zaflock_${lkey}" i=0 while [ -f "$lockfile" ] && [ $i -lt $seconds ]; do sleep 1 @@ -28,7 +28,6 @@ if [ -f "$lockfile" ] && [ -z "$force" ]; then exit 1 fi -touch "$lockfile" -[ -n "$*" ] && $@ -rm -f "$lockfile" +[ -n "$*" ] && $@ 2>"$lockfile" +[ -s "$lockfile" ] && zaf_wrn <"$lockfile" diff --git a/zaf b/zaf index e1cb691..350a56a 100755 --- a/zaf +++ b/zaf @@ -25,23 +25,6 @@ ZAF_CFG_FILE="/etc/zaf.conf" [ -n "$secondstage" ] && exec $0 $params fi -[ -z "$ZAF_TMP_BASE" ] && ZAF_TMP_BASE=/tmp/zaf -ZAF_TMP_DIR="${ZAF_TMP_BASE}-${USER}" -[ -z "$ZAF_CACHE_DIR" ] && ZAF_CACHE_DIR=${ZAF_TMP_BASE}c - -[ -z "$ZAF_DEBUG" ] && ZAF_DEBUG=1 -export ZAF_DEBUG - -# If debug is on, do not remove tmp dir -if [ "$ZAF_DEBUG" -le 3 ]; then - trap "rm -rif ${ZAF_TMP_DIR}" EXIT -fi - -! [ -d "${ZAF_TMP_DIR}" ] && mkdir "${ZAF_TMP_DIR}" -if ! [ -d "${ZAF_CACHE_DIR}" ]; then - mkdir "${ZAF_CACHE_DIR}" -fi - if [ -f ./lib/zaf.lib.sh ]; then . ./lib/zaf.lib.sh . ./lib/plugin.lib.sh @@ -60,6 +43,26 @@ else [ -f ${ZAF_LIB_DIR}/zaf.${ZAF_OS}.sh ] && . ${ZAF_LIB_DIR}/zaf.${ZAF_OS}.sh fi +[ -z "$ZAF_TMP_BASE" ] && ZAF_TMP_BASE=/tmp/zaf +ZAF_TMP_DIR="${ZAF_TMP_BASE}-$(zaf_random)" +[ -z "$ZAF_CACHE_DIR" ] && ZAF_CACHE_DIR=${ZAF_TMP_BASE}c + +[ -z "$ZAF_DEBUG" ] && ZAF_DEBUG=1 +export ZAF_DEBUG +export ZAF_LOG_STDERR="-s" + +# If debug is on, do not remove tmp dir +if [ "$ZAF_DEBUG" -le 3 ]; then + trap "rm -rf ${ZAF_TMP_DIR}" EXIT +else + trap 'zaf_wrn "Leaving $ZAF_TMP_DIR" contents due to ZAF_DEBUG.' EXIT +fi + +! [ -d "${ZAF_TMP_DIR}" ] && mkdir "${ZAF_TMP_DIR}" +if ! [ -d "${ZAF_CACHE_DIR}" ]; then + mkdir "${ZAF_CACHE_DIR}" +fi + if zaf_is_root; then chgrp zabbix "${ZAF_CACHE_DIR}" chmod g+w "${ZAF_CACHE_DIR}" @@ -115,15 +118,19 @@ show) zaf_plugin_info $ZAF_PLUGINS_DIR/$plugin/control.zaf done else - if zaf_list_plugins | grep -q "^$1"; then - [ -f $ZAF_PLUGINS_DIR/$1/control.zaf ] && zaf_plugin_info $ZAF_PLUGINS_DIR/$1/control.zaf || zaf_err "Plugin $1 not installed." - else - if echo $1 |grep -q ^http; then - zaf_prepare_plugin "$1" "$ZAF_TMP_DIR/plugin" - zaf_plugin_info "$ZAF_TMP_DIR/plugin/control.zaf" + if echo $1 | grep -vq "\."; then + if zaf_list_plugins | grep -q "^$1"; then + zaf_is_plugin $1 && zaf_plugin_info $ZAF_PLUGINS_DIR/$1/control.zaf || zaf_err "Plugin $1 not installed." else - zaf_err "Plugin $1 not installed." + if echo $1 |grep -q ^http; then + zaf_prepare_plugin "$1" "$ZAF_TMP_DIR/plugin" + zaf_plugin_info "$ZAF_TMP_DIR/plugin/control.zaf" + else + zaf_err "Plugin $1 not installed." + fi fi + else + zaf_item_info "$1" fi fi ;; @@ -153,7 +160,7 @@ test) for p in $plugins; do ! zaf_is_plugin $p && zaf_err "Unknown plugin $p" for i in $(zaf_list_plugin_items $p test); do - echo $i: $(zaf_test_item $i) + zaf_test_item $i echo done done