diff options
Diffstat (limited to 'src/pmsnap/pmsnap.sh')
-rwxr-xr-x | src/pmsnap/pmsnap.sh | 457 |
1 files changed, 457 insertions, 0 deletions
diff --git a/src/pmsnap/pmsnap.sh b/src/pmsnap/pmsnap.sh new file mode 100755 index 0000000..87434a5 --- /dev/null +++ b/src/pmsnap/pmsnap.sh @@ -0,0 +1,457 @@ +#!/bin/sh +# +# Copyright (c) 2008 Aconex. All Rights Reserved. +# Copyright (c) 1995-2000,2003 Silicon Graphics, Inc. All Rights Reserved. +# +# 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 2 of the License, or (at your +# option) 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, write to the Free Software Foundation, Inc., +# 51 Franklin Street, Fifth Floor, Boston, MA 02110, USA +# + +. $PCP_DIR/etc/pcp.env + +tmp=`mktemp -d /tmp/pcp.XXXXXXXXX` || exit 1 +trap "rm -rf $tmp; exit 0" 0 1 2 3 15 +prog=`basename $0` + +LOCALHOST=`pmhostname` +CONFIGDIR=$PCP_VAR_DIR/config/pmsnap +CONTROL=$CONFIGDIR/control +[ -z "$PCP_PMSNAPCONTROL_PATH" ] || CONTROL="$PCP_PMSNAPCONTROL_PATH" + +_usage() +{ + cat << EOF +Usage: $prog [-dNV] [-C dir] [-c regex] [-f format] [-n regex] [-o dir] + -C alternate directory for control file(s) + -c matches the Config field in the pmsnap control file + -f output image format (default png) + -N show me, but do not execute commands + -n matches the Name field in the pmsnap control file + -o default directory for output images (default ".") + -V verbose trace of actions (for debugging) + -- pass all following options directly to pmchart + +If no patterns are given then all lines in the pmsnap control file + $CONTROL +will be processed. If any patterns are given then only lines which +match all patterns will be processed. + +Patterns are full regular expressions, see egrep(1) and may require +appropriate quotes to avoid shell meta character expansion. +EOF + exit 1 +} + +_fixpath() +{ + echo $1 $2 |\ + $PCP_AWK_PROG '{ + if (substr($2, 1, 1) == "/") + print $2 + else + printf "%s/%s\n", $1, $2 + }' +} + +_warning() +{ + echo + echo "$prog: $CONTROL[$line]:" + echo "$*" | fmt \ +| sed -e '1{ +s/^/Warning: / +n +}' -e 's/^/ /' +} + +_error() +{ + echo + echo "$prog: $CONTROL[$line]:" + echo "$*" | fmt \ +| sed -e '1{ +s/^/Error: / +n +}' -e 's/^/ /' +} + +_debug() +{ + echo + echo "$prog: $CONTROL[$line]:" + echo "$*" | fmt \ +| sed -e '1{ +s/^/Debug: / +n +}' -e 's/^/ /' +} + +serverId() +{ + id=42 + while [ -f /tmp/.X$id-lock ]; do + id=`expr $id + 1` + done + echo $id +} + +startXvfb() +{ + [ -x /usr/bin/Xvfb ] || return + + geom="2048x2048" + args="-nolisten tcp -screen 0 ${geom}x8" + server=`serverId` + cookie=`mcookie` + XAUTHORITY=$tmp/xauth xauth add ":$server" . "$cookie" >/dev/null 2>&1 + XAUTHORITY=$tmp/xauth /usr/bin/Xvfb ":$server" $args >/dev/null 2>&1 & + pid=$? + pmsleep 0.2 + kill -0 $pid 2>/dev/null || return + export XAUTHORITY=$tmp/xauth + export DISPLAY=":$server" + echo $pid +} + +stopXvfb() +{ + pid="$1" + [ -z "$pid" -o "$pid" -le 0 ] && return + kill $pid +} + +line=0 +archives="" +configs='.*' +names='.*' +dir="." +format="png" +verbose=false +passthru=false +version="1.0" + +# option parsing +# +SHOWME=false +PMLC="echo flush | pmlc >/dev/null 2>&1" +while getopts a:C:c:f:Nn:o:V-? c +do + case $c + in + C) CONFIGDIR="$OPTARG" + ;; + c) configs="$OPTARG" + ;; + f) format="$OPTARG" + ;; + o) dir="$OPTARG" + ;; + N) SHOWME=true + PMLC="echo '+ echo flush | pmlc'" + ;; + n) names="$OPTARG" + ;; + V) verbose=true + ;; + -) passthru=true + ;; + ?) _usage + ;; + esac + [ $passthru = true ] && break +done + +if [ $passthru = false ] +then + shift `expr $OPTIND - 1` + [ $# -ne 0 ] && _usage +fi +commonargs="$commonargs $@" + +CONTROL=$CONFIGDIR/control +if [ ! -f "$CONTROL" ] +then + echo "$prog: Error: cannot find control file \"$CONTROL\"" + exit 1 +fi + +if [ ! -d "$dir" ] +then + echo "$prog: Error: directory \"$dir\" does not exist" + exit 1 +fi +cd $dir +dir=`pwd` +$SHOWME && echo "+ cd $dir" + +$SHOWME || xvfb=`startXvfb` + +# escape / in patterns so $PCP_AWK_PROG is not confused +# +names=`echo "$names" | sed -e 's;/;\\\\/;g'` +configs=`echo "$configs" | sed -e 's;/;\\\\/;g'` + +sed -e 's/LOCALHOSTNAME/'$LOCALHOST'/g' < $CONTROL \ +| $PCP_AWK_PROG ' +/^\#/ || /^\$/ || NF < 4 { + print + next +} +{ + if ($1 ~ /'$names'/ && $3 ~ /'$configs'/) { + printf "%s %s %s '\''", $1, $2, $3 + for (i=4; i<= NF; i++) + printf "%s ", $i + printf "'\''\n" + } +}' \ +| while read aname afolio aview args +do + line=`expr $line + 1` + case "$aname" + in + \#*|'') # comment or empty + continue + ;; + + \$*) # in-line variable assignment + $SHOWME && echo "# $aname $afolio $aview $args" + cmd=`echo "$aname $afolio $aview $args" \ + | sed -n \ + -e "/='/s/\(='[^']*'\).*/\1/" \ + -e '/="/s/\(="[^"]*"\).*/\1/' \ + -e '/=[^"'"'"']/s/[;&<>|].*$//' \ + -e '/^\\$[A-Za-z][A-Za-z0-9_]*=/{ +s/^\\$// +s/^\([A-Za-z][A-Za-z0-9_]*\)=/export \1; \1=/p +}'` + if [ -z "$cmd" ] + then + # in-line command, not a variable assignment + _warning "in-line command is not a variable assignment, line ignored" + else + case "$cmd" + in + 'export PATH;'*) + _warning "cannot change \$PATH, line ignored" + ;; + 'export IFS;'*) + _warning "cannot change \$IFS, line ignored" + ;; + *) + $SHOWME && echo "+ $cmd" + eval $cmd + ;; + esac + fi + continue + ;; + esac + + if [ -z "$afolio" -o -z "$aview" -o -z "$args" ] + then + _error "insufficient fields in control file record" + continue + fi + + # strip first and last single quote added by awk prior to read + # + args=`echo $args | sed -e "s/^'//" -e "s/'$//"` + + name=`_fixpath $dir $aname` + if [ -d $PCP_LOG_DIR/pmlogger ]; then + folio=`_fixpath $PCP_LOG_DIR/pmlogger $afolio` + fi + view=`_fixpath $dir $aview` + + # make sure output directory exists + # + outdir=`dirname $name` + if [ ! -d $outdir ] + then + if $SHOWME + then + echo "+ mkdir -p $outdir" + else + mkdir -p $outdir + if [ ! -d $outdir ] + then + _error "cannot create directory \"$outdir\" for output file" + else + $verbose && _debug "created image output directory \"$outdir\"" + fi + fi + fi + + if $SHOWME + then + : + else + if [ ! -w $outdir ] + then + _error "cannot write in directory \"$outdir\" to create output file" + exit 1 + fi + fi + + if $verbose + then + echo + _debug "name=\"$name\"" + _debug "folio=\"$folio\"" + _debug "view=\"$view\"" + _debug "args=\"$args\"" + _debug "commonargs=\"$commonargs\"" + fi + + if [ ! -f "$view" ] + then + if [ ! -f $CONFIGDIR/$aview ] + then + if [ ! -f $PCP_VAR_DIR/config/pmchart/$aview ] + then + if [ ! -f $PCP_VAR_DIR/config/kmchart/$aview ] + then + _warning "could not find \"$view\", \"$CONFIGDIR/$aview\", \"$PCP_VAR_DIR/config/pmchart/$aview, or \"$PCP_VAR_DIR/config/kmchart/$aview\"" + continue + else + view=$PCP_VAR_DIR/config/kmchart/$aview + fi + else + view=$PCP_VAR_DIR/config/pmchart/$aview + fi + else + view=$CONFIGDIR/$aview + fi + fi + + if [ ! -f $folio ] + then + # oops, no folio + _error "cannot find archive folio \"$folio\"" + echo "Skipping entry from control file ..." + continue + fi + + f=$folio + $SHOWME && echo "+ pmafm $f selection" + pmafm "$f" selection >$tmp/out 2>&1 + + if [ $? -ne 0 ] + then + if [ ! -f $folio.meta ] + then + _warning "\"$folio\" is neither a PCP folio nor a PCP archive" + ls -l $folio + continue + else + contents=$folio + fi + else + contents=`sed -n -e '/Archive:/s///gp' <$tmp/out` + if [ -z "$contents" ] + then + _warning "cannot determine archive name from PCP folio \"$folio\"" + continue + fi + fi + + arch="" + + for c in $contents + do + if [ -f $c.meta ] + then + host=`pminfo -f -a $c pmcd.pmlogger.host \ + | sed -e 's/"//g' -e 's/\[//g' \ + | $PCP_AWK_PROG '$1=="inst" {print $6; exit}'` + + port=`pminfo -f -a $c pmcd.pmlogger.port \ + | sed -e 's/"//g' -e 's/\[//g' \ + | $PCP_AWK_PROG '$1=="inst" {print $6; exit}'` + + if [ ! -z "$host" -a ! -z "$port" ] + then + echo "$host $port" >> $tmp/flush + else + if $verbose + then + _warning "could not extract host and pmlogger control port from archive \"$c\" ... this archive may not be flushed" + fi + fi + + if [ -z "$arch" ] + then + arch=$c + else + arch=$arch","$c + fi + else + _warning "cannot find or open archive \"$c\"" + fi + done + + if [ -z "$arch" ] + then + _warning "no archives could be found for \"$contents\"" + continue + fi + + sort -u $tmp/flush | while read host port + do + eval $PMLC -h $host -p $port + done + + if $SHOWME + then + echo "+ pmchart -c $view -o $name.$format -a $arch $commonargs $args" + else + eval pmchart -c "$view" -o "$tmp/name.$format" -a "$arch" $commonargs $args > $tmp/err 2>&1 + sts=$? + + if [ $sts -eq 0 -a -f $tmp/name.$format ] + then + # success, update the image + mv $tmp/name.$format $name.$format + $verbose && _debug "created \"$name.$format\"" + if [ -s "$tmp/err" ] + then + _warning "the output image \"$name.$format\" was created but there were warning messages from pmchart, as follows:" + cat $tmp/err + echo "-------------" + fi + elif grep 'too short to satisfy the requested starting alignment' $tmp/err >/dev/null + then + # archive's duration is too short for chart configuration ... + # silently ignore this one, as we'll probably succeed next time + # or soon thereafter + if $verbose + then + _debug "archive \"$arch\" too short for pmchart args \"$args\"" + fi + else + # failed, remove the image and report the error + _warning "the output image \"$name.$format\" was not created. There were error messages from pmchart, as follows:" + cat $tmp/err + echo "-------------" + rm -f $name.$format + fi + fi + + rm -f $tmp/err +done + +$SHOWME || stopXvfb "$xvfb" + +exit $status |