diff options
author | Igor Pashev <pashev.igor@gmail.com> | 2014-10-26 12:33:50 +0400 |
---|---|---|
committer | Igor Pashev <pashev.igor@gmail.com> | 2014-10-26 12:33:50 +0400 |
commit | 47e6e7c84f008a53061e661f31ae96629bc694ef (patch) | |
tree | 648a07f3b5b9d67ce19b0fd72e8caa1175c98f1a /src/pmdas/shping | |
download | pcp-debian.tar.gz |
Debian 3.9.10debian/3.9.10debian
Diffstat (limited to 'src/pmdas/shping')
-rw-r--r-- | src/pmdas/shping/GNUmakefile | 69 | ||||
-rwxr-xr-x | src/pmdas/shping/Install | 222 | ||||
-rw-r--r-- | src/pmdas/shping/README | 91 | ||||
-rw-r--r-- | src/pmdas/shping/Remove | 38 | ||||
-rw-r--r-- | src/pmdas/shping/help | 137 | ||||
-rw-r--r-- | src/pmdas/shping/pmda.c | 257 | ||||
-rw-r--r-- | src/pmdas/shping/pmlogconf.summary | 6 | ||||
-rw-r--r-- | src/pmdas/shping/pmns | 41 | ||||
-rw-r--r-- | src/pmdas/shping/root | 9 | ||||
-rw-r--r-- | src/pmdas/shping/sample.conf | 46 | ||||
-rw-r--r-- | src/pmdas/shping/shping.CPUTime.pmchart | 11 | ||||
-rw-r--r-- | src/pmdas/shping/shping.RealTime.pmchart | 9 | ||||
-rw-r--r-- | src/pmdas/shping/shping.c | 679 | ||||
-rw-r--r-- | src/pmdas/shping/shping.h | 54 | ||||
-rw-r--r-- | src/pmdas/shping/shping.response.pmie | 67 | ||||
-rw-r--r-- | src/pmdas/shping/shping.status.pmie | 63 |
16 files changed, 1799 insertions, 0 deletions
diff --git a/src/pmdas/shping/GNUmakefile b/src/pmdas/shping/GNUmakefile new file mode 100644 index 0000000..73b88da --- /dev/null +++ b/src/pmdas/shping/GNUmakefile @@ -0,0 +1,69 @@ +# +# Copyright (c) 1995-2001 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. +# + +TOPDIR = ../../.. +include $(TOPDIR)/src/include/builddefs + +IAM = shping +DOMAIN = SHPING + +CMDTARGETS = $(IAM)$(EXECSUFFIX) +HFILES = shping.h +CFILES = shping.c pmda.c +OTHERS = README root help pmns sample.conf +CHARTS = shping.CPUTime.pmchart shping.RealTime.pmchart +PMIECS = shping.status.pmie shping.response.pmie + +LSRCFILES = $(OTHERS) $(CHARTS) $(PMIECS) Install Remove pmlogconf.summary +LLDLIBS = $(PCP_PMDALIB) $(LIB_FOR_PTHREADS) + +PMDADIR = $(PCP_PMDAS_DIR)/$(IAM) +PMCHART = $(PCP_VAR_DIR)/config/pmchart +PMIE = $(PCP_VAR_DIR)/config/pmieconf/$(IAM) +LDIRT = *.log *.dir *.pag so_locations a.out domain.h $(CMDTARGETS) + +default: build-me + +include $(TOPDIR)/src/include/buildrules + +ifneq "$(TARGET_OS)" "mingw" +build-me: $(CMDTARGETS) + +install: build-me + $(INSTALL) -m 755 -d $(PMDADIR) + $(INSTALL) -m 755 $(IAM) $(PMDADIR)/pmda$(IAM) + $(INSTALL) -m 755 Install Remove $(PMDADIR) + $(INSTALL) -m 644 $(OTHERS) domain.h $(PMDADIR) + $(INSTALL) -m 644 shping.CPUTime.pmchart $(PMCHART)/shping.CPUTime + $(INSTALL) -m 644 shping.RealTime.pmchart $(PMCHART)/shping.RealTime + $(INSTALL) -m 755 -d $(PMIE) + $(INSTALL) -m 644 shping.status.pmie $(PMIE)/status + $(INSTALL) -m 644 shping.response.pmie $(PMIE)/response + $(INSTALL) -m 755 -d $(PCP_VAR_DIR)/config/pmlogconf/$(IAM) + $(INSTALL) -m 644 pmlogconf.summary $(PCP_VAR_DIR)/config/pmlogconf/$(IAM)/summary +else +build-me: +install: +endif + +$(IAM)$(EXECSUFFIX): $(OBJECTS) + +shping.o pmda.o: domain.h + +domain.h: ../../pmns/stdpmid + $(DOMAIN_MAKERULE) + +default_pcp: default + +install_pcp: install diff --git a/src/pmdas/shping/Install b/src/pmdas/shping/Install new file mode 100755 index 0000000..bcca1b1 --- /dev/null +++ b/src/pmdas/shping/Install @@ -0,0 +1,222 @@ +#! /bin/sh +# +# Copyright (c) 1997,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. +# +# Install the shping PMDA and/or PMNS +# + +. $PCP_DIR/etc/pcp.env +. $PCP_SHARE_DIR/lib/pmdaproc.sh + +iam=shping +pmda_interface=2 +forced_restart=false + +# Do it +# +pmdaSetup + +# controls for installation procedures +# +daemon_opt=true # can install as daemon +dso_opt=false +pipe_opt=true # supports pipe IPC +socket_opt=false # force pipe IPC +check_delay=10 # give the PMDA a chance to set itself up + +# be careful that mortals cannot write any configuration files, as +# these would present a security problem +# +umask 022 + + +# PMDA variables +# +tmp=`mktemp -d /tmp/pcp.XXXXXXXXX` || exit 1 +configfile="" +cycle=120 +timeout=20 +debug=0 + +trap "rm -rf $tmp; exit" 0 1 2 3 15 + +_quit() +{ + rm -rf $tmp + exit $1 +} + +do_debug=false + +_parsedefaults() +{ + echo "Extracting options from current installation ..." + while getopts D:I:d:l:t: c + do + case $c in + \?) echo "Warning: Unrecognized option in $PCP_PMCDCONF_PATH" + echo " Remove line for the $iam PMDA in $PCP_PMCDCONF_PATH and re-run ./Install" + _quit 2;; + D ) debug=$OPTARG;; + I ) cycle=$OPTARG;; + t ) timeout=$OPTARG;; + * ) ;; + esac + done + eval configfile='$'$OPTIND +} + +if $do_pmda +then + + # set options from $PCP_PMCDCONF_PATH, if possible + # + ans=`$PCP_AWK_PROG <$PCP_PMCDCONF_PATH ' +$1 == "'$iam'" { printf "%s",$6 + for (i=7;i<=NF;i++) printf " %s",$i + print "" + }'` + if [ ! -z "$ans" ] + then + _parsedefaults $ans + fi + + default_configfile=./sample.conf + if fgrep "CONFIGURE-ME-PLEASE" $default_configfile >/dev/null + then + # nslookup(1) may be hiding, like for OpenIndiana + # + export PATH=$PATH:/usr/sbin + nslookup=`which nslookup 2>/dev/null` + if [ -z "$nslookup" ] + then + echo "Warning: cannot find nslookup" + nslookup=nslookup + fi + # sample configuration file needs a little customization + # + if [ -f /etc/resolv.conf ] + then + my_dns_server=`$PCP_AWK_PROG </etc/resolv.conf '$1 == "nameserver" { print $2; exit }'` + else + my_dns_server=`hostname` + fi + sed <$default_configfile >$tmp/tmp \ + -e '/CONFIGURE-ME-PLEASE/d' \ + -e "s@DEFAULT-DNS-SERVER@$my_dns_server@" \ + -e "s@NSLOOKUP@$nslookup@" + cp $tmp/tmp $default_configfile + fi + + # go figure out which configuration file to use ... + # + pmdaChooseConfigFile + + if [ ! -f "$configfile" ] + then + $PCP_ECHO_PROG $PCP_ECHO_N "Do you wish to enter commands to create a new configuration file? [y] ""$PCP_ECHO_C" + read ans + if [ "X$ans" = "Xy" -o "X$ans" = "XY" -o -z "$ans" ] + then + configfile="$configdir/$iam.conf" + if [ -f $configfile ] + then + echo "Removing old configuration file \"$configfile\"" + rm -f $configfile + if [ -f $configfile ] + then + echo "Cannot remove \"$configfile\"" + _quit 1 + fi + fi + + echo + echo \ +'Enter one ping specification per line, in the format + +tag command line details + +where the "tag" is a single unique word (no spaces) and the "command line +details" are the corresponding sh(1) command. For example + +dns-self nslookup `hostname` + +An empty line terminates the specification process and there must be at +least one specification. +' + + args="" + touch $configfile + if [ ! -f $configfile ] + then + echo "Installation aborted." + _quit 1 + fi + + while [ ! -s "$configfile" ] + do + while true + do + $PCP_ECHO_PROG $PCP_ECHO_N "Tag Command: ""$PCP_ECHO_C" + read tag cmd + [ -z "$tag" ] && break + if grep "^$tag " $configfile >/dev/null + then + echo "Sorry, tag \"$tag\" already in use. Please try again." + continue + fi + echo "$tag $cmd" >>$configfile + done + done + else + echo "" + echo "Error: Abandoning installation as no configuration file was specified." + _quit 1 + fi + fi + + echo + echo "All commands are run one after another as a group and the group is run" + $PCP_ECHO_PROG $PCP_ECHO_N "once per \"cycle\" time. Enter the cycle time in seconds [$cycle] ""$PCP_ECHO_C" + read ans + if [ ! -z "$ans" ] + then + cycle=$ans + fi + + echo + echo "Each command must complete within a timeout period, or it will be aborted" + $PCP_ECHO_PROG $PCP_ECHO_N "by the \"$iam\" PMDA. Enter the timeout period (in seconds) [$timeout] ""$PCP_ECHO_C" + read ans + if [ ! -z "$ans" ] + then + timeout=$ans + fi + + if [ "$do_debug" = true ] + then + echo + $PCP_ECHO_PROG $PCP_ECHO_N "Enter the debugging flag (see pmdbg(1)) [$debug] ""$PCP_ECHO_C" + read ans + if [ ! -z "$ans" ] + then + debug=$ans + fi + fi + + args="-I $cycle -t $timeout -D $debug $configfile" +fi + +pmdaInstall + +_quit 0 diff --git a/src/pmdas/shping/README b/src/pmdas/shping/README new file mode 100644 index 0000000..a071cbc --- /dev/null +++ b/src/pmdas/shping/README @@ -0,0 +1,91 @@ +Performance Co-Pilot shping PMDA for General Performance Monitoring +=================================================================== + +This PMDA is designed to be configurable to monitor elapsed time and +CPU time (user and system) for arbitrary applications that can be run +from the Bourne shell. Each application is assumed to run to completion +to probe or ping a particular service or dimension of system performance. + +The metrics exported from the shping PMDA may be used to quantify of +service or service availability for both critical system services and +tasks that well correlated to performance as perceived by end-users. + +The sample configuration file includes examples to "ping": + + + sh(1) start up and exit + + a simple task, date(1) + + sum(1) for some simple user-mode computation + + compilation and execution of an antipodean variant of the + generic "hullo world" C program + + DNS (default server, trivial and error cases) + + yp service via ypcat(1) + + rpcinfo(1) for RPC registration from portmap/rpcbind + + mail delivery (telnet tcp port 25) + + Usenet news from nntp (telnet tcp port 119) + +Metrics +======= + +The file ./help contains descriptions for all of the metrics exported +by this PMDA. + +Once the PMDA has been installed, the following command will list all +the available metrics and their explanatory "help" text: + + $ pminfo -fT shping + +Installation of the shping PMDA +=============================== + + + # cd $PCP_PMDAS_DIR/shping + + + Check that there is no clash with the Performance Metrics Domain + number defined in ./domain.h and the other PMDAs currently in use + (see $PCP_PMCDCONF_PATH). If there is, edit ./domain.h and choose + another domain number. + + + Then run the Install script (as root) + + # ./Install + + and choose both the "collector" and "monitor" installation + configuration options. + + Answer the questions, which include the option to specify new or + alternate commands to be run. See $PCP_PMDAS_DIR/shping/sample.conf + for example specifications of commands. + +De-installation +=============== + + + Simply use + + # cd $PCP_PMDAS_DIR/shping + # ./Remove + +Changing the settings +===================== + +The cycle time and timeout period can be dynamically modified using +pmstore(1) for the metrics shping.control.cycletime and +shping.control.timeout respectively. + +To make permanent changes, re-run the Install script. + +Troubleshooting +=============== + + + After installing or restarting the agent, the PMCD log file + ($PCP_LOG_DIR/pmcd/pmcd.log) and the PMDA log file + ($PCP_LOG_DIR/pmcd/shping.log) should be checked for any warnings + or errors. + + + If the Install script reports some warnings when checking the + metrics, the problem should be listed in one of the log files. + + + Additional information can be logged if there appears to be + problems. The PCP application debug flags will cause the PMDA to + report additional information in $PCP_LOG_DIR/pmcd/shping.log. For + details about the agent's debug flags, use the comand + + $ pminfo -T shping.control.debug diff --git a/src/pmdas/shping/Remove b/src/pmdas/shping/Remove new file mode 100644 index 0000000..b991ac5 --- /dev/null +++ b/src/pmdas/shping/Remove @@ -0,0 +1,38 @@ +#! /bin/sh +# +# Copyright (c) 1997 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-1301 USA +# +# Remove the shping PMDA +# + +# Get standard environment +. $PCP_DIR/etc/pcp.env + +# Get the common procedures and variable assignments +# +. $PCP_SHARE_DIR/lib/pmdaproc.sh + +# The name of the PMDA +# +iam=shping + +# Do it +# +pmdaSetup +pmdaRemove + +exit 0 diff --git a/src/pmdas/shping/help b/src/pmdas/shping/help new file mode 100644 index 0000000..69d758c --- /dev/null +++ b/src/pmdas/shping/help @@ -0,0 +1,137 @@ +# +# Copyright (c) 2000 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. +# +# shping PMDA help file in the ASCII format +# +# lines beginning with a # are ignored +# lines beginning @ introduce a new entry of the form +# @ metric_name oneline-text +# help test goes +# here over multiple lines +# ... +# +# the metric_name is decoded against the default PMNS -- as a special case, +# a name of the form NNN.MM (for numeric NNN and MM) is interpreted as an +# instance domain identification, and the text describes the instance domain +# +# blank lines before the @ line are ignored +# + +@ 19.0 shping command instance domain +There is one instance for each command run by the shping PMDA. + +The external instance name comes from the "tag" in the shping PMDA +configuration file. The internal instance number is the ordinal +command number in the configuration file. + +@ shping.error command execution error code for shping PMDA +As each command is executed, if there is a problem, the error +code or cause is stored in shping.error. + +The interpretation of the value for shping.error depends on +shping.status as follows: + + If shping.status is 1 (the command was run but returned a non-zero + exit status) then shping.error is the exit status. + + If shping.status is 2 (the command was run but was terminated by + a signal) then shping.error is the signal number. + + If shping.status is 3 (the command did not complete) then + shping.error is a PCP error codes: see pmerr(1). Of particular + relevance is -1008 (PM_ERR_TIMEOUT) when the command failed to + complete in the time specified by shping.control.timeout. + + If shping.status is 4 (the commands was not run) then shping.error + is the value of the system error code. + + Otherwise shping.error will be zero. + +@ shping.status command execution status for shping PMDA +As each command is executed, the success or failure is encoded in +shping.status, using the following values: + + -1 PMDA is initializing and command has not been run yet + 0 command completed and exit status was 0 + 1 command completed and exit status was non-zero + 2 command was run but terminated by a signal + 3 command was run but did not complete (usually a timeout) + 4 command was not run due to some system error or resource + availability + +@ shping.time.real elapsed time for a command +This metric records the elapsed time in milliseconds for the most recent +execution of each command to be run by the shping PMDA. + +Care should be used when interpreting the value if the corresponding +value for shping.status is non-zero, as the command may not have run to +completion. If the command timed out, shping.time.real will be -1. + +@ shping.time.cpu_usr user mode CPU time for a command +This metric records the user mode CPU time in milliseconds for the most +recent execution of each command to be run by the shping PMDA. + +Care should be used when interpreting the value if the corresponding +value for shping.status is non-zero, as the command may not have run to +completion. If the command timed out, shping.time.cpu_usr will be -1. + +@ shping.time.cpu_sys system mode CPU time for a command +This metric records the system mode CPU time in milliseconds for the most +recent execution of each command to be run by the shping PMDA. + +Care should be used when interpreting the value if the corresponding +value for shping.status is non-zero, as the command may not have run to +completion. If the command timed out, shping.time.cpu_sys will be -1. + +@ shping.cmd commands run by shping PMDA +The text of each sh(1) command run by the shping PMDA. + +@ shping.control.numcmd number of commands in the group to be run by the shping PMDA + +@ shping.control.cycles number of times the command group has been run by the shping PMDA + +@ shping.control.cycletime shping PMDA cycle time +All commands are run by the shping PMDA are executed one after another +in a group, and the group is run once per "cycle" time. This metric +reports the cycle time in seconds. + +The cycle time may be changed dynamically by modifying this metric +with pmstore(1). + +@ shping.control.timeout shping PMDA timeout period +The number of seconds the shping PMDA is willing to wait before +considering a single command to have timed out and killing it off. + +The time out interval may be changed dynamically by modifying this +metric with pmstore(1). + +@ shping.control.debug shping PMDA debug flag +The debug flag for the shping PMDA (see pmdbg(1)). All trace and +diagnostic files are created in $PCP_LOG_DIR/pmcd. + +The debug flags DBG_TRACE_APPL0 (2048) and DBG_TRACE_APPL1 (4096) +may be used as follows: + +DBG_TRACE_APPL0 - additional trace messages associated with the running + of each command appear in shping.log + +DBG_TRACE_APPL1 - the standard output and standard error of each command + is appended to shping.out (instead of the default + /dev/null) + +The debug flags may be changed dynamically by modifying this +metric with pmstore(1), e.g. + $ pmstore shping.control.debug 6144 +would enable both of the diagnostic traces associated with +DBG_TRACE_APPL0 and DBG_TRACE_APPL1. + diff --git a/src/pmdas/shping/pmda.c b/src/pmdas/shping/pmda.c new file mode 100644 index 0000000..648cec3 --- /dev/null +++ b/src/pmdas/shping/pmda.c @@ -0,0 +1,257 @@ +/* + * sh(1) ping PMDA + * + * Copyright (c) 1995-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. + */ + +#include <ctype.h> +#include "shping.h" +#include "domain.h" + +__uint32_t cycletime = 120; /* default cycle time, 2 minutes */ +__uint32_t timeout = 20; /* response timeout in seconds */ +static char *username; /* user account to run under */ +cmd_t *cmdlist; + +#ifdef HAVE_SPROC + +/* Signals are only used with sproc, threads will never generate SIGGHLD */ +void +onchld(int s) +{ + int done; + int waitStatus; + int die = 0; + + while ((done = waitpid(-1, &waitStatus, WNOHANG)) > 0) { + + if (done != sprocpid) + continue; + die = 1; + + if (WIFEXITED(waitStatus)) { + + if (WEXITSTATUS(waitStatus) == 0) + logmessage(LOG_INFO, + "Sproc (pid=%d) exited normally\n", + done); + else + logmessage(LOG_CRIT, + "Sproc (pid=%d) exited with status = %d\n", + done, WEXITSTATUS(waitStatus)); + } + else if (WIFSIGNALED(waitStatus)) { + + if (WCOREDUMP(waitStatus)) + logmessage(LOG_CRIT, + "Sproc (pid=%d) received signal = %d and dumped core\n", + done, WTERMSIG(waitStatus)); + else + logmessage(LOG_CRIT, + "Sproc (pid=%d) received signal = %d\n", + done, WTERMSIG(waitStatus)); + } + else { + logmessage(LOG_CRIT, + "Sproc (pid=%d) died, reason unknown\n", done); + } + } + + if (die) { + logmessage(LOG_INFO, "Main process exiting\n"); + exit(0); + } +} +#endif + +void +usage(void) +{ + fprintf(stderr, +"Usage: %s [options] configfile\n\n\ +Options:\n\ + -C parse configuration file and exit\n\ + -d domain use domain (numeric) for metrics domain of PMDA\n\ + -I interval cycle time in seconds between subsequent executions of each\n\ + command [default 120 seconds]\n\ + -l logfile write log into logfile rather than using the default log\n\ + -t timeout time in seconds before aborting the wait for individual\n\ + commands to complete [default 20 seconds]\n\ + -U username run the agent and commands as alternate user [default \"pcp\"]\n", + pmProgname); + exit(1); +} + +int +main(int argc, char **argv) +{ + pmdaInterface dispatch; + int n = 0; + int i; + int err = 0; + int sep = __pmPathSeparator(); + int line; + int numcmd = 0; + int parseonly = 0; + char *configfile; + FILE *conf; + char *endnum; + char *p; + char *tag; + char lbuf[256]; + char mypath[MAXPATHLEN]; + + __pmSetProgname(argv[0]); + __pmGetUsername(&username); + + snprintf(mypath, sizeof(mypath), "%s%c" "shping" "%c" "help", + pmGetConfig("PCP_PMDAS_DIR"), sep, sep); + pmdaDaemon(&dispatch, PMDA_INTERFACE_2, pmProgname, SHPING, + "shping.log", mypath); + + while ((n = pmdaGetOpt(argc, argv,"CD:d:I:l:t:U:?", + &dispatch, &err)) != EOF) { + switch (n) { + + case 'C': + parseonly = 1; + break; + + case 'I': + cycletime = (int)strtol(optarg, &endnum, 10); + if (*endnum != '\0') { + fprintf(stderr, + "%s: -I requires number of seconds as argument\n", + pmProgname); + err++; + } + break; + + case 't': + timeout = (int)strtol(optarg, &endnum, 10); + if (*endnum != '\0') { + fprintf(stderr, + "%s: -t requires number of seconds as argument\n", + pmProgname); + err++; + } + break; + + case 'U': + username = optarg; + break; + + case '?': + err++; + } + } + + if (err || optind != argc -1) { + usage(); + } + + configfile = argv[optind]; + if ((conf = fopen(configfile, "r")) == NULL) { + fprintf(stderr, "%s: Unable to open config file \"%s\": %s\n", + pmProgname, configfile, osstrerror()); + exit(1); + } + line = 0; + + for ( ; ; ) { + if (fgets(lbuf, sizeof(lbuf), conf) == NULL) + break; + + line++; + p = lbuf; + while (*p && isspace((int)*p)) + p++; + if (*p == '\0' || *p == '\n' || *p == '#') + continue; + tag = p++; + while (*p && !isspace((int)*p)) + p++; + if (*p) + *p++ = '\0'; + while (*p && isspace((int)*p)) + p++; + if (*p == '\0' || *p == '\n') { + fprintf(stderr, "[%s:%d] missing command after tag \"%s\"\n", + configfile, line, tag); + exit(1); + } + + numcmd++; + if (parseonly) + continue; + if ((cmdlist = (cmd_t *)realloc(cmdlist, numcmd * sizeof(cmd_t))) == NULL) { + __pmNoMem("main:cmdlist", numcmd * sizeof(cmd_t), + PM_FATAL_ERR); + } + + cmdlist[numcmd-1].tag = strdup(tag); + cmdlist[numcmd-1].cmd = strdup(p); + cmdlist[numcmd-1].status = STATUS_NOTYET; + cmdlist[numcmd-1].error = 0; + cmdlist[numcmd-1].real = cmdlist[numcmd-1].usr = cmdlist[numcmd-1].sys = -1; + + /* trim trailing newline */ + p = cmdlist[numcmd-1].cmd; + while (*p && *p != '\n') + p++; + *p = '\0'; + } + + fclose(conf); + + if (numcmd == 0) { + fprintf(stderr, "%s: No commands in config file \"%s\"?\n", + pmProgname, configfile); + exit(1); + } + else if (parseonly) + exit(0); + +#ifdef PCP_DEBUG + if (pmDebug & DBG_TRACE_APPL1) { + fprintf(stderr, "Parsed %d commands\n", numcmd); + fprintf(stderr, "Tag\tCommand\n"); + for (i = 0; i < numcmd; i++) { + fprintf(stderr, "[%s]\t%s\n", cmdlist[i].tag, cmdlist[i].cmd); + } + } +#endif + + /* set up indom description */ + indomtab.it_numinst = numcmd; + if ((indomtab.it_set = (pmdaInstid *)malloc(numcmd*sizeof(pmdaInstid))) == NULL) { + __pmNoMem("main.indomtab", numcmd * sizeof(pmdaInstid), PM_FATAL_ERR); + } + for (i = 0; i < numcmd; i++) { + indomtab.it_set[i].i_inst = i; + indomtab.it_set[i].i_name = cmdlist[i].tag; + } + +#ifdef HAVE_SPROC + signal(SIGCHLD, onchld); +#endif + + pmdaOpenLog(&dispatch); + __pmSetProcessIdentity(username); + + shping_init(&dispatch); + pmdaConnect(&dispatch); + pmdaMain(&dispatch); + + exit(0); +} diff --git a/src/pmdas/shping/pmlogconf.summary b/src/pmdas/shping/pmlogconf.summary new file mode 100644 index 0000000..709865e --- /dev/null +++ b/src/pmdas/shping/pmlogconf.summary @@ -0,0 +1,6 @@ +#pmlogconf-setup 2.0 +ident shping PMDA summary information +probe shping.status exists ? include : exclude + shping.status + shping.time + shping.error diff --git a/src/pmdas/shping/pmns b/src/pmdas/shping/pmns new file mode 100644 index 0000000..70003e6 --- /dev/null +++ b/src/pmdas/shping/pmns @@ -0,0 +1,41 @@ +/* + * Metrics for shping PMDA + * + * Copyright (c) 2000-2004 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-1301 USA + */ + +shping { + status SHPING:0:6 + error SHPING:0:10 + time + cmd SHPING:0:7 + control +} + +shping.time { + real SHPING:0:0 + cpu_usr SHPING:0:1 + cpu_sys SHPING:0:2 +} + +shping.control { + numcmd SHPING:0:3 + cycles SHPING:0:9 + cycletime SHPING:0:4 + timeout SHPING:0:5 + debug SHPING:0:8 +} diff --git a/src/pmdas/shping/root b/src/pmdas/shping/root new file mode 100644 index 0000000..a0e1b52 --- /dev/null +++ b/src/pmdas/shping/root @@ -0,0 +1,9 @@ +/* + * fake "root" for validating the local PMNS subtree + */ + +#include <stdpmid> + +root { shping } + +#include "pmns" diff --git a/src/pmdas/shping/sample.conf b/src/pmdas/shping/sample.conf new file mode 100644 index 0000000..028a196 --- /dev/null +++ b/src/pmdas/shping/sample.conf @@ -0,0 +1,46 @@ +# sample configuration file for shping PMDA +# +# Warning: these commands will be run as "root" using sh(1) with the +# current directory set to $PCP_LOG_DIR/pmcd and the +# following set in the environment: +# IFS=" \t\n" +# PATH=... as per $PCP_DIR/etc/pcp.env ... +# + +# Specification format, one per line ("Tags" must be unique) +# Tag Shell command + +# minimal effort here, no stress for the shell ... just start and quit +null exit 0 + +# not too much work, date(1) is pretty light-weight +date date + +# compile and run the generic simple program ... requires a C compiler +# to be installed +cc cd /tmp; rm -f $$.[oc] $$; echo "main(){printf(\"g'day world\\\\n\");}" >/tmp/$$.c; cc -o $$ $$.c; ./$$; rm -f $$.[oc] $$ + +# Is the default DNS server responding? +# CONFIGURE-ME-PLEASE - local customization required +# CONFIGURE-ME-PLEASE - DEFAULT-DNS-SERVER will be changed by Install to +# CONFIGURE-ME-PLEASE - be the hostname for the default DNS server +# CONFIGURE-ME-PLEASE - and NSLOOKUP is the path of the nslookup(1) command +dns NSLOOKUP - DEFAULT-DNS-SERVER </dev/null + +# DNS lookup for localhost +dns-self NSLOOKUP `hostname` + +# DNS lookup that will fail ... +dns-err NSLOOKUP foo.bar.no.host.com + +# ypserv ... if you have yp running +ypserv ypcat hosts | grep `hostname` + +# contact portmap/rpcbind for registered RPC programs +rpcbind rpcinfo -p + +# if smtpd is running here, a simple test +smtp ( echo "expn root"; echo quit ) | telnet-probe localhost 25 + +# NNTP ... need to customize nntp server host +nntp ( echo "listgroup comp.sys.sgi"; echo quit ) | telnet-probe tokyo.engr.sgi.com 119 diff --git a/src/pmdas/shping/shping.CPUTime.pmchart b/src/pmdas/shping/shping.CPUTime.pmchart new file mode 100644 index 0000000..cce7e88 --- /dev/null +++ b/src/pmdas/shping/shping.CPUTime.pmchart @@ -0,0 +1,11 @@ +#pmchart +Version 2.0 host dynamic + +Chart Title "User CPU Time for shping Commands" Style plot + Plot Color #-cycle Host * Metric shping.time.cpu_usr Matching .* + +Chart Title "System CPU Time for shping Commands" Style plot + Plot Color #-cycle Host * Metric shping.time.cpu_sys Matching .* + +# +# CPU time (user and system) for commands run by the shping PMDA diff --git a/src/pmdas/shping/shping.RealTime.pmchart b/src/pmdas/shping/shping.RealTime.pmchart new file mode 100644 index 0000000..05d5436 --- /dev/null +++ b/src/pmdas/shping/shping.RealTime.pmchart @@ -0,0 +1,9 @@ +#pmchart +Version 2.0 host dynamic + +Chart Title "Elapsed Time for shping Commands" Style plot + Plot Color #-cycle Host * Metric shping.time.real Matching .* + +# +# Elapsed time (or real time, or response time) for commands run by the +# shping PMDA diff --git a/src/pmdas/shping/shping.c b/src/pmdas/shping/shping.c new file mode 100644 index 0000000..f14be03 --- /dev/null +++ b/src/pmdas/shping/shping.c @@ -0,0 +1,679 @@ +/* + * Copyright (c) 2012 Red Hat. + * Copyright (c) 1995-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. + */ + +#include <ctype.h> +#include "pmapi.h" +#include "impl.h" +#include "pmda.h" +#include "shping.h" +#include "domain.h" +#include <sys/stat.h> +#if defined(HAVE_SYS_WAIT_H) +#include <sys/wait.h> +#endif +#if defined(HAVE_SYS_RESOURCE_H) +#include <sys/resource.h> +#endif +#if defined(HAVE_SYS_PRCTL_H) +#include <sys/prctl.h> +#endif +#if defined(HAVE_SCHED_H) +#include <sched.h> +#endif +#if defined(HAVE_PTHREAD_H) +#include <pthread.h> +#endif + +#define LOG_PRI(p) ((p) & LOG_PRIMASK) + +static int cycles; /* completed cycles */ +static int numskip; /* skipped cycles */ +static int numcmd; /* number of commands */ +static int timedout; /* command timed out */ +static pid_t shpid; /* for /sbin/sh running command */ + +#if defined(HAVE_PTHREAD_H) +static pthread_t sprocpid; +#elif defined(HAVE_SCHED_H) +pid_t sprocpid; /* for refresh() */ +#else +#error "Need pthreads or sproc" +#endif + +/* + * only one instance domain here ... + */ +#define SHPING_INDOM 0 +pmdaIndom indomtab = { 0, 0, NULL }; + +/* + * all metrics supported in this PMDA - one table entry for each + */ +static pmdaMetric metrics[] = +{ +/* time.real */ + { NULL, + { PMDA_PMID(0,0), PM_TYPE_FLOAT, SHPING_INDOM, PM_SEM_INSTANT, + PMDA_PMUNITS(0,1,0,0,PM_TIME_MSEC,0), }, }, +/* time.cpu_usr */ + { NULL, + { PMDA_PMID(0,1), PM_TYPE_FLOAT, SHPING_INDOM, PM_SEM_INSTANT, + PMDA_PMUNITS(0,1,0,0,PM_TIME_MSEC,0), }, }, +/* time.cpu_sys */ + { NULL, + { PMDA_PMID(0,2), PM_TYPE_FLOAT, SHPING_INDOM, PM_SEM_INSTANT, + PMDA_PMUNITS(0,1,0,0,PM_TIME_MSEC,0), }, }, +/* control.numcmd */ + { NULL, + { PMDA_PMID(0,3),PM_TYPE_U32,PM_INDOM_NULL,PM_SEM_DISCRETE, + PMDA_PMUNITS(0,0,0,0,0,0), }, }, +/* control.cycletime */ + { NULL, + { PMDA_PMID(0,4),PM_TYPE_U32,PM_INDOM_NULL,PM_SEM_DISCRETE, + PMDA_PMUNITS(0,1,0,0,PM_TIME_SEC,0), }, }, +/* control.timeout */ + { NULL, + { PMDA_PMID(0,5),PM_TYPE_U32,PM_INDOM_NULL,PM_SEM_DISCRETE, + PMDA_PMUNITS(0,1,0,0,PM_TIME_SEC,0), }, }, +/* status */ + { NULL, + { PMDA_PMID(0,6),PM_TYPE_32,SHPING_INDOM,PM_SEM_INSTANT, + PMDA_PMUNITS(0,0,0,0,0,0), }, }, +/* cmd */ + { NULL, + { PMDA_PMID(0,7),PM_TYPE_STRING,SHPING_INDOM,PM_SEM_DISCRETE, + PMDA_PMUNITS(0,0,0,0,0,0), }, }, +/* control.debug */ + { NULL, + { PMDA_PMID(0,8),PM_TYPE_32,PM_INDOM_NULL,PM_SEM_DISCRETE, + PMDA_PMUNITS(0,0,0,0,0,0), }, }, +/* control.cycles */ + { NULL, + { PMDA_PMID(0,9),PM_TYPE_U32,PM_INDOM_NULL,PM_SEM_COUNTER, + PMDA_PMUNITS(0,0,1,0,0,PM_COUNT_ONE), }, }, +/* error */ + { NULL, + { PMDA_PMID(0,10),PM_TYPE_32,SHPING_INDOM,PM_SEM_INSTANT, + PMDA_PMUNITS(0,0,0,0,0,0), }, }, + +}; + +static int nummetric = (sizeof(metrics)/sizeof(metrics[0])); + +void +logmessage(int priority, const char *format, ...) +{ + va_list arglist; + char buffer[2048]; + char *level; + char *p; + time_t now; + + buffer[0] = '\0'; + time(&now); + + priority = LOG_PRI(priority); + switch (priority) { + case LOG_EMERG : + level = "Emergency"; + break; + case LOG_ALERT : + level = "Alert"; + break; + case LOG_CRIT : + level = "Critical"; + break; + case LOG_ERR : + level = "Error"; + break; + case LOG_WARNING : + level = "Warning"; + break; + case LOG_NOTICE : + level = "Notice"; + break; + case LOG_INFO : + level = "Info"; + break; + case LOG_DEBUG : + level = "Debug"; + break; + default: + level = "???"; + break; + } + + va_start (arglist, format); + vsnprintf (buffer, sizeof(buffer), format, arglist); + + /* strip unwanted '\n' at end of text so's not to double up */ + for (p = buffer; *p; p++); + if (*(--p) == '\n') *p = '\0'; + + fprintf (stderr, "[%.19s] %s(%" FMT_PID ") %s: %s\n", ctime(&now), pmProgname, getpid(), level, buffer) ; + va_end (arglist) ; +} + + +static void +onhup(int dummy) +{ + _exit(0); +} + +static void +onalarm(int dummy) +{ + timedout = 1; + if (shpid > 1) { /* something other than error, self or init */ + kill(-shpid, SIGTERM); /* nuke process group */ + sleep(1); + kill(-shpid, SIGKILL); + } + signal(SIGALRM, onalarm); +#ifdef PCP_DEBUG + if (pmDebug & DBG_TRACE_APPL1) + fprintf(stderr, "Timeout!\n"); +#endif +} + +/* + * the sproc starts here to refresh the metric values periodically + */ +static void +refresh(void *dummy) +{ + int i; + int sts; + int waittime; + struct timeval startcycle; + struct timeval now; + struct timeval then; + struct rusage cpu_now; + struct rusage cpu_then; + char *argv[4]; + + signal(SIGHUP, onhup); +#if defined (PR_TERMCHILD) + prctl(PR_TERMCHILD); /* SIGHUP when the parent dies */ +#elif defined (PR_SET_PDEATHSIG) + prctl(PR_SET_PDEATHSIG, SIGTERM); +#elif defined(IS_SOLARIS) || defined(IS_DARWIN) || defined(IS_MINGW) || defined(IS_AIX) || defined(IS_FREEBSD) || defined(IS_GNU) || defined(IS_NETBSD) + /* no signals here for child exit */ +#else +!bozo: cant decide between PR_TERMCHILD and PR_SET_PDEATHSIG +#endif +#ifndef NOFILE +#define NOFILE 7 +#endif + + signal(SIGALRM, onalarm); + + putenv("IFS= \t\n"); + putenv("PATH=/usr/sbin:/usr/bsd:/sbin:/usr/bin:/bin"); + + argv[0] = "sh"; + argv[1] = "-c"; + argv[2] = ""; + argv[3] = NULL; + + for ( ; ; ) { + cycles++; + __pmtimevalNow(&startcycle); +#ifdef PCP_DEBUG + if (pmDebug & DBG_TRACE_APPL1) + fprintf(stderr, "\nStart cycle @ %s", ctime(&startcycle.tv_sec)); +#endif + for (i = 0; i < numcmd; i++) { +#ifdef PCP_DEBUG + if (pmDebug & DBG_TRACE_APPL1) + fprintf(stderr, "[%s] %s ->\n", cmdlist[i].tag, cmdlist[i].cmd); +#endif + getrusage(RUSAGE_CHILDREN, &cpu_then); + __pmtimevalNow(&then); + fflush(stderr); + fflush(stdout); + shpid = fork(); + if (shpid == 0) { + int j; + setsid(); /* make new process group */ + for (j = 0; j < NOFILE; j++) + close(j); + open("/dev/null", O_RDONLY, 0); + sts = -1; +#ifdef PCP_DEBUG + if (pmDebug & DBG_TRACE_APPL2) { + FILE *f; + if ((f = fopen("shping.out", "a")) != NULL) { + fprintf(f, "\n[%s] %s\n", cmdlist[i].tag, cmdlist[i].cmd); + fclose(f); + } + sts = open("shping.out", O_WRONLY|O_APPEND|O_CREAT, 0644); + } +#endif + if (sts == -1) + open("/dev/null", O_WRONLY, 0); + if (dup(1) == -1) { + fprintf(stderr, "Warning: dup() failed: %s\n", pmErrStr(-oserror())); + } + argv[2] = cmdlist[i].cmd; + sts = execv("/bin/sh", argv); + exit(-1); + } + else if (shpid < 0) { + logmessage(LOG_CRIT, "refresh: fork() failed: %s", osstrerror()); + cmdlist[i].status = STATUS_SYS; + cmdlist[i].error = oserror(); + cmdlist[i].real = cmdlist[i].usr = cmdlist[i].sys = -1; + continue; + + } + timedout = 0; + alarm(timeout); + waitpid(shpid, &sts, 0); + __pmtimevalNow(&now); + getrusage(RUSAGE_CHILDREN, &cpu_now); + alarm(0); + + if (timedout) { + cmdlist[i].error = PM_ERR_TIMEOUT; + cmdlist[i].status = STATUS_TIMEOUT; + cmdlist[i].real = cmdlist[i].usr = cmdlist[i].sys = -1; +#ifdef PCP_DEBUG + if (pmDebug & DBG_TRACE_APPL0) + logmessage(LOG_INFO, "[%s] timeout\n", cmdlist[i].tag); +#endif + } + else { + if (WIFEXITED(sts)) { + cmdlist[i].error = WEXITSTATUS(sts); + if (cmdlist[i].error == 0) + cmdlist[i].status = STATUS_OK; + else { + cmdlist[i].status = STATUS_EXIT; +#ifdef PCP_DEBUG + if (pmDebug & DBG_TRACE_APPL0) + logmessage(LOG_INFO, "[%s] exit status: %d\n", + cmdlist[i].tag, cmdlist[i].error); +#endif + } + } + else if (WIFSIGNALED(sts)) { + cmdlist[i].error = WTERMSIG(sts); + cmdlist[i].status = STATUS_SIG; +#ifdef PCP_DEBUG + if (pmDebug & DBG_TRACE_APPL0) + logmessage(LOG_INFO, "[%s] killed signal: %d\n", + cmdlist[i].tag, cmdlist[i].error); +#endif + } + else { + /* assume WIFSTOPPED(sts) */ + cmdlist[i].error = WSTOPSIG(sts); + cmdlist[i].status = STATUS_SIG; +#ifdef PCP_DEBUG + if (pmDebug & DBG_TRACE_APPL0) + logmessage(LOG_INFO, "[%s] stopped signal: %d\n", + cmdlist[i].tag, cmdlist[i].error); +#endif + } + cmdlist[i].real = 1000 * (float)(now.tv_sec - then.tv_sec) + + (float)(now.tv_usec - then.tv_usec) / 1000; + cmdlist[i].usr = 1000 * (float)(cpu_now.ru_utime.tv_sec - cpu_then.ru_utime.tv_sec) + + (float)(cpu_now.ru_utime.tv_usec - cpu_then.ru_utime.tv_usec) / 1000; + cmdlist[i].sys = 1000 * (float)(cpu_now.ru_stime.tv_sec - cpu_then.ru_stime.tv_sec) + + (float)(cpu_now.ru_stime.tv_usec - cpu_then.ru_stime.tv_usec) / 1000; + } + +#ifdef PCP_DEBUG + if (pmDebug & DBG_TRACE_APPL1) + fprintf(stderr, "status: %d error: %d real: %.3f usr: %.3f sys: %.3f\n\n", + cmdlist[i].status, cmdlist[i].error, + cmdlist[i].real, cmdlist[i].usr, cmdlist[i].sys); +#endif + } + + /* + * harvest delinquent children ... includes those who were fork()'d + * above, and timed out. + */ + for ( ; ; ) { + sts = waitpid(-1, NULL, WNOHANG); + if (sts <= 0) + break; + } + + __pmtimevalNow(&now); + if (cycletime) { + waittime = (int)cycletime - now.tv_sec + startcycle.tv_sec; + if (waittime < 0) { + /* can't keep up */ + while (waittime < 0) { + numskip++; + waittime += cycletime; + } + } + sleep(waittime); + } + } +} + +static int +shping_fetch(int numpmid, pmID pmidlist[], pmResult **resp, pmdaExt *ext) +{ + int i; /* over pmidlist[] */ + int j; /* over vset->vlist[] */ + int sts; + int need; + int inst; + int numval; + static pmResult *res = NULL; + static int maxnpmids = 0; + pmValueSet *vset; + __pmID_int *pmidp; + pmAtomValue atom; + pmDesc *dp = NULL; + int type; + +#ifndef HAVE_SPROC + /* In the pthread world we don't have asyncronous notification that + * a thread has died, so we use pthread_kill to check is refresh + * is still running. */ + int err; + + if ( (err = pthread_kill (sprocpid, 0)) != 0 ) { + logmessage (LOG_CRIT, "'refresh' thread is not responding: %s\n", + strerror (err)); + exit (1); + } +#endif + + + if (numpmid > maxnpmids) + { + if (res != NULL) + free(res); + +/* (numpmid - 1) because there's room for one valueSet in a pmResult */ + + need = sizeof(pmResult) + (numpmid - 1) * sizeof(pmValueSet *); + if ((res = (pmResult *) malloc(need)) == NULL) + return -oserror(); + maxnpmids = numpmid; + } + + res->timestamp.tv_sec = 0; + res->timestamp.tv_usec = 0; + res->numpmid = numpmid; + + + for (i = 0; i < numpmid; i++) { + + pmidp = (__pmID_int*)&pmidlist[i]; + dp = NULL; + + if (ext->e_direct) { + if (pmidp->cluster == 0 && pmidp->item < nummetric) + dp = &metrics[pmidp->item].m_desc; + } + else { + for (j = 1; j<nummetric; j++) { + if (pmidp->cluster == 0 && + metrics[j].m_desc.pmid == pmidlist[i]) { + dp = &metrics[j].m_desc; + break; + } + } + } + + if (dp == NULL) + numval = PM_ERR_PMID; + else { + if (dp->indom != PM_INDOM_NULL) { + numval = 0; + __pmdaStartInst(dp->indom, ext); + while(__pmdaNextInst(&inst, ext)) { + numval++; + } + } + else { + numval = 1; + } + } + + if (numval >= 1) + res->vset[i] = vset = (pmValueSet *)malloc(sizeof(pmValueSet) + + (numval - 1)*sizeof(pmValue)); + else + res->vset[i] = vset = (pmValueSet *)malloc(sizeof(pmValueSet) - + sizeof(pmValue)); + + if (vset == NULL) { + if (i) { + res->numpmid = i; + __pmFreeResultValues(res); + } + return -oserror(); + } + vset->pmid = pmidlist[i]; + vset->numval = numval; + vset->valfmt = PM_VAL_INSITU; + if (vset->numval <= 0) + continue; + + if (dp->indom == PM_INDOM_NULL) + inst = PM_IN_NULL; + else { + __pmdaStartInst(dp->indom, ext); + __pmdaNextInst(&inst, ext); + } + + type = dp->type; + pmidp = (__pmID_int *)&pmidlist[i]; + j = 0; + + do { + if (j == numval) { + /* more instances than expected! */ + numval++; + res->vset[i] = vset = (pmValueSet *)realloc(vset, + sizeof(pmValueSet) + (numval - 1)*sizeof(pmValue)); + if (vset == NULL) { + if (i) { + res->numpmid = i; + __pmFreeResultValues(res); + } + return -oserror(); + } + } + vset->vlist[j].inst = inst; + + if (pmidp->cluster == 0) { + switch (pmidp->item) { + + case 0: /* shping.time.real PMID: ...0.0 */ + atom.f = cmdlist[inst].real; + break; + + case 1: /* shping.time.cpu_usr PMID: ...0.1 */ + atom.f = cmdlist[inst].usr; + break; + + case 2: /* shping.time.cpu_sys PMID: ...0.2 */ + atom.f = cmdlist[inst].sys; + break; + + case 3: /* shping.control.numcmd PMID: ...0.3 */ + atom.ul = numcmd; + break; + + case 4: /* shping.control.cycletime PMID: ...0.4 */ + atom.ul = cycletime; + break; + + case 5: /* shping.control.timeout PMID: ...0.5 */ + atom.ul = timeout; + break; + + case 6: /* shping.status PMID: ...0.6 */ + atom.l = cmdlist[inst].status; + break; + + case 7: /* shping.cmd PMID: ...0.7 */ + atom.cp = cmdlist[inst].cmd; + break; + + case 8: /* shping.control.debug PMID: ...0.8 */ + atom.l = pmDebug; + break; + + case 9: /* shping.control.cycles PMID: ...0.9 */ + atom.ul = cycles; + break; + + case 10: /* shping.error PMID: ...0.10 */ + atom.ul = cmdlist[inst].error; + break; + + default: + j = PM_ERR_PMID; + break; + } + } + if (j < 0) + break; + + sts = __pmStuffValue(&atom, &vset->vlist[j], type); + if (sts < 0) { + __pmFreeResultValues(res); + return sts; + } + + vset->valfmt = sts; + j++; /* next element in vlist[] for next instance */ + } while (dp->indom != PM_INDOM_NULL && __pmdaNextInst(&inst, ext)); + + vset->numval = j; + } + *resp = res; + return 0; +} + +static int +shping_store(pmResult *result, pmdaExt *ext) +{ + int i; + pmValueSet *vsp; + int sts = 0; + int ival; + __pmID_int *pmidp; + + for (i = 0; i < result->numpmid; i++) { + vsp = result->vset[i]; + pmidp = (__pmID_int *)&vsp->pmid; + if (pmidp->cluster == 0) { + switch (pmidp->item) { + case 4: /* shping.control.cycletime PMID: ...0.4 */ + ival = vsp->vlist[0].value.lval; + if (ival < 0) { + sts = PM_ERR_SIGN; + break; + } + cycletime = ival; + break; + + case 5: /* shping.control.timeout PMID: ...0.5 */ + ival = vsp->vlist[0].value.lval; + if (ival < 0) { + sts = PM_ERR_SIGN; + break; + } + timeout = ival; + break; + + case 8: /* shping.control.debug PMID: ...0.8 */ + ival = vsp->vlist[0].value.lval; + if (ival < 0) { + sts = PM_ERR_SIGN; + break; + } + pmDebug = ival; + break; + + default: + sts = PM_ERR_PMID; + break; + } + } + else { + /* not one of the metrics we are willing to change */ + sts = PM_ERR_PMID; + break; + } + } + return sts; +} + +void +shping_init(pmdaInterface *dp) +{ + if (dp->status != 0) + return; + + unlink("shping.out"); /* just in case */ + + dp->version.two.fetch = shping_fetch; + dp->version.two.store = shping_store; + + pmdaInit(dp, &indomtab, 1, metrics, nummetric); + + if (dp->version.two.ext->e_direct == 0) { + logmessage(LOG_CRIT, "Metric tables require direct mapping.\n"); + dp->status = -1; + return; + } + + numcmd = indomtab.it_numinst; + + /* start the sproc for async fetches */ +#ifdef HAVE_SPROC + if ( (sprocpid = sproc(refresh, PR_SADDR, NULL)) < 0 ) { + logmessage(LOG_CRIT, "sproc failed: %s\n", osstrerror()); + dp->status = sprocpid; + } + else { + dp->status = 0; + logmessage(LOG_INFO, "Started sproc (spid=%" FMT_PID ")\n", sprocpid); + } + + /* we're talking to pmcd ... no timeout's for us thanks */ + signal(SIGALRM, SIG_IGN); + +#elif defined (HAVE_PTHREAD_H) + { + int err = pthread_create(&sprocpid, NULL, (void (*))refresh, NULL); + if ( err != 0 ) { + logmessage (LOG_CRIT, "Cannot spawn a new thread: %s\n", + strerror (err)); + dp->status = err; + } else { + dp->status = 0; + logmessage (LOG_INFO, "Started refresh thread\n"); + } + } +#else +#error "Need pthreads or sproc" +#endif +} diff --git a/src/pmdas/shping/shping.h b/src/pmdas/shping/shping.h new file mode 100644 index 0000000..1c266a1 --- /dev/null +++ b/src/pmdas/shping/shping.h @@ -0,0 +1,54 @@ +/* + * Copyright (c) 1995 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-1301 USA + */ + +#include "pmapi.h" +#include "impl.h" +#include "pmda.h" + +typedef struct { + char *tag; + char *cmd; + int status; + int error; + float real; + float usr; + float sys; +} cmd_t; + +#define STATUS_NOTYET -1 +#define STATUS_OK 0 +#define STATUS_EXIT 1 +#define STATUS_SIG 2 +#define STATUS_TIMEOUT 3 +#define STATUS_SYS 4 + +extern cmd_t *cmdlist; + +extern __uint32_t cycletime; /* seconds per command cycle */ +extern __uint32_t timeout; /* response timeout in seconds */ +#ifdef HAVE_SPROC +extern pid_t sprocpid; /* for refresh() */ +#endif +extern pmdaIndom indomtab; /* cmd tag indom */ + +extern int pmDebug; +extern char *pmProgname; + +extern void shping_init(pmdaInterface *); + +extern void logmessage(int, const char *, ...); diff --git a/src/pmdas/shping/shping.response.pmie b/src/pmdas/shping/shping.response.pmie new file mode 100644 index 0000000..f77457a --- /dev/null +++ b/src/pmdas/shping/shping.response.pmie @@ -0,0 +1,67 @@ +#pmieconf-rules 1 +# --- DO NOT MODIFY THIS FILE --- see pmieconf(4) + +rule shping.response + summary = "$rule$" + enumerate = hosts + predicate = +"some_inst ( + shping.time.real $hosts$ > $threshold$ && + shping.status $hosts$ == 0 +)" + enabled = no + version = 1 + help = +"A monitored application or service probe from the shping PMDA +has taken more than threshold milliseconds to complete. + +If this rule is enabled, the shping PMDA should be installed; see +$PCP_PMDAS_DIR/shping/README and pmdashping(1). + +If some application or service is not available then the +corresponding line should be commented out of the shping +configuration file ($PCP_PMDAS_DIR/shping/shping.conf by default) +and the shping PMDA restarted."; + +string rule + default = "Shell-ping PMDA slow application or service response" + modify = no + display = no; + +unsigned threshold + default = 3000 + help = +"Threshold time, in milliseconds, for command to run to completion."; + +string action_expand + default = %vmsec[%i] + display = no + modify = no; + +string email_expand + default = "service: %i response time: %vmsec" + display = no + modify = no; + + +# Configuration info specific to non-PCP tools follows... +# + +# for SGI Embedded Support Partner integration: +string esp_type + default = "0x200095" + display = no + modify = no; + +# for EnlightenDSM integration: +string enln_test + default = shping.response + display = no + modify = no; +string enln_units + default = msec[%i] + display = no + modify = no; + +# +# --- DO NOT MODIFY THIS FILE --- see pmieconf(4) diff --git a/src/pmdas/shping/shping.status.pmie b/src/pmdas/shping/shping.status.pmie new file mode 100644 index 0000000..199c600 --- /dev/null +++ b/src/pmdas/shping/shping.status.pmie @@ -0,0 +1,63 @@ +#pmieconf-rules 1 +# --- DO NOT MODIFY THIS FILE --- see pmieconf(4) + +rule shping.status + summary = "$rule$" + enumerate = hosts + predicate = +"some_inst ( + shping.status $hosts$ @0 > 0 && shping.status $hosts$ @1 == 0 +)" + enabled = no + version = 1 + help = +"An application or service being monitored by the shping PMDA was +previously probed successfully and the probe has either failed, or +not responded within a timeout period (as defined by the PCP metric +shping.control.timeout) during the last sample interval. + +If this rule is enabled, the shping PMDA should be installed; see +$PCP_PMDAS_DIR/shping/README and pmdashping(1). + +If some application or service is not available then the +corresponding line should be commented out of the shping +configuration file ($PCP_PMDAS_DIR/shping/shping.conf by default) +and the shping PMDA restarted."; + +string rule + default = "Shell-ping PMDA application or service probe failure" + modify = no + display = no; + +string action_expand + default = %i + display = no + modify = no; + +string email_expand + default = "application or service: %i" + display = no + modify = no; + + +# Configuration info specific to non-PCP tools follows... +# + +# for SGI Embedded Support Partner integration: +string esp_type + default = "0x200090" + display = no + modify = no; + +# for EnlightenDSM integration: +string enln_test + default = shping.status + display = no + modify = no; +string enln_units + default = exit_status + display = no + modify = no; + +# +# --- DO NOT MODIFY THIS FILE --- see pmieconf(4) |