diff options
Diffstat (limited to 'src/pmcd/pmdaproc.sh')
-rw-r--r-- | src/pmcd/pmdaproc.sh | 1457 |
1 files changed, 1457 insertions, 0 deletions
diff --git a/src/pmcd/pmdaproc.sh b/src/pmcd/pmdaproc.sh new file mode 100644 index 0000000..0ef6eae --- /dev/null +++ b/src/pmcd/pmdaproc.sh @@ -0,0 +1,1457 @@ +# Common sh(1) procedures to be used in the Performance Co-Pilot +# PMDA Install and Remove scripts +# +# Copyright (c) 1995-2001,2003 Silicon Graphics, Inc. All Rights Reserved. +# Portions Copyright (c) 2008 Aconex. All Rights Reserved. +# Portions Copyright (c) 2013-2014 Red Hat. +# +# 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. + +# source the PCP configuration environment variables +. $PCP_DIR/etc/pcp.env + +tmp=`mktemp -d $PCP_TMPFILE_DIR/pmdaproc.XXXXXXXXX` || exit 1 +pmdatmp=$tmp +trap "rm -rf $pmdatmp $pcptmp; exit" 0 1 2 3 15 + +_setup_platform() +{ + case "$PCP_PLATFORM" + in + mingw) + uid=0 # no permissions we can usefully test here + dso_suffix=dll + default_pipe_opt=false + default_socket_opt=true + CHOWN=": skip chown" + CHMOD=chmod + ;; + *) + eval `id | sed -e 's/(.*//'` + dso_suffix=so + [ "$PCP_PLATFORM" = darwin ] && dso_suffix=dylib + default_pipe_opt=true + default_socket_opt=false + CHOWN=chown + CHMOD=chmod + ;; + esac +} + +_setup_localhost() +{ + # Try to catch some truly evil preconditions. If you cannot reach + # localhost, all bets are off! + # + if which ping >/dev/null 2>&1 + then + __opt='' + # Larry Wall style hunt for the version of ping that is first + # on our path + # + ping --help >$tmp/hlp 2>&1 + if grep '.-c count' $tmp/hlp >/dev/null 2>&1 + then + __opt='-c 1 localhost' + elif grep '.-n count' $tmp/hlp >/dev/null 2>&1 + then + __opt='-n 1 localhost' + elif grep 'host .*packetsize .*count' $tmp/hlp >/dev/null 2>&1 + then + __opt='localhost 56 1' + elif grep 'host .*data_size.*npackets' $tmp/hlp >/dev/null 2>&1 + then + __opt='localhost 56 1' + fi + if [ -z "$__opt" ] + then + echo "Warning: can't find a ping(1) that I understand ... pushing on" + else + if ping $__opt >$tmp/hlp 2>&1 + then + : + else + # failing that, try 3 pings ... failure means all 3 were lost, + # and so there is no hope of continuing + # + __opt=`echo "$__opt" | sed -e 's/1/3/'` + if ping $__opt >/dev/null 2>&1 + then + : + else + echo "Error: no route to localhost, pmcd reconfiguration abandoned" + exit 1 + fi + fi + fi + fi +} + +_setup_localhost +_setup_platform +rm -rf $tmp + +# some useful common variables for Install/Remove scripts +# +# put your PMNS files here +PMNSDIR=$PCP_VAR_DIR/pmns + +# pmcd and pcp log files here +if [ ! -z "$PCP_LOGDIR" ] +then + # this is being discouraged and is no longer documented anywhere + LOGDIR=$PCP_LOGDIR +else + if [ -d $PCP_LOG_DIR/pmcd ] + then + # the preferred naming scheme + # + LOGDIR=$PCP_LOG_DIR/pmcd + else + # backwards compatibility for IRIX + # + LOGDIR=$PCP_LOG_DIR + fi +fi + +# writeable root of PMNS +NAMESPACE=${PMNS_DEFAULT-$PMNSDIR/root} +PMNSROOT=`basename $NAMESPACE` + +# echo without newline - deprecated - use the $PCP_ECHO_* ones from +# /etc/pcp.conf instead, however some old Install and Remove scripts may +# still use $ECHONL, so keep it here +# +ECHONL="echo -n" + +# Install control variables +# Can install as DSO? +dso_opt=false +# Can install as perl script? +perl_opt=false +# Can install as python script? +python_opt=false +# Can install as daemon? +daemon_opt=true +# If daemon, pipe? +pipe_opt=$default_pipe_opt +# If daemon, socket? and default for Internet sockets? +socket_opt=$default_socket_opt +socket_inet_def='' +# IPC Protocol for daemon (binary only now) +ipc_prot=binary +# Need to force a restart of pmcd? +forced_restart=true +# Delay after install before checking (sec) +check_delay=3 +# Additional command line args to go in $PCP_PMCDCONF_PATH +args="" +# ditto for perl PMDAs +perl_args="" +# ditto for python PMDAS +python_args="" +# Source for the pmns +pmns_source=pmns +# Source for the helptext +help_source=help +# Assume libpcp_pmda.so.1 +pmda_interface=1 +# Full pathname to directory where PMDA is to be found ... +# exectable and/or DSO, domain.h, pmns, control files, etc. +pmda_dir="`pwd`" + + +# Other variables and constants +# +prog=`basename $0` +tmp=`mktemp -d $PCP_TMPFILE_DIR/pcp.XXXXXXXXX` || exit 1 +pcptmp=$tmp +do_pmda=true +do_check=true +__here=`pwd` +__pmcd_is_dead=false +__echo=false +__verbose=false +__ns_opt='' + +trap "rm -rf $tmp; exit" 0 1 2 3 15 + +# Parse command line args +# +while [ $# -gt 0 ] +do + case $1 + in + -e) # echo user input + __echo=true + ;; + + -N) # name space only + do_pmda=false + ;; + + -n) # alternate name space + if [ $# -lt 2 ] + then + echo "$prog: -n requires a name space file option" + exit 1 + fi + NAMESPACE=$2 + PMNSROOT=`basename $NAMESPACE` + PMNSDIR=`dirname $NAMESPACE` + __ns_opt="-n $2" + shift + ;; + + -Q) # skip check for metrics going away + do_check=false + ;; + + -R) # $ROOT + if [ "$prog" = "Remove" ] + then + echo "Usage: $prog [-eNQV] [-n namespace]" + exit 1 + fi + if [ $# -lt 2 ] + then + echo "$prog: -R requires a directory option" + exit 1 + fi + root=$2 + shift + ;; + + -V) # verbose + __verbose=true + ;; + + *) + if [ "$prog" = "Install" ] + then + echo "Usage: $prog [-eNQV] [-n namespace] [-R rootdir]" + else + echo "Usage: $prog [-eNQV] [-n namespace]" + fi + exit 1 + ;; + esac + shift +done + +# wait for pmcd to be alive again +# Usage: __wait_for_pmcd [can_wait] +# +__wait_for_pmcd() +{ + # 60 seconds default seems like a reasonble max time to get going + [ -z "$__can_wait" ] && __can_wait=${1-60} + if pmcd_wait -t $__can_wait + then + : + else + echo "Arrgghhh ... PMCD failed to start after $__can_wait seconds" + if [ -f $LOGDIR/pmcd.log ] + then + echo "Here is the PMCD logfile ($LOGDIR/pmcd.log):" + ls -l $LOGDIR/pmcd.log + cat $LOGDIR/pmcd.log + else + echo "No trace of the PMCD logfile ($LOGDIR/pmcd.log)!" + fi + __pmcd_is_dead=true + fi +} + +# try and put pmcd back the way it was +# +__restore_pmcd() +{ + if [ -f $tmp/pmcd.conf.save ] + then + __pmcd_is_dead=false + echo + echo "Save current PMCD control file in $PCP_PMCDCONF_PATH.prev ..." + rm -f $PCP_PMCDCONF_PATH.prev + mv $PCP_PMCDCONF_PATH $PCP_PMCDCONF_PATH.prev + echo "Restoring previous PMCD control file, and trying to restart PMCD ..." + cp $tmp/pmcd.conf.save $PCP_PMCDCONF_PATH + eval $CHOWN root $PCP_PMCDCONF_PATH + eval $CHMOD 644 $PCP_PMCDCONF_PATH + rm -f $tmp/pmcd.conf.save + $PCP_RC_DIR/pcp start + __wait_for_pmcd + fi + if $__pmcd_is_dead + then + echo + echo "Sorry, failed to restart PMCD." + fi +} + +# __pmda_cull name domain +# +__pmda_cull() +{ + # context and integrity checks + # + if [ $# -ne 2 ] + then + echo "pmdaproc.sh: internal botch: __pmda_cull() called with $# (instead of 2) arguments" + exit 1 + fi + [ ! -f $PCP_PMCDCONF_PATH ] && return + if eval $CHMOD u+w $PCP_PMCDCONF_PATH + then + : + else + echo "pmdaproc.sh: __pmda_cull: Unable to make $PCP_PMCDCONF_PATH writable" + exit 1 + fi + if [ ! -w $PCP_PMCDCONF_PATH ] + then + echo "pmdaproc.sh: \"$PCP_PMCDCONF_PATH\" is not writeable" + exit 1 + fi + + # remove matching entry from $PCP_PMCDCONF_PATH if present + # + $PCP_AWK_PROG <$PCP_PMCDCONF_PATH >$tmp/pmcd.conf ' +BEGIN { status = 0 } +$1 == "'"$1"'" && $2 == "'"$2"'" { status = 1; next } + { print } +END { exit status }' + if [ $? -eq 0 ] + then + # no match + : + else + + # log change to the PCP NOTICES file + # + $PCP_BINADM_DIR/pmpost "PMDA cull: from $PCP_PMCDCONF_PATH: $1 $2" + + # save pmcd.conf in case we encounter a problem, and then + # install updated $PCP_PMCDCONF_PATH + # + cp $PCP_PMCDCONF_PATH $tmp/pmcd.conf.save + cp $tmp/pmcd.conf $PCP_PMCDCONF_PATH + eval $CHOWN root $PCP_PMCDCONF_PATH + eval $CHMOD 644 $PCP_PMCDCONF_PATH + + # signal pmcd if it is running + # + if pminfo -v pmcd.version >/dev/null 2>&1 + then + pmsignal -a -s HUP pmcd >/dev/null 2>&1 + # allow signal processing to be done before checking status + sleep 2 + __wait_for_pmcd + if $__pmcd_is_dead + then + __restore_pmcd + # give PMCD a chance to get back into original state + sleep 3 + __wait_for_pmcd + fi + fi + fi + rm -f $tmp/pmcd.conf + + # stop any matching PMDA that is still running + # + for __sig in TERM KILL + do + __pids=`_get_pids_by_name pmda$1` + if [ ! -z "$__pids" ] + then + pmsignal -s $__sig $__pids >/dev/null 2>&1 + # allow signal processing to be done + sleep 2 + else + break + fi + done +} + +# __pmda_add "entry for $PCP_PMCDCONF_PATH" +# +__pmda_add() +{ + # context and integrity checks + # + if [ $# -ne 1 ] + then + echo "pmdaproc.sh: internal botch: __pmda_add() called with $# (instead of 1) arguments" + exit 1 + fi + if eval $CHMOD u+w $PCP_PMCDCONF_PATH + then + : + else + echo "pmdaproc.sh: __pmda_add: Unable to make $PCP_PMCDCONF_PATH writable" + exit 1 + fi + if [ ! -w $PCP_PMCDCONF_PATH ] + then + echo "pmdaproc.sh: \"$PCP_PMCDCONF_PATH\" is not writeable" + exit 1 + fi + + # save pmcd.conf in case we encounter a problem + # + cp $PCP_PMCDCONF_PATH $tmp/pmcd.conf.save + + myname=`echo $1 | $PCP_AWK_PROG '{print $1}'` + mydomain=`echo $1 | $PCP_AWK_PROG '{print $2}'` + # add entry to $PCP_PMCDCONF_PATH + # + echo >$tmp/pmcd.body + echo >$tmp/pmcd.access + $PCP_AWK_PROG <$PCP_PMCDCONF_PATH ' +NF==0 { next } +/^[ ]*\[[ ]*access[ ]*\]/ { state = 2 } +state == 2 { print >"'$tmp/pmcd.access'"; next } +$1=="'$myname'" && $2=="'$mydomain'" { next } + { print >"'$tmp/pmcd.body'"; next }' + ( cat $tmp/pmcd.body \ + ; echo "$1" \ + ; cat $tmp/pmcd.access \ + ) >$PCP_PMCDCONF_PATH + rm -f $tmp/pmcd.access $tmp/pmcd.body + eval $CHOWN root $PCP_PMCDCONF_PATH + eval $CHMOD 644 $PCP_PMCDCONF_PATH + + # log change to pcplog/NOTICES + # + $PCP_BINADM_DIR/pmpost "PMDA add: to $PCP_PMCDCONF_PATH: $1" + + # signal pmcd if it is running (and ok to do so), else start it + # + if ! $forced_restart && pminfo -v pmcd.version >/dev/null 2>&1 + then + pmsignal -a -s HUP pmcd >/dev/null 2>&1 + # allow signal processing to be done before checking status + sleep 2 + __wait_for_pmcd + $__pmcd_is_dead && __restore_pmcd + else + log=$LOGDIR/pmcd.log + rm -f $log + $PCP_RC_DIR/pcp start + __wait_for_pmcd + $__pmcd_is_dead && __restore_pmcd + fi +} + +# expect -R root or $ROOT not set in environment +# +__check_root() +{ + if [ "X$root" != X ] + then + ROOT="$root" + export ROOT + else + if [ "X$ROOT" != X -a "X$ROOT" != X/ ] + then + echo "Install: \$ROOT was set to \"$ROOT\"" + echo " Use -R rootdir to install somewhere other than /" + exit 1 + fi + fi +} + +# should be able to extract default domain from domain.h +# +__check_domain() +{ + if [ -f domain.h ] + then + __infile=domain.h + elif [ -f domain.h.perl ] + then + __infile=domain.h.perl + elif [ -f domain.h.python ] + then + __infile=domain.h.python + else + echo "Install: cannot find ./domain.h to determine the Performance Metrics Domain" + exit 1 + fi + # $domain is for backwards compatibility, modern PMDAs + # have something like + # #define FOO 123 + # + domain='' + eval `$PCP_AWK_PROG <$__infile ' +/^#define/ && $3 ~ /^[0-9][0-9]*$/ { print $2 "=" $3 + if (seen == 0) { + print "domain=" $3 + sub(/^PMDA/, "", $2) + print "SYMDOM=" $2 + seen = 1 + } + }'` + if [ "X$domain" = X ] + then + echo "Install: cannot determine the Performance Metrics Domain from ./domain.h" + exit 1 + fi +} + +# handle optional configuration files that maybe already given in an +# $PCP_PMCDCONF_PATH line or user-supplied or some default or sample +# file +# +# before calling _choose_configfile, optionally define the following +# variables +# +# Name Default Use +# +# configdir $PCP_VAR_DIR/config/$iam directory for config ... assumed +# name is $iam.conf in this directory +# +# configfile "" set if have a preferred choice, +# e.g. from $PCP_PMCDCONF_PATH +# this will be set on return if we've +# found an acceptable config file +# +# default_configfile +# "" if set, this is the default which +# will be offered +# +# Note: +# If the choice is aborted then $configfile will be set to empty. +# Therefore, there should be a test for an empty $configfile after +# the call to this function. +# +_choose_configfile() +{ + configdir=${configdir-$PCP_VAR_DIR/config/$iam} + + if [ ! -d $configdir ] + then + mkdir -p $configdir + fi + + while true + do + echo "Possible configuration files to choose from:" + # List viable alternatives + __i=0 # menu item number + __filelist="" # list of configuration files + __choice="" # the choice of configuration file + __choice1="" # the menu item for the 1st possible choice + __choice2="" # the menu item for the 2nd possible choice + __choice3="" # the menu item for the 3rd possible choice + + if [ ! -z "$configfile" ] + then + if [ -f $configfile ] + then + __i=`expr $__i + 1` + __choice1=$__i + __filelist="$__filelist $configfile" + echo "[$__i] $configfile" + fi + fi + + if [ -f $configdir/$iam.conf ] + then + if echo $__filelist | grep "$configdir/$iam.conf" >/dev/null + then + : + else + __i=`expr $__i + 1` + __choice2=$__i + __filelist="$__filelist $configdir/$iam.conf" + echo "[$__i] $configdir/$iam.conf" + fi + fi + + if [ -f $default_configfile ] + then + if echo $__filelist | grep "$default_configfile" >/dev/null + then + : + else + __i=`expr $__i + 1` + __choice3=$__i + __filelist="$__filelist $default_configfile" + echo "[$__i] $default_configfile" + fi + fi + + __i=`expr $__i + 1` + __own_choice=$__i + echo "[$__i] Specify your own configuration file." + + __i=`expr $__i + 1` + __abort_choice=$__i + echo "[$__i] None of the above (abandon configuration file selection)." + + $PCP_ECHO_PROG $PCP_ECHO_N "Which configuration file do you want to use ? [1] ""$PCP_ECHO_C" + read __reply + $__echo && echo "$__reply" + + # default + if [ -z "$__reply" ] + then + __reply=1 + fi + + # Process the reply from the user + if [ $__reply = $__own_choice ] + then + $PCP_ECHO_PROG $PCP_ECHO_N "Enter the name of the existing configuration file: ""$PCP_ECHO_C" + read __choice + $__echo && echo "$__choice" + if [ ! -f "$__choice" ] + then + echo "Cannot open \"$__choice\"." + echo "" + echo "Please choose another configuration file." + __choice="" + fi + elif [ $__reply = $__abort_choice ] + then + echo "Abandoning configuration file selection." + configfile="" + return 0 + elif [ "X$__reply" = "X$__choice1" -o "X$__reply" = "X$__choice2" -o "X$__reply" = "X$__choice3" ] + then + # extract nth field as the file + __choice=`echo $__filelist | $PCP_AWK_PROG -v n=$__reply '{ print $n }'` + else + echo "Illegal choice: $__reply" + echo "" + echo "Please choose number between: 1 and $__i" + fi + + if [ ! -z "$__choice" ] + then + echo + echo "Contents of the selected configuration file:" + echo "--------------- start $__choice ---------------" + cat $__choice + echo "--------------- end $__choice ---------------" + echo + + $PCP_ECHO_PROG $PCP_ECHO_N "Use this configuration file? [y] ""$PCP_ECHO_C" + read ans + $__echo && echo "$ans" + if [ ! -z "$ans" -a "X$ans" != Xy -a "X$ans" != XY ] + then + echo "" + echo "Please choose another configuration file." + else + break + fi + fi + done + + + __dest=$configdir/$iam.conf + if [ "$__choice" != "$__dest" ] + then + if [ -f $__dest ] + then + echo "Removing old configuration file \"$__dest\"" + rm -f $__dest + if [ -f $__dest ] + then + echo "Error: cannot remove old configuration file \"$__dest\"" + exit 1 + fi + fi + if cp $__choice $__dest + then + : + else + echo "Error: cannot install new configuration file \"$__dest\"" + exit 1 + fi + __choice=$__dest + fi + + configfile=$__choice +} + +# choose correct PMDA installation mode +# +# make sure we are installing in the correct style of configuration +# +__choose_mode() +{ + __def=m + $do_pmda && __def=b + echo \ +'You will need to choose an appropriate configuration for installation of +the "'$iam'" Performance Metrics Domain Agent (PMDA). + + collector collect performance statistics on this system + monitor allow this system to monitor local and/or remote systems + both collector and monitor configuration for this system +' + while true + do + $PCP_ECHO_PROG $PCP_ECHO_N 'Please enter c(ollector) or m(onitor) or b(oth) ['$__def'] '"$PCP_ECHO_C" + read ans + $__echo && echo "$ans" + case "$ans" + in + "") break + ;; + c|collector|b|both) + do_pmda=true + break + ;; + m|monitor) + do_pmda=false + break + ;; + *) echo "Sorry, that is not acceptable response ..." + ;; + esac + done +} + +# choose an IPC method +# +__choose_ipc() +{ + _dir=$1 + ipc_type='' + $pipe_opt && ipc_type=pipe + $socket_opt && ipc_type=socket + $pipe_opt && $socket_opt && ipc_type='' + if [ -z "$ipc_type" ] + then + while true + do + $PCP_ECHO_PROG $PCP_ECHO_N "PMCD should communicate with the $iam daemon via a pipe or a socket? [pipe] ""$PCP_ECHO_C" + read ipc_type + $__echo && echo "$ipc_type" + if [ "X$ipc_type" = Xpipe -o "X$ipc_type" = X ] + then + ipc_type=pipe + break + elif [ "X$ipc_type" = Xsocket ] + then + break + else + echo "Must choose one of \"pipe\" or \"socket\", please try again" + fi + done + fi + + if [ $ipc_type = pipe ] + then + # This defaults to binary unless the Install file + # specifies ipc_prot="binary notready" -- See pmcd(1) + type="pipe $ipc_prot $_dir/$pmda_name" + else + while true + do + $PCP_ECHO_PROG $PCP_ECHO_N "Use Internet, IPv6 or Unix domain sockets? [Internet] ""$PCP_ECHO_C" + read ans + $__echo && echo "$ans" + if [ "X$ans" = XInternet -o "X$ans" = XIPv6 -o "X$ans" = X ] + then + $PCP_ECHO_PROG $PCP_ECHO_N "Internet port number or service name? [$socket_inet_def] ""$PCP_ECHO_C" + read port + $__echo && echo "$port" + [ "X$port" = X ] && port=$socket_inet_def + case $port + in + [0-9]*) + ;; + *) + if grep "^$port[ ]*[0-9]*/tcp" /etc/services >/dev/null 2>&1 + then + : + else + echo "Warning: there is no tcp service for \"$port\" in /etc/services!" + fi + ;; + esac + if [ "X$ans" = XInternet -o "X$ans" = X ] + then + type="socket inet $port $_dir/$pmda_name" + args="-i $port $args" + else + type="socket ipv6 $port $_dir/$pmda_name" + args="-6 $port $args" + fi + break + elif [ "X$ans" = XUnix ] + then + $PCP_ECHO_PROG $PCP_ECHO_N "Unix FIFO name? ""$PCP_ECHO_C" + read fifo + $__echo && echo "$fifo" + if [ "X$fifo" = X ] + then + echo "Must provide a name, please try again" + else + type="socket unix $fifo $_dir/$pmda_name" + args="-u $fifo $args" + break + fi + else + echo "Must choose one of \"Unix\" or \"Internet\", please try again" + fi + done + fi +} + +# filter pmprobe -i output of the format: +# postgresql.active.is_in_recovery -12351 Missing metric value(s) +# postgresql.statio.sys_sequences.blks_hit 0 +# disk.partitions.read 13 ?0 ?1 ?2 ?3 ?4 ?5 ?6 ?7 ?8 ?9 ?10 ?11 ?12 +# to produce a summary of metrics, values and warnings +# +__filter() +{ + $PCP_AWK_PROG ' +/^'$1'/ { metric++ + if ($2 < 0) + warn++ + else + value += $2 + next + } + { warn++ } +END { if (warn) printf "%d warnings, ",warn + printf "%d metrics and %d values\n",metric,value + }' +} + +_setup() +{ + # some more configuration controls + pmns_name=${pmns_name-$iam} + pmda_name=pmda$iam + pmda_dso_name="${PCP_PMDAS_DIR}/${iam}/pmda_${iam}.${dso_suffix}" + dso_name="${dso_name-$pmda_dso_name}" + dso_entry=${iam}_init + + _check_userroot + _check_directory + + # automatically generate files for those lazy Perl programmers + # + if $perl_opt + then + perl_name="${pmda_dir}/pmda${iam}.perl" + [ -f "$perl_name" ] || perl_name="${pmda_dir}/pmda${iam}.pl" + if [ -f "$perl_name" ] + then + perl_pmns="${pmda_dir}/pmns.perl" + perl_dom="${pmda_dir}/domain.h.perl" + perl -e 'use PCP::PMDA' 2>/dev/null + if test $? -eq 0 + then + eval PCP_PERL_DOMAIN=1 perl "$perl_name" > "$perl_dom" + eval PCP_PERL_PMNS=1 perl "$perl_name" > "$perl_pmns" + elif $dso_opt || $daemon_opt + then + : # we have an alternative, so continue on + else + echo 'Perl PCP::PMDA module is not installed, install it and try again' + exit 1 + fi + else + if $dso_opt || $daemon_opt + then + : # we have an alternative, so continue on + else + echo "Neither pmda${iam}.perl nor pmda${iam}.pl found in ${pmda_dir}" + echo "Error: no Perl PMDA to install" + exit 1 + fi + fi + fi + + # automatically generate files for the Python programmers too + # + if $python_opt + then + python_name="${pmda_dir}/pmda${iam}.python" + [ -f "$python_name" ] || python_name="${pmda_dir}/pmda${iam}.py" + if [ -f "$python_name" ] + then + python_pmns="${pmda_dir}/pmns.python" + python_dom="${pmda_dir}/domain.h.python" + python -c 'from pcp import pmda' 2>/dev/null + if test $? -eq 0 + then + eval PCP_PYTHON_DOMAIN=1 python "$python_name" > "$python_dom" + eval PCP_PYTHON_PMNS=1 python "$python_name" > "$python_pmns" + elif $dso_opt || $daemon_opt + then + : # we have an alternative, so continue on + else + echo 'Python pcp.pmda module is not installed, install it and try again' + exit 1 + fi + else + if $dso_opt || $daemon_opt + then + : # we have an alternative, so continue on + else + echo "Neither pmda${iam}.python nor pmda${iam}.py found in ${pmda_dir}" + echo "Error: no Python PMDA to install" + exit 1 + fi + fi + fi + + # Juggle pmns and domain.h in case perl/python pmda install was done here + # last time + # + for file in pmns domain.h + do + [ -f $file.save ] && mv $file.save $file + done + + # Set $domain and $SYMDOM from domain.h + # + __check_domain + + case $prog + in + *Install*) + # Check that $ROOT is not set, we have a default domain value and + # choose the installation mode (collector, monitor or both) + # + __check_root + __choose_mode + ;; + esac +} + +_install_views() +{ + viewer="$1" + have_views=false + + [ `echo *.$viewer` != "*.$viewer" ] && have_views=true + if [ -d $PCP_VAR_DIR/config/$viewer ] + then + $have_views && echo "Installing $viewer view(s) ..." + for __i in *.$viewer + do + if [ "$__i" != "*.$viewer" ] + then + __dest=$PCP_VAR_DIR/config/$viewer/`basename $__i .$viewer` + rm -f $__dest + cp $__i $__dest + fi + done + else + $have_views && \ + echo "Skip installing $viewer view(s) ... no \"$PCP_VAR_DIR/config/$viewer\" directory" + fi +} + +# Configurable PMDA installation +# +# before calling _install, +# 1. set $iam +# 2. set one/some/all of $dso_opt, $perl_opt, $python_opt or $daemon_opt to true +# (optional, $daemon_opt is true by default) +# 3. if $daemon_opt set one or both of $pipe_opt or $socket_opt true +# (optional, $pipe_opt is true by default) +# 4. if $socket_opt and there is a default Internet socket, set +# $socket_inet_def + +_install() +{ + if [ -z "$iam" ] + then + echo 'Botch: must define $iam before calling _install()' + exit 1 + fi + + if $do_pmda + then + if $dso_opt || $perl_opt || $python_opt || $daemon_opt + then + : + else + echo 'Botch: must set at least one of $dso_opt, $perl_opt, $python_opt or $daemon_opt to "true"' + exit 1 + fi + if $daemon_opt + then + if $pipe_opt || $socket_opt + then + : + else + echo 'Botch: must set at least one of $pipe_opt or $socket_opt to "true"' + exit 1 + fi + fi + + # Select a PMDA style (dso/perl/python/deamon), and for daemons the + # IPC method for communication between PMCD and the PMDA. + # + pmda_options='' + pmda_default_option='' + pmda_multiple_options=false + + if $dso_opt + then + pmda_options="dso" + pmda_default_option="dso" + fi + if $perl_opt + then + pmda_default_option="perl" + if test -n "$pmda_options" + then + pmda_options="perl or $pmda_options" + pmda_multiple_options=true + else + pmda_options="perl" + fi + fi + if $python_opt + then + pmda_default_option="python" + if test -n "$pmda_options" + then + pmda_options="python or $pmda_options" + pmda_multiple_options=true + else + pmda_options="python" + fi + fi + if $daemon_opt + then + pmda_default_option="daemon" + if test -n "$pmda_options" + then + pmda_options="daemon or $pmda_options" + pmda_multiple_options=true + else + pmda_options="daemon" + fi + fi + + pmda_type="$pmda_default_option" + if $pmda_multiple_options + then + while true + do + $PCP_ECHO_PROG $PCP_ECHO_N "Install $iam as a $pmda_options agent? [$pmda_default_option] ""$PCP_ECHO_C" + read pmda_type + $__echo && echo "$pmda_type" + if [ "X$pmda_type" = Xdaemon -o "X$pmda_type" = X ] + then + pmda_type=daemon + break + elif [ "X$pmda_type" = Xdso ] + then + break + elif [ "X$pmda_type" = Xperl ] + then + perl -e 'use PCP::PMDA' 2>/dev/null + if test $? -ne 0 + then + echo 'Perl PCP::PMDA module is not installed, install it and try again' + else + break + fi + elif [ "X$pmda_type" = Xpython ] + then + python -c 'from pcp import pmda' 2>/dev/null + if test $? -ne 0 + then + echo 'Python pcp pmda module is not installed, install it and try again' + else + break + fi + else + echo "Must choose one of $pmda_options, please try again" + fi + done + fi + if [ "$pmda_type" = daemon ] + then + __choose_ipc $pmda_dir + args="-d $domain $args" + elif [ "$pmda_type" = perl ] + then + type="pipe binary perl $perl_name $perl_args" + args="" + elif [ "$pmda_type" = python ] + then + type="pipe binary python $python_name $python_args" + args="" + else + type="dso $dso_entry $dso_name" + args="" + fi + + # Install binaries + # + if [ "$pmda_type" = perl -o "$pmda_type" = python ] + then + : # we can safely skip building binaries + elif [ -f Makefile -o -f makefile -o -f GNUmakefile ] + then + # $PCP_MAKE_PROG may contain command line args ... executable + # is first word + # + if [ ! -f "`echo $PCP_MAKE_PROG | sed -e 's/ .*//'`" -o ! -f "$PCP_INC_DIR/pmda.h" ] + then + echo "$prog: Arrgh, PCP devel environment required to install this PMDA" + exit 1 + fi + + echo "Installing files ..." + if $PCP_MAKE_PROG install + then + : + else + echo "$prog: Arrgh, \"$PCP_MAKE_PROG install\" failed!" + exit 1 + fi + fi + + # Fix domain in help for instance domains (if any) + # + if [ -f $help_source ] + then + case $pmda_interface + in + 1) + help_version=1 + ;; + *) # PMDA_INTERFACE_2 or later + help_version=2 + ;; + esac + sed -e "/^@ $SYMDOM\./s/$SYMDOM\./$domain./" <$help_source \ + | newhelp -n root -v $help_version -o $help_source + fi + fi + + if $do_pmda + then + if [ "X$pmda_type" = Xperl -o "X$pmda_type" = Xpython ] + then + # Juggle pmns and domain.h ... save originals and + # use *.{perl,python} ones created earlier + for file in pmns domain.h + do + if [ ! -f "$file.$pmda_type" ] + then + echo "Botch: $file.$pmda_type missing ... giving up" + exit 1 + fi + if [ -f $file ] + then + if diff $file.$pmda_type $file >/dev/null + then + : + else + [ ! -f $file.save ] && mv $file $file.save + mv $file.$pmda_type $file + fi + else + mv $file.$pmda_type $file + fi + done + fi + else + # Maybe PMNS only install, and only implementation may be + # Perl or Python ones ... simpler juggling needed here. + # + for file in pmns domain.h + do + [ ! -f $file -a -f $file.perl ] && mv $file.perl $file + [ ! -f $file -a -f $file.python ] && mv $file.python $file + done + fi + + $PCP_SHARE_DIR/lib/lockpmns $NAMESPACE + trap "$PCP_SHARE_DIR/lib/unlockpmns \$NAMESPACE; rm -rf $pcptmp $pmdatmp; exit" 0 1 2 3 15 + + echo "Updating the Performance Metrics Name Space (PMNS) ..." + + # Install the namespace + # + + if [ ! -f $NAMESPACE ] + then + # We may be installing an agent right after an install - + # before pmcd startup, which has a pre-execution step of + # rebuilding the namespace root. Do so now. + if [ -x $PMNSDIR/Rebuild ] + then + echo "$prog: cannot Rebuild the PMNS for \"$NAMESPACE\"" + exit 1 + fi + cd $PMNSDIR + ./Rebuild -dus + cd $__here + forced_restart=true + fi + + for __n in $pmns_name + do + if pminfo $__ns_opt $__n >/dev/null 2>&1 + then + cd $PMNSDIR + if pmnsdel -n $PMNSROOT $__n >$tmp/base 2>&1 + then + pmsignal -a -s HUP pmcd >/dev/null 2>&1 + # Make sure the PMNS timestamp will be different the next + # time the PMNS is updated (for Linux only 1 sec resolution) + sleep 2 + else + if grep 'Non-terminal "'"$__n"'" not found' $tmp/base >/dev/null + then + : + elif grep 'Error: metricpath "'"$__n"'" not defined' $tmp/base >/dev/null + then + : + else + echo "$prog: failed to delete \"$__n\" from the PMNS" + cat $tmp/base + exit 1 + fi + fi + cd $__here + fi + + # Put the default domain number into the namespace file + # + # If there is only one namespace, then the pmns file will + # be named "pmns". If there are multiple metric trees, + # subsequent pmns files will be named "pmns.<metricname>" + # + # the string "pmns" can be overridden by the Install/Remove + # scripts by altering $pmns_source + # + if [ "$__n" = "$iam" -o "$__n" = "$pmns_name" ] + then + __s=$pmns_source + else + __s=$pmns_source.$__n + fi + sed -e "s/$SYMDOM:/$domain:/" <$__s >$PMNSDIR/$__n + + cd $PMNSDIR + if pmnsadd -n $PMNSROOT $__n + then + pmsignal -a -s HUP pmcd >/dev/null 2>&1 + # Make sure the PMNS timestamp will be different the next + # time the PMNS is updated (for Linux only 1 sec resolution) + sleep 2 + else + echo "$prog: failed to add the PMNS entries for \"$__n\" ..." + echo + ls -l + exit 1 + fi + cd $__here + done + + trap "rm -rf $pcptmp $pmdatmp; exit" 0 1 2 3 15 + $PCP_SHARE_DIR/lib/unlockpmns $NAMESPACE + + _install_views pmchart + _install_views kmchart + _install_views pmview + + if $do_pmda + then + # Terminate old PMDA + # + echo "Terminate PMDA if already installed ..." + __pmda_cull $iam $domain + + # Rotate log files + # + if [ -f $PCP_LOG_DIR/pmcd/$iam.log ] + then + rm -f $PCP_LOG_DIR/pmcd/$iam.log.prev + mv -f $PCP_LOG_DIR/pmcd/$iam.log $PCP_LOG_DIR/pmcd/$iam.log.prev + fi + + # Add PMDA to pmcd's configuration file + # + echo "Updating the PMCD control file, and notifying PMCD ..." + __pmda_add "$iam $domain $type $args" + + # Check that the agent is running OK + # + if $do_check + then + [ "$check_delay" -gt 5 ] && echo "Wait $check_delay seconds for the $iam agent to initialize ..." + sleep $check_delay + for __n in $pmns_name + do + $PCP_ECHO_PROG $PCP_ECHO_N "Check $__n metrics have appeared ... ""$PCP_ECHO_C" + pmprobe -i $__ns_opt $__n | tee $tmp/verbose | __filter $__n + if $__verbose + then + echo "pminfo output ..." + cat $tmp/verbose + fi + done + fi + else + echo "Skipping PMDA install and PMCD re-configuration" + fi +} + +_remove() +{ + # Update the namespace + # + + $PCP_SHARE_DIR/lib/lockpmns $NAMESPACE + trap "$PCP_SHARE_DIR/lib/unlockpmns \$NAMESPACE; rm -rf $pcptmp $pmdatmp; exit" 0 1 2 3 15 + + echo "Culling the Performance Metrics Name Space ..." + cd $PMNSDIR + + for __n in $pmns_name + do + $PCP_ECHO_PROG $PCP_ECHO_N "$__n ... ""$PCP_ECHO_C" + if pmnsdel -n $PMNSROOT $__n >$tmp/base 2>&1 + then + rm -f $PMNSDIR/$__n + pmsignal -a -s HUP pmcd >/dev/null 2>&1 + sleep 2 + echo "done" + else + if grep 'Non-terminal "'"$__n"'" not found' $tmp/base >/dev/null + then + echo "not found in Name Space, this is OK" + elif grep 'Error: metricpath "'"$__n"'" not defined' $tmp/base >/dev/null + then + echo "not found in Name Space, this is OK" + else + echo "error" + cat $tmp/base + exit + fi + fi + done + + # Remove the PMDA and help files + # + cd $__here + + if $do_pmda + then + echo "Updating the PMCD control file, and notifying PMCD ..." + __pmda_cull $iam $domain + + if [ -f Makefile -o -f makefile -o -f GNUmakefile ] + then + echo "Removing files ..." + $PCP_MAKE_PROG clobber >/dev/null + fi + for __i in *.pmchart + do + if [ "$__i" != "*.pmchart" ] + then + __dest=$PCP_VAR_DIR/config/pmchart/`basename $__i .pmchart` + rm -f $__dest + fi + done + for __i in *.kmchart + do + if [ "$__i" != "*.kmchart" ] + then + __dest=$PCP_VAR_DIR/config/kmchart/`basename $__i .kmchart` + rm -f $__dest + fi + done + + if $do_check + then + for __n in $pmns_name + do + $PCP_ECHO_PROG $PCP_ECHO_N "Check $__n metrics have gone away ... ""$PCP_ECHO_C" + if pminfo -n $NAMESPACE -f $__n >$tmp/base 2>&1 + then + echo "Arrgh, something has gone wrong!" + cat $tmp/base + else + echo "OK" + fi + done + fi + else + echo "Skipping PMDA removal and PMCD re-configuration" + fi + + trap "rm -rf $pcptmp $pmdatmp; exit" 0 1 2 3 15 + $PCP_SHARE_DIR/lib/unlockpmns $NAMESPACE +} + +_check_userroot() +{ + if [ "$uid" -ne 0 ] + then + if [ -n "$PCP_DIR" ] + then + : running in a non-default installation, do not need to be root + else + echo "Error: You must be root (uid 0) to update the PCP collector configuration." + exit 1 + fi + fi +} + +_check_directory() +{ + case "$__here" + in + */pmdas/$iam) + ;; + *) + echo "Error: expect current directory to be .../pmdas/$iam, not $__here" + echo " (typical location is $PCP_PMDAS_DIR/$iam on this platform)" + exit 1 + ;; + esac +} + +# preferred public interfaces +# +pmdaSetup() +{ + _setup +} + +pmdaChooseConfigFile() +{ + _choose_configfile +} + +pmdaInstall() +{ + _install +} + +pmdaRemove() +{ + _remove +} |