#!/bin/sh
#check.sh : functionnal check functions for various server
#Copyright (C) 2016 Weber Yann
#
#This program is free software; you can redistribute it and/or modify
#it under the terms of the GNU General Public License as published by
#the Free Software Foundation; either version 3 of the License, or
#any later version.
#
#This program is distributed in the hope that it will be useful,
#but WITHOUT ANY WARRANTY; without even the implied warranty of
#MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
#GNU General Public License for more details.
#
#You should have received a copy of the GNU General Public License
#along with this program. If not, see .
if [ -z "$color" ]
then
color=1
fi
if [ -z "$verbose" ]
then
verbose=1
fi
if [ -z "$exit_on_fail" ]
then
exit_on_fail=1
fi
alias echo="/bin/echo -e"
col_reset() {
if [ "$color" -gt 0 ]
then
tput sgr0
fi
}
col_set() {
if [ -z "$1" ]
then
return
fi
if [ "$color" -gt 0 ]
then
tput setaf $1
fi
}
log() {
echo "$(col_set $3)[$(printf "%7s" "$1")]$(col_reset) $2"
}
datetime() {
date -Iseconds
}
logdate() {
echo "$(date -Iseconds) $(col_set $3)[$(printf "%7s" "$1")]$(col_reset) $2"
}
fail() {
if [ "$verbose" -lt 2 ]
then
echo "" #for the dot printed with -n
fi
test_msg="$1"
test_status=1
}
err() {
msg="$(log ERR "$1" 1)"
test_msg="$1"
test_status=-1
}
success() {
msg="$(log OK "$1" 2)"
test_msg="$1"
test_status=0
}
#
# Tests & testcase functions
#
tc_name=""
tc_infos=""
tc_fail=0
tc_run=0
total_fail=0
total_run=0
test_msg=""
test_status=0
_test_setup() {
test_status=0
test_msg=""
}
TC_INIT() {
tc_name=$1
tc_infos=$2
tc_fail=0
tc_run=0
msg="Running testcase '$tc_name'"
if [ -n "$tc_infos" ]
then
msg="${msg} ($tc_infos)"
fi
if [ "$verbose" -gt 0 ]
then
logdate TESTCASE "$msg" 4
fi
}
TC_END() {
if [ "$tc_fail" -gt 0 ]
then
if [ "$verbose" -gt 1 ]
then
logdate TESTCASE "-------------$tc_name END------------" 1
fi
logdate FAIL "Testcase '$tc_name' tests: ${tc_run} fails: $(col_set 1)${tc_fail}$(col_reset)" 1
if [ "$exit_on_fail" -ne 0 ]
then
CHECK_REPORT
fi
elif [ "$verbose" -eq 1 ]
then
echo "" #for the dot printed with -n
logdate TESTCASE "Testcase '$tc_name' tests:${tc_run} fails: $tc_fail" 2
elif [ "$verbose" -gt 1 ]
then
logdate TESTCASE "-------------$tc_name END------------" 4
fi
tc_name=""
tc_infos=""
tc_fail=0
tc_run=0
}
TC_RUN() {
_test_setup
cmd=$1
shift
args=""
case $#
in
1)$cmd "$1";;
2)$cmd "$1" "$2";;
3)$cmd "$1" "$2" "$3";;
4)$cmd "$1" "$2" "$3" "$4";;
*)fail "To many arguments for $cmd"
esac
#$cmd $args
tc_run=$(expr $tc_run + 1)
total_run=$(expr $total_run + 1)
if [ "$test_status" -ne 0 ]
then
err_type="FAIL"
if [ "$test_status" -lt 0 ]
then
err_type="ERR"
fi
tc_fail=$(expr $tc_fail + 1)
total_fail=$(expr $total_fail + 1)
logdate $err_type "$tc_name: $test_msg" 1 >&2
elif [ "$verbose" -gt 1 ]
then
logdate OK "$tc_name: $test_msg" 2
else
echo -n '.'
fi
}
CHECK_START() {
logdate STATUS "Starting tests" 3
}
CHECK_REPORT() {
if [ "$verbose" -eq 0 -a "$tc_fail" -eq "0" ]
then
echo "" # for dot printed with -n
fi
if [ "$verbose" -gt 0 ]
then
logdate STATUS "All tests done" 3
fi
if [ "$total_fail" -gt 0 ]
then
logdate FAIL "Summary : tests: ${total_run} fails: $(col_set 1)${total_fail}$(col_reset)" 1
exit 1
else
logdate OK "Summary : tests:${total_run} fails: $total_fail" 2
exit 0
fi
}
#
# HTTP/HTTPS tests
#
_check_http_status() {
# $1 url
# $2 status
# $* curl options
url=$1
shift 1
expt=$1
if [ -z "$1" ]
then
expt=200
fi
shift 1
status=$(curl -s -o /dev/null -w "%{http_code}" $* $url)
if [ "$status" -ne "$expt" ]
then
fail "Check http status $expt for $url : $status returned"
elif [ "$verbose" -gt 0 ]
then
success "Check http status $status for $url"
fi
}
check_http_status() {
# $1 url
# $2 status
_check_http_status $1 $2
}
check_http_200() {
_check_http_status $1 200
}
check_https_cert() {
# Check that SSL Cert is valid
# $1 URL
status=$(curl -s -o /dev/null -w "%{http_code}" https://$1)
rep=$?
if [ "$rep" -eq 0 ]
then
success "https://$1 cert verified"
return
fi
status=$(curl -k -s -o /dev/null -q "%{http_code}" https://$1)
rep=$?
if [ "$rep" -eq 0 ]
then
fail "https://$1 cert invalid"
else
err "Unable to curl https://$1"
fi
}
check_html_title() {
url="$1"
expt="$2"
tmpxsl=$(mktemp -t XSL.XXXXXXXXXXX)
echo '
' > $tmpxsl
tmphtml=$(mktemp -t html.XXXXXXXXX)
curl --silent $url > $tmphtml
title=$(xsltproc --html --novalid $tmpxsl $tmphtml 2>/dev/null)
if [ "$?" -ne "0" ]
then
title=$(xsltproc --novalid $tmpxsl $tmphtml 2>/dev/null)
fi
if [ "$title" = "$expt" ]
then
success "$url HTML title is '$expt'"
else
fail "$url HTML title is '$title' but '$expt' expected"
fi
rm $tmpxsl $tmphtml 2>/dev/null
}
check_audiostream() {
# Uses one of mplayer or mpv to retrieve a small amount of stream
# and attempt to decode it.
# $1 Stream URL
MPLAYER="`which mplayer`"
MPV="`which mpv`"
if [ -x $MPLAYER ]
then
check_audiostream_mplayer "$1"
elif [ -x $MPV ]
then
check_audiostream_mpv "$1"
else
fail "Unable to find mplayer nor mpv"
fi
}
check_audiostream_mplayer() {
# Uses mplayer to fetch 128Kb (by default) of stream
# $1 Stream URL
# $2 size in kb without the kb suffix
# $3 mplayer path
tmpfile=$(mktemp -t check_audiostream.XXXXXXXXX)
sz="$2"
if [ -z "$sz" ]
then
sz="128"
fi
MPLAYER="$3"
if [ -z "$MPLAYER" ]
then
MPLAYER="`which mplayer`"
fi
sz_kb="${sz}kb"
expt_sz="`expr $sz \* 8`"
if [ "$verbose" -gt 1 ]
then
logdate INFO "$tc_name: Running mplayer on '$1' for $sz_kb" 3
fi
$MPLAYER -endpos $sz_kb -ao pcm:file=$tmpfile "$1" 1>/dev/null 2>/dev/null
res=$?
bytes=$(du -b $tmpfile | cut -f1)
rm $tmpfile 2>/dev/null
if [ "$bytes" -lt $expt_sz ]
then
fail "mplayer retrieved ${bytes}B of stream instead of expected $sz_kb"
return
fi
if [ "$res" -eq 0 ]
then
success "mplayer retrieved $sz of stream on $1"
else
fail "mplayer failed to retrieve stream on $1"
fi
}
check_audiostream_mpv() {
# Uses mpv to fetch 4s of audio stream
# $1 Stream URL
# $2 time of stream to fetch
# $3 mpv path
time="$2"
if [ -z "$time" ]
then
time="4"
fi
MPV="$3"
if [ -z "$MPV" ]
then
MPV="`which mpv`"
fi
if [ "$verbose" -gt 1 ]
then
logdate INFO "$tc_name: Running mpv on '$1' for ${time}s" 3
fi
start_time=`date "+%s"`
$MPV --vo=null --ao=null --o=/dev/null --of=wav --length $time "$1" 1> /dev/null 2>/dev/null
res=$?
stop_time=`date "+%s"`
run_time=`expr $stop_time - $start_time`
if [ $run_time -lt $time ]
then
fail "mpv stopped running ${run_time} after launch but ${time}s should be received"
return
fi
if [ $res -eq 0 ]
then
success "mpv retrieved ${time}s of stream on $1"
else
fail "mpv failed to retrieve ${time}s of stream on $1"
fi
}
check_ping() {
ns=$1
count=$2
if [ -z "$count" ]
then
count=5
fi
ping -i 0.2 -c $count $ns 2>/dev/null >/dev/null
res=$?
if [ "$res" -ne 0 ]
then
fail "unable to ping '$ns'"
else
success "successfully send $count ping to '$ns'"
fi
}
check_git_repo() {
tmpdir=$(mktemp -d -t check_git.XXXXXXXXX)
git clone $1 $tmpdir 2>/dev/null 1>/dev/null
res=$?
rm -Rf $tmpdir
if [ "$res" -ne 0 ]
then
fail "unable to clone git repo '$1'"
else
success "git repo '$1' cloned'"
fi
}
#
# Jabber XMPP checks
#
__xmpp_probe() {
serv=$1
timeout=$2
type=$3
payload="\n\n"
if [ "$verbose" -gt 2 ]
then
echo -e $payload | sed -e "s/^/$(datetime) [ DEBUG] Sent : /" >&2
fi
echo -e $payload
sleep $timeout
}
_xmpp_probe() {
serv=$1
port=$2
timeout=$3
type=$4
tmpres=$(mktemp -t xmpp_probe.XXXXXXXXX)
echo "$(__xmpp_probe $serv $timeout $type| nc -q2 $serv $port)" | xmllint --format - > $tmpres
if [ "$verbose" -gt 2 ]
then
cat $tmpres | sed -e "s/^/$(datetime) [ DEBUG] Recv : /" >&2
fi
cat $tmpres
rm $tmpres
}
_check_xmpp_ns() {
ns1=$1
expt_ns=$2
expt_port=$3
dnsq="_xmpp-${4}._tcp.$1"
rep="$(dig $dnsq srv +short | cut -d" " -f3,4)"
if [ "$rep" = "$expt_port ${expt_ns}." ]
then
success "$dnsq = '$rep'"
else
fail "$dnsq = '$rep' but '$expt_port ${expt_ns}.' expected"
fi
}
check_xmpp_serv_ns() {
_check_xmpp_ns "$1" "$2" "$3" "server"
}
check_xmpp_client_ns() {
_check_xmpp_ns "$1" "$2" "$3" "client"
}
_check_xmpp_server() {
serv=$1
port=$2
timeout=$3
type=$4
if [ -z "$port" ]
then
port=5222
fi
if [ -z "$timeout" ]
then
timeout=2
fi
if [ "$verbose" -gt 1 ]
then
tpe="client"
if [ "$type" = "server" ]
then
tpe="S2S"
fi
logdate INFO "$tc_name: Connecting to XMPP $serv $tpe port $port (timeout=${timeout}s)" 3
fi
stream=$(_xmpp_probe $serv $port $timeout $type| head -n2 | tail -n1)
if [ -z "$stream" ]
then
fail "Empty reply from $serv:$port"
return
fi
if [ "$type" = "client" ]
then
infos=$(echo $stream | sed -E 's/^<([^ ]+).* xmlns="([^"]+)".* from="([^"]+)" .*$/\1 \2 \3/')
else
infos="$(echo $stream | sed -E 's/^<([^ ]+).* xmlns="([^"]+)" .*$/\1 \2/') $serv"
fi
if echo "$infos" | grep "jabber:$type" >/dev/null
then
success "Successfully connected to XMPP $type $serv:$port"
else
fail "Unexpected reply from $serv:$port : $infos"
fi
}
check_xmpp_server_client() {
_check_xmpp_server "$1" "$2" "$3" "client"
}
check_xmpp_server_s2s() {
_check_xmpp_server "$1" "$2" "$3" "server"
}
check_xmpp_ssl() {
serv=$1
port=$2
if [ -z "$port" ]
then
port=5222
fi
openssl s_client -connect $serv:$port /dev/null 2>/dev/null
rep=$?
if [ "$rep" -eq 0 ]
then
success "Openssl successfully negociating XMPP ssl with $serv:$port"
else
fail "Openssl failed negociating XMPP ssl with $serv:$port"
fi
}
#
# SSH checks
#
check_ssh_nc() {
host=$1
port=$2
if [ -z "$port" ]
then
port=22
fi
rep="$(nc -w1 $host $port /dev/null
then
success "OpenSSH replied on $host:$port"
else
fail "Bad reply from $host:$port : '$rep'"
fi
}
check_ssh_key() {
host="$1"
testkey="$2"
keytype="$3"
port="$4"
if [ -z "$port" ]
then
port=22
fi
if [ -z "$keytype" ]
then
keytype="rsa"
fi
key=$(ssh-keyscan -p $port -t $keytype $host 2>/dev/null | cut -d " " -f3)
if [ -z "$key" ]
then
fail "SSH server not responding"
return
elif [ "$key" = "$testkey" ]
then
success "OpenSSH $host:$port key is $testkey"
return
else
fail "OpenSSH $host:$port missmatch : "
logdate ERR "Expected : $testkey" 1
logdate ERR "Received : $key" 1
return
fi
}
check_mpc() {
# check_mpc [$host [$port] ]
# tests if you can contact an MPD server in a client way
# returns the current state of the server
host=$1
port=$2
if [ -z "$host" ]
then
host=127.0.0.1
fi
if [ -z "$port" ]
then
port=6600
fi
if echo "status" | nc -w 1 "$host" "$port" | head -1 | grep "^OK MPD"
then
success "MPD server can be contacted on $host:$port"
status=$(echo "status" | nc -w 1 "$host" "$port" | grep "^state:"|cut -d: -f2)
success "It's state is : $status"
fi
}