#!/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 .
alias echo="/bin/echo -e"
color=1
verbose=2
exit_on_fail=0
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 http://$1 $2
}
check_http_200() {
_check_http_status http://$1 200
}
check_https_status() {
# $1 url
# $2 status
_check_http_status https://$1 $2
}
check_https_200() {
_check_http_status https://$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 mplayer to fetch 128Kb of stream
# $1 Stream URL
tmpfile=$(mktemp -t check_audiostream.XXXXXXXXX)
sz="128kb"
if [ "$verbose" -gt 1 ]
then
logdate INFO "$tc_name: Running mplayer on '$1' for $sz" 3
fi
mplayer -endpos $sz -ao pcm:file=$tmpfile "$1" 1>/dev/null 2>/dev/null
res=$?
bytes=$(du $tmpfile | cut -f1)
rm $tmpfile 2>/dev/null
if [ "$bytes" -lt 1024 ]
then
fail "mplayer retrieved ${bytes}B of stream instead of expected $sz"
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_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 | cut -d ' ' -f1,2)" = "stream:stream jabber:$type" ]
then
if [ "$(echo $infos | cut -d ' ' -f3)" = "$serv" ]
then
success "Successfully connected to XMPP $type $serv:$port"
else
fail "Server $serv:$port announce itself as $(echo $infos | cut -f3)"
fi
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 -q1 z3.zered.net $port /dev/null
then
success "OpenSSH replied on $host:$port"
else
fail "Bad replie from $host:$port : '$rep'"
fi
}