#!/bin/sh
# PCP QA Test No. 1458
# Exercise access pmproxy with secure.enabled = false
#
# The main purpose of this is to test that the component works correctly
# when secure.enabled = false; we can expect the https URLs to fail.
#
# See https://github.com/performancecopilot/pcp/issues/1490

# Copyright (c) 2019,2021 Red Hat
# Modified by Netflix, Inc.
#

seq=`basename $0`
echo "QA output created by $seq"

# get standard environment, filters and checks
. ./common.product
. ./common.filter
. ./common.check

_check_series	# pmseries availability means libuv is in use
_check_valgrind
openssl help 2>/dev/null || _notrun "No openssl binary found"

if [ -f /etc/lsb-release ]
then
    . /etc/lsb-release
    if [ "$DISTRIB_ID" = Ubuntu ]
    then
	# This test fails for Ubuntu 19.10 with a myriad of errors involving
	# the use of uninitialized values.  The code paths very but typically
	# involve libuv -> libssl ->  libcrypto
	#
	case "$DISTRIB_RELEASE"
	in
	    19.10)
		_notrun "problems with libuv, libssl, libcrypto and valgrind on Ubuntu $DISTRIB_RELEASE"
		;;
	esac
    fi
fi

_cleanup()
{
    cd $here
    if $need_restore
    then
	need_restore=false
	_restore_config $PCP_SYSCONF_DIR/labels
	_sighup_pmcd
    fi
    date >>$seq_full
    for suff in '' .prev
    do
	echo "--- $PCP_LOG_DIR/pmproxy/pmproxy.log$suff ---" >>$seq_full
	if [ -f $PCP_LOG_DIR/pmproxy/pmproxy.log$suff ]
	then
	    cat $PCP_LOG_DIR/pmproxy/pmproxy.log$suff >>$seq_full
	else
	    echo "... does not exist" >>$seq_full
	fi
    done
    if $restart_redis
    then
	_service redis-server start
	echo "Restarting redis-server ..." >>$seq_full
	$PCP_PS_PROG $PCP_PS_ALL_FLAGS | grep -E '[P]PID]|/[r]edis-server( |$)' >>$seq_full
    fi
    $sudo rm -rf $tmp $tmp.*
}

status=1	# failure is the default!
need_restore=false
username=`id -u -n`
trap "_cleanup; exit \$status" 0 1 2 3 15

# if redis-server is installed and running, it needs to be at least
# version 5 ... otherwise stop redis-server and restart when this
# test is done
# redis-server --version output looks like
# Redis server v=3.0.6 sha=00000000:0 malloc=jemalloc-3.6.0 bits=64 build=c15f5256d258cb6b
#
restart_redis=false
if which redis-server >/dev/null 2>&1
then
    redis_vers=`redis-server --version | sed -e 's/.* v=//' -e 's/ .*//'`
    echo "redis_vers=$redis_vers" >>$seq_full
    case "$redis_vers"
    in
	1.*|2.*|3.*|4.*)
	    # too old for pmproxy
	    #
	    $PCP_PS_PROG $PCP_PS_ALL_FLAGS | grep -E '[P]PID]|/[r]edis-server( |$)' >>$seq_full
	    redis_pid=`$PCP_PS_PROG $PCP_PS_ALL_FLAGS | grep '[r]edis-server ' | $PCP_AWK_PROG '{print $2}'`
	    echo "redis_pid=$redis_pid" >>$seq_full
	    if [ -n "$redis_pid" ]
	    then
		_service redis-server stop
		restart_redis=true
	    fi
	    ;;
    esac
fi

_check_empty()
{
    tee -a $seq_full > $tmp.unfiltered
    if [ -s $tmp.unfiltered ]
    then
	echo "Botch: got output from curl"
    else
	echo "Good!, empty output from curl"
    fi
}

_filter_json()
{
    tee -a $seq_full > $tmp.unfiltered
    if [ -s $tmp.unfiltered ]
    then
	pmjson < $tmp.unfiltered > $tmp.filtered
	status=$?
	    if [ $status -eq 0 ]; then
	    cat $tmp.filtered | \
	    sed \
		-e '/"machineid": .*/d' \
		-e 's,"series": .*,"series": "SERIES",g' \
		-e 's,"context": .*,"context": "CONTEXT",g' \
		-e 's,"hostname": .*,"hostname": "HOSTNAME",g' \
		-e 's,"domainname": .*,"domainname": "DOMAINNAME",g' \
	    #end
	else
	    echo "Invalid JSON: $status"
	    cat $tmp.unfiltered
	    rm -f $tmp.context
	fi
    else
	echo "Botch: no output from curl"
    fi
}

_filter_port()
{
    sed \
        -e '/ ipv6 /d' \
	-e "s/ $port / PORT /g" \
    #end
}

# real QA test starts here
_save_config $PCP_SYSCONF_DIR/labels
need_restore=true

$sudo rm -rf $PCP_SYSCONF_DIR/labels/*
_sighup_pmcd || _exit 1

openssl req \
	-new -newkey rsa:4096 -days 365 -nodes -x509 \
	-subj "/C=US/ST=Denial/L=Springfield/O=Dis/CN=www.pcpqa.com" \
	-keyout $tmp.key -out $tmp.cert >>$seq_full 2>&1
# creates a self-signed (insecure) certificate, so for testing only

echo "[keys]" >> $tmp.conf
echo "enabled = false" >> $tmp.conf
echo "[pmproxy]" >> $tmp.conf
echo "http.enabled = true" >> $tmp.conf
echo "secure.enabled = false" >> $tmp.conf

port=`_find_free_port`
mkdir -p $tmp.pmproxy/pmproxy
export PCP_RUN_DIR=$tmp.pmproxy
export PCP_TMP_DIR=$tmp.pmproxy

$valgrind_clean_assert pmproxy -f -l- --timeseries \
	-c $tmp.conf -p $port -U $username \
	>$tmp.valout 2>$tmp.valerr &
pid=$!

echo "valgrind pid: $pid" >>$seq_full
echo "pmproxy port: $port" >>$seq_full

# valgrind takes awhile to fire up
date >>$seq_full
i=0
while [ $i -lt 40 ]
do
    $PCP_BINADM_DIR/telnet-probe -c localhost $port && break
    sleep 1
    i=`expr $i + 1`
done
if $PCP_BINADM_DIR/telnet-probe -c localhost $port
then
    echo "Startup took $i secs" >>$seq_full
else
    echo "Arrgh: valgrind failed start pmproxy and get port $port ready after 40 secs"
    $PCP_PS_PROG $PCP_PS_ALL_FLAGS | grep -E '[P]PID]|/[p]mproxy( |$)|[v]algrind ' >$tmp.triage 2>&1
    if [ -s $tmp.triage ]
    then
	echo "--- likely looking processes ..." >>$seq_full
	cat $tmp.triage >>$seq_full
    else
	echo "--- there are no likely looking processes!" >>$seq_full
    fi
    echo "--- valgrind stdout ---" >>$seq_full
    cat $tmp.valout >>$seq_full
    echo "--- valgrind stderr ---" >>$seq_full
    cat $tmp.valerr >>$seq_full
    exit
fi

date >>$seq_full
echo "=== checking serial http operation ===" | tee -a $seq_full
for i in 1 2 3 4; do
    curl -Gs "http://localhost:$port/pmapi/metric?name=sample.long.ten" 2>$tmp.err$i >$tmp.out$i
done
for i in 1 2 3 4; do
echo === out$i === | tee -a $seq_full
_filter_json < $tmp.out$i
done

date >>$seq_full
echo "=== checking parallel http operation ===" | tee -a $seq_full
for i in 1 2 3 4; do
    curl -Gs "http://localhost:$port/pmapi/metric?name=sample.long.ten" 2>$tmp.err$i >$tmp.out$i & 2>/dev/null eval pid$i=$!
done
wait $pid1 $pid2 $pid3 $pid4
for i in 1 2 3 4; do
echo === out$i === | tee -a $seq_full
_filter_json < $tmp.out$i
done

date >>$seq_full
echo "=== checking serial https/TLS operation ===" | tee -a $seq_full
for i in 1 2 3 4; do
    curl -k -Gs "https://localhost:$port/pmapi/metric?name=sample.long.ten" 2>$tmp.err$i >$tmp.out$i
done
for i in 1 2 3 4; do
echo === out$i === | tee -a $seq_full
_check_empty < $tmp.out$i
done

date >>$seq_full
echo "=== checking parallel https/TLS operation ===" | tee -a $seq_full
for i in 1 2 3 4; do
    curl -k -Gs "https://localhost:$port/pmapi/metric?name=sample.long.ten" 2>$tmp.err$i >$tmp.out$i & 2>/dev/null eval pid$i=$!
done
wait $pid1 $pid2 $pid3 $pid4
for i in 1 2 3 4; do
echo === out$i === | tee -a $seq_full
_check_empty < $tmp.out$i
done

echo "=== check pmproxy is running ==="
pminfo -v -h localhost@localhost:$port hinv.ncpu
if [ $? -eq 0 ]; then
    echo "pmproxy check passed"
else
    echo "pmproxy check failed"
fi

# valgrind takes awhile to shutdown too
pmsignal $pid >/dev/null 2>&1
pmsleep 3.5
echo "=== valgrind stdout ===" | tee -a $seq_full
cat $tmp.valout | _filter_valgrind

echo "=== valgrind stderr ===" | tee -a $seq_full
cat $tmp.valerr | _filter_pmproxy_log | _filter_port \
| sed -e '/Cannot connect to key server: Connection refused/d'

# final kill if it's spinning
$sudo kill -9 $pid >/dev/null 2>&1

# success, all done
status=0
exit
