BZ 1849511 - resolve covscan and other issues from upstream QA  f7f1dd546 pmproxy: complete handling of HTTP/1.1 TRACE requests cc662872b qa: add pcp-free-tera archive to pcp-testsuite package 80639d05b pmlogger_check.sh: major overhaul (diags and systemd fixups) 460b7ac2a src/pmlogger/rc_pmlogger: use --quick to pmlogger_check 0b3b4d4ee src/pmlogger/pmlogger_check.service.in: add --skip-primary arg to pmlogger_check 3a68366a8 src/pmlogger/pmlogger.service.in: change ancillary services from After to Before 5d65a6035 src/pmlogger/pmlogger_daily.sh: similar changes to pmlogger_check.sh ace576907 src/pmlogger/pmlogger_check.sh: fix locking snarfoo 2b2c3db11 src/pmlogger/pmlogger_daily.sh: fix diagnostic spaghetti 4cc54287f pmproxy: allow URLs up to 8k in length diff -auNr pcp-5.1.1-004/man/man1/pmlogger_check.1 pcp-5.1.1-005/man/man1/pmlogger_check.1 --- pcp-5.1.1-004/man/man1/pmlogger_check.1 2020-04-07 13:31:03.000000000 +1000 +++ pcp-5.1.1-005/man/man1/pmlogger_check.1 2020-06-22 20:08:18.454403788 +1000 @@ -19,7 +19,7 @@ \f3pmlogger_daily\f1 \- administration of Performance Co-Pilot archive log files .SH SYNOPSIS .B $PCP_BINADM_DIR/pmlogger_check -[\f3\-CNsTV?\f1] +[\f3\-CNpqsTV?\f1] [\f3\-c\f1 \f2control\f1] [\f3\-l\f1 \f2logfile\f1] .br @@ -269,6 +269,20 @@ .TP \fB\-p\fR If this option is specified for +.B pmlogger_check +then any line from the control files for the +.I primary +.B pmlogger +will be ignored. +This option is intended for environments where some system daemon, +like +.BR systemd (1), +is responsible for controlling (starting, stopping, restarting, etc.) the +.I primary +.BR pmlogger . +.TP +\fB\-p\fR +If this option is specified for .B pmlogger_daily then the status of the daily processing is polled and if the daily .BR pmlogger (1) @@ -296,6 +310,12 @@ .B pmlogger_daily are mutually exclusive. .TP +\fB\-q\fR +If this option is specified for +.B pmlogger_check +then the script will ``quickstart'' avoiding any optional processing +like file compression. +.TP \fB\-r\fR, \fB\-\-norewrite\fR This command line option acts as an override and prevents all archive rewriting with diff -auNr pcp-5.1.1-004/qa/1837 pcp-5.1.1-005/qa/1837 --- pcp-5.1.1-004/qa/1837 2020-06-22 20:00:17.636331169 +1000 +++ pcp-5.1.1-005/qa/1837 2020-06-22 20:08:18.457403819 +1000 @@ -1,6 +1,6 @@ #!/bin/sh # PCP QA Test No. 1837 -# Exercise PMWEBAPI handling server OPTIONS. +# Exercise PMWEBAPI handling server OPTIONS and TRACE. # # Copyright (c) 2020 Red Hat. All Rights Reserved. # @@ -43,7 +43,12 @@ # real QA test starts here _service pmproxy restart >/dev/null 2>&1 -curl -isS --request-target "*" -X OPTIONS http://localhost:44322 \ +echo; echo "=== OPTIONS" +curl -isS -X OPTIONS --request-target "*" http://localhost:44322 \ + 2>&1 | tee -a $here/$seq.full | _webapi_header_filter + +echo; echo "=== TRACE" +curl -isS -X TRACE http://localhost:44322 \ 2>&1 | tee -a $here/$seq.full | _webapi_header_filter echo >>$here/$seq.full diff -auNr pcp-5.1.1-004/qa/1837.out pcp-5.1.1-005/qa/1837.out --- pcp-5.1.1-004/qa/1837.out 2020-06-22 20:00:17.637331179 +1000 +++ pcp-5.1.1-005/qa/1837.out 2020-06-22 20:08:18.457403819 +1000 @@ -1,6 +1,17 @@ QA output created by 1837 +=== OPTIONS + Access-Control-Allow-Methods: GET, PUT, HEAD, POST, TRACE, OPTIONS Content-Length: 0 Date: DATE HTTP/1.1 200 OK + +=== TRACE + +Accept: */* +Content-Length: 0 +Date: DATE +HTTP/1.1 200 OK +Host: localhost:44322 +User-Agent: curl VERSION diff -auNr pcp-5.1.1-004/qa/archives/GNUmakefile pcp-5.1.1-005/qa/archives/GNUmakefile --- pcp-5.1.1-004/qa/archives/GNUmakefile 2020-03-19 15:15:42.000000000 +1100 +++ pcp-5.1.1-005/qa/archives/GNUmakefile 2020-06-22 20:08:18.461403861 +1000 @@ -35,6 +35,7 @@ pcp-atop.0.xz pcp-atop.meta pcp-atop.index \ pcp-atop-boot.0.xz pcp-atop-boot.meta pcp-atop-boot.index \ pcp-dstat.0.xz pcp-dstat.meta pcp-dstat.index \ + pcp-free-tera.0.xz pcp-free-tera.meta.xz pcp-free-tera.index \ pcp-hotatop.0.xz pcp-hotatop.meta pcp-hotatop.index \ pcp-zeroconf.0.xz pcp-zeroconf.meta pcp-zeroconf.index \ value-test.0.xz value-test.meta value-test.index \ diff -auNr pcp-5.1.1-004/qa/common.check pcp-5.1.1-005/qa/common.check --- pcp-5.1.1-004/qa/common.check 2020-06-22 20:00:17.637331179 +1000 +++ pcp-5.1.1-005/qa/common.check 2020-06-22 20:08:18.459403840 +1000 @@ -2697,6 +2697,7 @@ | col -b \ | sed \ -e 's/^\(Content-Length:\) [1-9][0-9]*/\1 SIZE/g' \ + -e 's/^\(User-Agent: curl\).*/\1 VERSION/g' \ -e 's/^\(Date:\).*/\1 DATE/g' \ -e 's/\(\"context\":\) [0-9][0-9]*/\1 CTXID/g' \ -e '/^Connection: Keep-Alive/d' \ diff -auNr pcp-5.1.1-004/src/pmlogger/pmlogger_check.service.in pcp-5.1.1-005/src/pmlogger/pmlogger_check.service.in --- pcp-5.1.1-004/src/pmlogger/pmlogger_check.service.in 2020-05-22 16:40:09.000000000 +1000 +++ pcp-5.1.1-005/src/pmlogger/pmlogger_check.service.in 2020-06-22 20:08:18.452403767 +1000 @@ -6,7 +6,7 @@ [Service] Type=oneshot TimeoutStartSec=25m -Environment="PMLOGGER_CHECK_PARAMS=-C" +Environment="PMLOGGER_CHECK_PARAMS=-C --skip-primary" EnvironmentFile=-@PCP_SYSCONFIG_DIR@/pmlogger_timers ExecStart=@PCP_BINADM_DIR@/pmlogger_check $PMLOGGER_CHECK_PARAMS WorkingDirectory=@PCP_VAR_DIR@ diff -auNr pcp-5.1.1-004/src/pmlogger/pmlogger_check.sh pcp-5.1.1-005/src/pmlogger/pmlogger_check.sh --- pcp-5.1.1-004/src/pmlogger/pmlogger_check.sh 2020-05-04 09:52:04.000000000 +1000 +++ pcp-5.1.1-005/src/pmlogger/pmlogger_check.sh 2020-06-22 20:13:04.029416598 +1000 @@ -36,16 +36,24 @@ echo >$tmp/lock prog=`basename $0` PROGLOG=$PCP_LOG_DIR/pmlogger/$prog.log +MYPROGLOG=$PROGLOG.$$ USE_SYSLOG=true _cleanup() { + if [ -s "$MYPROGLOG" ] + then + rm -f "$PROGLOG" + mv "$MYPROGLOG" "$PROGLOG" + else + rm -f "$MYPROGLOG" + fi $USE_SYSLOG && [ $status -ne 0 ] && \ $PCP_SYSLOG_PROG -p daemon.error "$prog failed - see $PROGLOG" - [ -s "$PROGLOG" ] || rm -f "$PROGLOG" lockfile=`cat $tmp/lock 2>/dev/null` rm -f "$lockfile" rm -rf $tmp + $VERY_VERBOSE && echo "End: `date '+%F %T.%N'`" } trap "_cleanup; exit \$status" 0 1 2 3 15 @@ -86,6 +94,8 @@ CHECK_RUNLEVEL=false START_PMLOGGER=true STOP_PMLOGGER=false +QUICKSTART=false +SKIP_PRIMARY=false echo > $tmp/usage cat >> $tmp/usage << EOF @@ -94,6 +104,8 @@ -l=FILE,--logfile=FILE send important diagnostic messages to FILE -C query system service runlevel information -N,--showme perform a dry run, showing what would be done + -p,--skip-primary do not start or stop the primary pmlogger instance + -q,--quick quick start, no compression -s,--stop stop pmlogger processes instead of starting them -T,--terse produce a terser form of output -V,--verbose increase diagnostic verbosity @@ -117,6 +129,7 @@ -C) CHECK_RUNLEVEL=true ;; -l) PROGLOG="$2" + MYPROGLOG="$PROGLOG".$$ USE_SYSLOG=false daily_args="${daily_args} -l $2.from.check" shift @@ -129,6 +142,10 @@ KILL="echo + kill" daily_args="${daily_args} -N" ;; + -p) SKIP_PRIMARY=true + ;; + -q) QUICKSTART=true + ;; -s) START_PMLOGGER=false STOP_PMLOGGER=true ;; @@ -162,9 +179,15 @@ _compress_now() { - # If $PCP_COMPRESSAFTER=0 in the control file(s), compress archives now. - # Invoked just before exit when this script has finished successfully. - $PCP_BINADM_DIR/pmlogger_daily -K $daily_args + if $QUICKSTART + then + $VERY_VERBOSE && echo "Skip compression, -q/--quick on command line" + else + # If $PCP_COMPRESSAFTER=0 in the control file(s), compress archives now. + # Invoked just before exit when this script has finished successfully. + $VERY_VERBOSE && echo "Doing compression ..." + $PCP_BINADM_DIR/pmlogger_daily -K $daily_args + fi } # after argument checking, everything must be logged to ensure no mail is @@ -187,26 +210,37 @@ # # Exception ($SHOWME, above) is for -N where we want to see the output. # - touch "$PROGLOG" - chown $PCP_USER:$PCP_GROUP "$PROGLOG" >/dev/null 2>&1 - exec 1>"$PROGLOG" 2>&1 + touch "$MYPROGLOG" + chown $PCP_USER:$PCP_GROUP "$MYPROGLOG" >/dev/null 2>&1 + exec 1>"$MYPROGLOG" 2>&1 +fi + +if $VERY_VERBOSE +then + echo "Start: `date '+%F %T.%N'`" + if `which pstree >/dev/null 2>&1` + then + echo "Called from:" + pstree -spa $$ + echo "--- end of pstree output ---" + fi fi # if SaveLogs exists in the $PCP_LOG_DIR/pmlogger directory then save -# $PROGLOG there as well with a unique name that contains the date and time +# $MYPROGLOG there as well with a unique name that contains the date and time # when we're run # if [ -d $PCP_LOG_DIR/pmlogger/SaveLogs ] then - now="`date '+%Y%m%d.%H.%M'`" - link=`echo $PROGLOG | sed -e "s/$prog/SaveLogs\/$prog.$now/"` + now="`date '+%Y%m%d.%H.%M.%S'`" + link=`echo $MYPROGLOG | sed -e "s/$prog/SaveLogs\/$prog.$now/"` if [ ! -f "$link" ] then if $SHOWME then - echo "+ ln $PROGLOG $link" + echo "+ ln $MYPROGLOG $link" else - ln $PROGLOG $link + ln $MYPROGLOG $link fi fi fi @@ -273,7 +307,7 @@ _unlock() { - rm -f lock + rm -f "$1/lock" echo >$tmp/lock } @@ -395,6 +429,41 @@ echo "$pid" } +# wait for the local pmcd to get going for a primary pmlogger +# (borrowed from qa/common.check) +# +# wait_for_pmcd [maxdelay] +# +_wait_for_pmcd() +{ + # 5 seconds default seems like a reasonable max time to get going + _can_wait=${1-5} + _limit=`expr $_can_wait \* 10` + _i=0 + _dead=true + while [ $_i -lt $_limit ] + do + _sts=`pmprobe pmcd.numclients 2>/dev/null | $PCP_AWK_PROG '{print $2}'` + if [ "${_sts:-0}" -gt 0 ] + then + # numval really > 0, we're done + # + _dead=false + break + fi + pmsleep 0.1 + _i=`expr $_i + 1` + done + if $_dead + then + date + echo "Arrgghhh ... pmcd at localhost failed to start after $_can_wait seconds" + echo "=== failing pmprobes ===" + pmprobe pmcd.numclients + status=1 + fi +} + _check_archive() { if [ ! -e "$logfile" ] @@ -531,7 +600,17 @@ cd "$here" line=`expr $line + 1` - $VERY_VERBOSE && echo "[$controlfile:$line] host=\"$host\" primary=\"$primary\" socks=\"$socks\" dir=\"$dir\" args=\"$args\"" + + if $VERY_VERBOSE + then + case "$host" + in + \#*|'') # comment or empty + ;; + *) echo "[$controlfile:$line] host=\"$host\" primary=\"$primary\" socks=\"$socks\" dir=\"$dir\" args=\"$args\"" + ;; + esac + fi case "$host" in @@ -599,6 +678,15 @@ continue fi + # if -s/--skip-primary on the command line, do not process + # a control file line for the primary pmlogger + # + if $SKIP_PRIMARY && [ $primary = y ] + then + $VERY_VERBOSE && echo "Skip, -s/--skip-primary on command line" + continue + fi + # substitute LOCALHOSTNAME marker in this config line # (differently for directory and pcp -h HOST arguments) # @@ -610,7 +698,7 @@ then pflag='' [ $primary = y ] && pflag=' -P' - echo "Check pmlogger$pflag -h $host ... in $dir ..." + echo "Checking for: pmlogger$pflag -h $host ... in $dir ..." fi # check for directory duplicate entries @@ -664,19 +752,25 @@ delay=200 # tenths of a second while [ $delay -gt 0 ] do - if pmlock -v lock >$tmp/out 2>&1 + if pmlock -v "$dir/lock" >$tmp/out 2>&1 then - echo $dir/lock >$tmp/lock + echo "$dir/lock" >$tmp/lock + if $VERY_VERBOSE + then + echo "Acquired lock:" + ls -l $dir/lock + fi break else [ -f $tmp/stamp ] || touch -t `pmdate -30M %Y%m%d%H%M` $tmp/stamp - if [ -z "`find lock -newer $tmp/stamp -print 2>/dev/null`" ] + find $tmp/stamp -newer "$dir/lock" -print 2>/dev/null >$tmp/tmp + if [ -s $tmp/tmp ] then - if [ -f lock ] + if [ -f "$dir/lock" ] then echo "$prog: Warning: removing lock file older than 30 minutes" LC_TIME=POSIX ls -l $dir/lock - rm -f lock + rm -f "$dir/lock" else # there is a small timing window here where pmlock # might fail, but the lock file has been removed by @@ -714,7 +808,7 @@ continue fi fi - if [ -f lock ] + if [ -f "$dir/lock" ] then echo "$prog: Warning: is another PCP cron job running concurrently?" LC_TIME=POSIX ls -l $dir/lock @@ -753,6 +847,14 @@ $VERY_VERBOSE && echo "primary pmlogger process $pid not running" pid='' fi + else + if $VERY_VERBOSE + then + echo "$PCP_TMP_DIR/pmlogger/primary: missing?" + echo "Contents of $PCP_TMP_DIR/pmlogger" + ls -l $PCP_TMP_DIR/pmlogger + echo "--- end of ls output ---" + fi fi else for log in $PCP_TMP_DIR/pmlogger/[0-9]* @@ -798,6 +900,17 @@ # PM_LOG_PORT_DIR="$PCP_TMP_DIR/pmlogger" rm -f "$PM_LOG_PORT_DIR/primary" + # We really starting the primary pmlogger to work, especially + # in the systemd world, so make sure pmcd is ready to accept + # connections. + # + _wait_for_pmcd + if [ "$status" = 1 ] + then + $VERY_VERBOSE && echo "pmcd not running, skip primary pmlogger" + _unlock "$dir" + continue + fi else args="-h $host $args" envs="" @@ -870,7 +983,7 @@ then echo echo "+ ${sock_me}$PMLOGGER $args $LOGNAME" - _unlock + _unlock "$dir" continue else $PCP_BINADM_DIR/pmpost "start pmlogger from $prog for host $host" @@ -903,7 +1016,7 @@ $PCP_ECHO_PROG $PCP_ECHO_N "$pid ""$PCP_ECHO_C" >> $tmp/pmloggers fi - _unlock + _unlock "$dir" done } diff -auNr pcp-5.1.1-004/src/pmlogger/pmlogger_daily.sh pcp-5.1.1-005/src/pmlogger/pmlogger_daily.sh --- pcp-5.1.1-004/src/pmlogger/pmlogger_daily.sh 2020-04-07 13:31:03.000000000 +1000 +++ pcp-5.1.1-005/src/pmlogger/pmlogger_daily.sh 2020-06-22 20:08:18.451403756 +1000 @@ -31,16 +31,24 @@ echo >$tmp/lock prog=`basename $0` PROGLOG=$PCP_LOG_DIR/pmlogger/$prog.log +MYPROGLOG=$PROGLOG.$$ USE_SYSLOG=true _cleanup() { + if [ -s "$MYPROGLOG" ] + then + rm -f "$PROGLOG" + mv "$MYPROGLOG" "$PROGLOG" + else + rm -f "$MYPROGLOG" + fi $USE_SYSLOG && [ $status -ne 0 ] && \ $PCP_SYSLOG_PROG -p daemon.error "$prog failed - see $PROGLOG" - [ -s "$PROGLOG" ] || rm -f "$PROGLOG" lockfile=`cat $tmp/lock 2>/dev/null` rm -f "$lockfile" "$PCP_RUN_DIR/pmlogger_daily.pid" rm -rf $tmp + $VERY_VERBOSE && echo "End: `date '+%F %T.%N'`" } trap "_cleanup; exit \$status" 0 1 2 3 15 @@ -215,8 +223,10 @@ fi COMPRESSONLY=true PROGLOG=$PCP_LOG_DIR/pmlogger/$prog-K.log + MYPROGLOG=$PROGLOG.$$ ;; -l) PROGLOG="$2" + MYPROGLOG=$PROGLOG.$$ USE_SYSLOG=false shift ;; @@ -278,6 +288,7 @@ # $PCP_LOG_DIR/pmlogger/daily..trace # PROGLOG=$PCP_LOG_DIR/pmlogger/daily.`date "+%Y%m%d.%H.%M"`.trace + MYPROGLOG=$PROGLOG.$$ VERBOSE=true VERY_VERBOSE=true MYARGS="$MYARGS -V -V" @@ -418,13 +429,23 @@ # # Exception ($SHOWME, above) is for -N where we want to see the output. # - touch "$PROGLOG" - chown $PCP_USER:$PCP_GROUP "$PROGLOG" >/dev/null 2>&1 - exec 1>"$PROGLOG" 2>&1 + touch "$MYPROGLOG" + chown $PCP_USER:$PCP_GROUP "$MYPROGLOG" >/dev/null 2>&1 + exec 1>"$MYPROGLOG" 2>&1 +fi + +if $VERY_VERBOSE +then + echo "Start: `date '+%F %T.%N'`" + if `which pstree >/dev/null 2>&1` + then + echo "Called from:" + pstree -spa $$ + fi fi # if SaveLogs exists in the $PCP_LOG_DIR/pmlogger directory then save -# $PROGLOG there as well with a unique name that contains the date and time +# $MYPROGLOG there as well with a unique name that contains the date and time # when we're run ... skip if -N (showme) # if $SHOWME @@ -433,15 +454,15 @@ else if [ -d $PCP_LOG_DIR/pmlogger/SaveLogs ] then - now="`date '+%Y%m%d.%H.%M'`" - link=`echo $PROGLOG | sed -e "s/$prog/SaveLogs\/$prog.$now/"` + now="`date '+%Y%m%d.%H.%M.%S'`" + link=`echo $MYPROGLOG | sed -e "s/$prog/SaveLogs\/$prog.$now/"` if [ ! -f "$link" ] then if $SHOWME then - echo "+ ln $PROGLOG $link" + echo "+ ln $MYPROGLOG $link" else - ln $PROGLOG $link + ln $MYPROGLOG $link fi fi fi @@ -487,19 +508,20 @@ delay=200 # tenths of a second while [ $delay -gt 0 ] do - if pmlock -v lock >>$tmp/out 2>&1 + if pmlock -v "$1/lock" >>$tmp/out 2>&1 then - echo $1/lock >$tmp/lock + echo "$1/lock" >$tmp/lock break else [ -f $tmp/stamp ] || touch -t `pmdate -30M %Y%m%d%H%M` $tmp/stamp - if [ ! -z "`find lock -newer $tmp/stamp -print 2>/dev/null`" ] + find $tmp/stamp -newer "$1/lock" -print 2>/dev/null >$tmp/tmp + if [ -s $tmp/tmp ] then - if [ -f lock ] + if [ -f "$1/lock" ] then _warning "removing lock file older than 30 minutes" - LC_TIME=POSIX ls -l $1/lock - rm -f lock + LC_TIME=POSIX ls -l "$1/lock" + rm -f "$1/lock" else # there is a small timing window here where pmlock # might fail, but the lock file has been removed by @@ -517,10 +539,10 @@ then # failed to gain mutex lock # - if [ -f lock ] + if [ -f "$1/lock" ] then _warning "is another PCP cron job running concurrently?" - LC_TIME=POSIX ls -l $1/lock + LC_TIME=POSIX ls -l "$1/lock" else echo "$prog: `cat $tmp/out`" fi @@ -534,7 +556,7 @@ _unlock() { - rm -f lock + rm -f "$1/lock" echo >$tmp/lock } @@ -703,6 +725,9 @@ # if the directory containing the archive matches, then the name # of the file is the pid. # +# The pid(s) (if any) appear on stdout, so be careful to send any +# diagnostics to stderr. +# _get_non_primary_logger_pid() { pid='' @@ -713,7 +738,7 @@ then _host=`sed -n 2p <$log` _arch=`sed -n 3p <$log` - $PCP_ECHO_PROG $PCP_ECHO_N "... try $log host=$_host arch=$_arch: ""$PCP_ECHO_C" + $PCP_ECHO_PROG >&2 $PCP_ECHO_N "... try $log host=$_host arch=$_arch: ""$PCP_ECHO_C" fi # throw away stderr in case $log has been removed by now match=`sed -e '3s@/[^/]*$@@' $log 2>/dev/null | \ @@ -721,19 +746,19 @@ BEGIN { m = 0 } NR == 3 && $0 == "'$dir'" { m = 2; next } END { print m }'` - $VERY_VERBOSE && $PCP_ECHO_PROG $PCP_ECHO_N "match=$match ""$PCP_ECHO_C" + $VERY_VERBOSE && $PCP_ECHO_PROG >&2 $PCP_ECHO_N "match=$match ""$PCP_ECHO_C" if [ "$match" = 2 ] then pid=`echo $log | sed -e 's,.*/,,'` if _get_pids_by_name pmlogger | grep "^$pid\$" >/dev/null then - $VERY_VERBOSE && echo "pmlogger process $pid identified, OK" + $VERY_VERBOSE && echo >&2 "pmlogger process $pid identified, OK" break fi - $VERY_VERBOSE && echo "pmlogger process $pid not running, skip" + $VERY_VERBOSE && echo >&2 "pmlogger process $pid not running, skip" pid='' else - $VERY_VERBOSE && echo "different directory, skip" + $VERY_VERBOSE && echo >&2 "different directory, skip" fi done echo "$pid" @@ -1028,6 +1053,8 @@ pid='' fi else + # pid(s) on stdout, diagnostics on stderr + # pid=`_get_non_primary_logger_pid` if $VERY_VERBOSE then @@ -1458,7 +1485,7 @@ fi fi - _unlock + _unlock "$dir" done } diff -auNr pcp-5.1.1-004/src/pmlogger/pmlogger.service.in pcp-5.1.1-005/src/pmlogger/pmlogger.service.in --- pcp-5.1.1-004/src/pmlogger/pmlogger.service.in 2020-06-22 20:00:17.634331148 +1000 +++ pcp-5.1.1-005/src/pmlogger/pmlogger.service.in 2020-06-22 20:08:18.452403767 +1000 @@ -2,7 +2,7 @@ Description=Performance Metrics Archive Logger Documentation=man:pmlogger(1) After=network-online.target pmcd.service -After=pmlogger_check.timer pmlogger_check.path pmlogger_daily.timer pmlogger_daily-poll.timer +Before=pmlogger_check.timer pmlogger_check.path pmlogger_daily.timer pmlogger_daily-poll.timer BindsTo=pmlogger_check.timer pmlogger_check.path pmlogger_daily.timer pmlogger_daily-poll.timer Wants=pmcd.service diff -auNr pcp-5.1.1-004/src/pmlogger/rc_pmlogger pcp-5.1.1-005/src/pmlogger/rc_pmlogger --- pcp-5.1.1-004/src/pmlogger/rc_pmlogger 2020-04-21 10:42:02.000000000 +1000 +++ pcp-5.1.1-005/src/pmlogger/rc_pmlogger 2020-06-22 20:08:18.453403777 +1000 @@ -96,7 +96,7 @@ bgtmp=`mktemp -d $PCP_DIR/var/tmp/pcp.XXXXXXXXX` || exit 1 trap "rm -rf $bgtmp; exit \$bgstatus" 0 1 2 3 15 - pmlogger_check $VFLAG >$bgtmp/pmcheck.out 2>$bgtmp/pmcheck + pmlogger_check --quick $VFLAG >$bgtmp/pmcheck.out 2>$bgtmp/pmcheck bgstatus=$? if [ -s $bgtmp/pmcheck ] then @@ -125,8 +125,6 @@ false else # Really start the pmlogger instances based on the control file. - # Done in the background to avoid delaying the init script, - # failure notification is external (syslog, log files). # $ECHO $PCP_ECHO_N "Starting pmlogger ..." "$PCP_ECHO_C" @@ -234,11 +232,9 @@ if [ $VERBOSE_CTL = on ] then # For a verbose startup and shutdown ECHO=$PCP_ECHO_PROG - REBUILDOPT='' VFLAG='-V' else # For a quiet startup and shutdown ECHO=: - REBUILDOPT=-s VFLAG= fi diff -auNr pcp-5.1.1-004/src/pmproxy/src/http.c pcp-5.1.1-005/src/pmproxy/src/http.c --- pcp-5.1.1-004/src/pmproxy/src/http.c 2020-06-22 20:00:17.635331158 +1000 +++ pcp-5.1.1-005/src/pmproxy/src/http.c 2020-06-22 20:08:18.460403851 +1000 @@ -324,17 +324,36 @@ } static sds -http_response_trace(struct client *client) +http_response_trace(struct client *client, int sts) { + struct http_parser *parser = &client->u.http.parser; dictIterator *iterator; dictEntry *entry; - sds result = sdsempty(); + char buffer[64]; + sds header; + + parser->http_major = parser->http_minor = 1; + + header = sdscatfmt(sdsempty(), + "HTTP/%u.%u %u %s\r\n" + "%S: Keep-Alive\r\n", + parser->http_major, parser->http_minor, + sts, http_status_mapping(sts), HEADER_CONNECTION); + header = sdscatfmt(header, "%S: %u\r\n", HEADER_CONTENT_LENGTH, 0); iterator = dictGetSafeIterator(client->u.http.headers); while ((entry = dictNext(iterator)) != NULL) - result = sdscatfmt("%S: %S\r\n", dictGetKey(entry), dictGetVal(entry)); + header = sdscatfmt(header, "%S: %S\r\n", dictGetKey(entry), dictGetVal(entry)); dictReleaseIterator(iterator); - return result; + + header = sdscatfmt(header, "Date: %s\r\n\r\n", + http_date_string(time(NULL), buffer, sizeof(buffer))); + + if (pmDebugOptions.http && pmDebugOptions.desperate) { + fprintf(stderr, "trace response to client %p\n", client); + fputs(header, stderr); + } + return header; } static sds @@ -418,7 +437,7 @@ if (client->u.http.parser.method == HTTP_OPTIONS) buffer = http_response_access(client, sts, options); else if (client->u.http.parser.method == HTTP_TRACE) - buffer = http_response_trace(client); + buffer = http_response_trace(client, sts); else /* HTTP_HEAD */ buffer = http_response_header(client, 0, sts, type); suffix = NULL; @@ -533,6 +552,8 @@ if (servlet && servlet->on_release) servlet->on_release(client); client->u.http.privdata = NULL; + client->u.http.servlet = NULL; + client->u.http.flags = 0; if (client->u.http.headers) { dictRelease(client->u.http.headers); @@ -696,29 +717,39 @@ { struct client *client = (struct client *)request->data; struct servlet *servlet; - sds buffer; int sts; http_client_release(client); /* new URL, clean slate */ - /* server options - https://tools.ietf.org/html/rfc7231#section-4.3.7 */ - if (length == 1 && *offset == '*' && - client->u.http.parser.method == HTTP_OPTIONS) { - buffer = http_response_access(client, HTTP_STATUS_OK, HTTP_SERVER_OPTIONS); - client_write(client, buffer, NULL); - } else if ((servlet = servlet_lookup(client, offset, length)) != NULL) { + /* pass to servlets handling each of our internal request endpoints */ + if ((servlet = servlet_lookup(client, offset, length)) != NULL) { client->u.http.servlet = servlet; - if ((sts = client->u.http.parser.status_code) == 0) { + if ((sts = client->u.http.parser.status_code) != 0) + http_error(client, sts, "failed to process URL"); + else { if (client->u.http.parser.method == HTTP_OPTIONS || client->u.http.parser.method == HTTP_TRACE || client->u.http.parser.method == HTTP_HEAD) client->u.http.flags |= HTTP_FLAG_NO_BODY; - else - client->u.http.flags &= ~HTTP_FLAG_NO_BODY; client->u.http.headers = dictCreate(&sdsOwnDictCallBacks, NULL); - return 0; } - http_error(client, sts, "failed to process URL"); - } else { + } + /* server options - https://tools.ietf.org/html/rfc7231#section-4.3.7 */ + else if (client->u.http.parser.method == HTTP_OPTIONS) { + if (length == 1 && *offset == '*') { + client->u.http.flags |= HTTP_FLAG_NO_BODY; + client->u.http.headers = dictCreate(&sdsOwnDictCallBacks, NULL); + } else { + sts = client->u.http.parser.status_code = HTTP_STATUS_BAD_REQUEST; + http_error(client, sts, "no handler for OPTIONS"); + } + } + /* server trace - https://tools.ietf.org/html/rfc7231#section-4.3.8 */ + else if (client->u.http.parser.method == HTTP_TRACE) { + client->u.http.flags |= HTTP_FLAG_NO_BODY; + client->u.http.headers = dictCreate(&sdsOwnDictCallBacks, NULL); + } + /* nothing available to respond to this request - inform the client */ + else { sts = client->u.http.parser.status_code = HTTP_STATUS_BAD_REQUEST; http_error(client, sts, "no handler for URL"); } @@ -734,7 +765,7 @@ if (pmDebugOptions.http && pmDebugOptions.desperate) printf("Body: %.*s\n(client=%p)\n", (int)length, offset, client); - if (servlet->on_body) + if (servlet && servlet->on_body) return servlet->on_body(client, offset, length); return 0; } @@ -828,7 +859,7 @@ } client->u.http.privdata = NULL; - if (servlet->on_headers) + if (servlet && servlet->on_headers) sts = servlet->on_headers(client, client->u.http.headers); /* HTTP Basic Auth for all servlets */ @@ -857,13 +888,31 @@ { struct client *client = (struct client *)request->data; struct servlet *servlet = client->u.http.servlet; + sds buffer; + int sts; if (pmDebugOptions.http) fprintf(stderr, "HTTP message complete (client=%p)\n", client); - if (servlet && servlet->on_done) - return servlet->on_done(client); - return 0; + if (servlet) { + if (servlet->on_done) + return servlet->on_done(client); + return 0; + } + + sts = HTTP_STATUS_OK; + if (client->u.http.parser.method == HTTP_OPTIONS) { + buffer = http_response_access(client, sts, HTTP_SERVER_OPTIONS); + client_write(client, buffer, NULL); + return 0; + } + if (client->u.http.parser.method == HTTP_TRACE) { + buffer = http_response_trace(client, sts); + client_write(client, buffer, NULL); + return 0; + } + + return 1; } void diff -auNr pcp-5.1.1.orig/qa/1608 pcp-5.1.1/qa/1608 --- pcp-5.1.1.orig/qa/1608 1970-01-01 10:00:00.000000000 +1000 +++ pcp-5.1.1/qa/1608 2020-06-23 12:16:04.005557293 +1000 @@ -0,0 +1,58 @@ +#!/bin/sh +# PCP QA Test No. 1608 +# Exercise a long URL handling in pmproxy. +# +# Copyright (c) 2020 Red Hat. All Rights Reserved. +# + +seq=`basename $0` +echo "QA output created by $seq" + +# get standard environment, filters and checks +. ./common.product +. ./common.filter +. ./common.check + +_check_series +which curl >/dev/null 2>&1 || _notrun "No curl binary installed" + +status=1 # failure is the default! +$sudo rm -rf $tmp $tmp.* $seq.full +trap "_cleanup; exit \$status" 0 1 2 3 15 + +pmproxy_was_running=false +[ -f $PCP_RUN_DIR/pmproxy.pid ] && pmproxy_was_running=true +echo "pmproxy_was_running=$pmproxy_was_running" >>$here/$seq.full + +_cleanup() +{ + if $pmproxy_was_running + then + echo "Restart pmproxy ..." >>$here/$seq.full + _service pmproxy restart >>$here/$seq.full 2>&1 + _wait_for_pmproxy + else + echo "Stopping pmproxy ..." >>$here/$seq.full + _service pmproxy stop >>$here/$seq.full 2>&1 + fi + $sudo rm -f $tmp.* +} + +_webapi_failure_filter() +{ + _webapi_header_filter | \ + sed \ + -e 's/pmproxy.[0-9][0-9]*.[0-9][0-9]*.[0-9][0-9]*/PMPROXY\/VERSION/g' \ + #end +} + +# real QA test starts here +_service pmproxy restart >/dev/null 2>&1 + +url="http://localhost:44322/pmapi/context" +aaa=`head -c 10000 < /dev/zero | tr '\0' '\141'` +curl -isS -X OPTIONS "${url}?${aaa}" | _webapi_failure_filter + +# success, all done +status=0 +exit diff -auNr pcp-5.1.1.orig/qa/1608.out pcp-5.1.1/qa/1608.out --- pcp-5.1.1.orig/qa/1608.out 1970-01-01 10:00:00.000000000 +1000 +++ pcp-5.1.1/qa/1608.out 2020-06-23 12:16:04.005557293 +1000 @@ -0,0 +1,16 @@ +QA output created by 1608 + + + + +

414 URI Too Long

+414 URI Too Long + +

unknown servlet: request URL too long


+

PMPROXY/VERSION

+Access-Control-Allow-Headers: Accept, Accept-Language, Content-Language, Content-Type +Access-Control-Allow-Origin: * +Content-Length: SIZE +Content-Type: text/html +Date: DATE +HTTP/1.1 414 URI Too Long diff -auNr pcp-5.1.1.orig/qa/group pcp-5.1.1/qa/group --- pcp-5.1.1.orig/qa/group 2020-06-23 12:15:21.335094106 +1000 +++ pcp-5.1.1/qa/group 2020-06-23 12:16:54.256102754 +1000 @@ -1717,6 +1717,7 @@ 1600 pmseries pmcd pmproxy pmlogger local 1601 pmseries pmproxy local 1602 pmproxy local +1608 pmproxy local 1622 selinux local 1623 libpcp_import collectl local 1644 pmda.perfevent local diff -auNr pcp-5.1.1.orig/src/pmproxy/src/http.c pcp-5.1.1/src/pmproxy/src/http.c --- pcp-5.1.1.orig/src/pmproxy/src/http.c 2020-06-23 12:15:21.364094421 +1000 +++ pcp-5.1.1/src/pmproxy/src/http.c 2020-06-23 12:16:04.008557325 +1000 @@ -21,7 +21,9 @@ static int chunked_transfer_size; /* pmproxy.chunksize, pagesize by default */ static int smallest_buffer_size = 128; -#define MAX_PARAMS_SIZE 4096 +/* https://tools.ietf.org/html/rfc7230#section-3.1.1 */ +#define MAX_URL_SIZE 8192 +#define MAX_PARAMS_SIZE 8000 #define MAX_HEADERS_SIZE 128 static sds HEADER_ACCESS_CONTROL_REQUEST_HEADERS, @@ -720,8 +722,13 @@ int sts; http_client_release(client); /* new URL, clean slate */ + + if (length >= MAX_URL_SIZE) { + sts = client->u.http.parser.status_code = HTTP_STATUS_URI_TOO_LONG; + http_error(client, sts, "request URL too long"); + } /* pass to servlets handling each of our internal request endpoints */ - if ((servlet = servlet_lookup(client, offset, length)) != NULL) { + else if ((servlet = servlet_lookup(client, offset, length)) != NULL) { client->u.http.servlet = servlet; if ((sts = client->u.http.parser.status_code) != 0) http_error(client, sts, "failed to process URL");