#!@@BASH@@
# -*- sh -*-

: <<'=cut'

=head1 NAME

vserver_cpu_ - Wildcard plugin to graph CPU usage types per vserver

=head1 CONFIGURATION

 [vserver_cpu_*]
   env.vservers - List of vservers to include in the graph, or "all"

=head2 DEFAULT CONFIGURATION

 [vserver_cpu_*]
   env.vservers all

=head1 USAGE

Configuration variables
  vservers - specify the vservers to include in the graph (default: all)

NOTE: If no configuration variable is set, the default will be used

see vserver_resources for example uses of configuration files

or links to define what to monitor:
 vserver_cpu_      -> monitor cpu usage of all vservers on all cpus
 vserver_hold_    -> monitor hold on all vservers on all cpus
 vserver_hold_0   -> monitor hold on all vservers on cpu0
 vserver_hold_1   -> monitor hold on all vservers on cpu1
 vserver_hold_foo -> monitor hold on all cpus on vserver named foo
 vserver_sys_foo  -> monitor cpu usage on all cpus on vserver named foo

=head1 AUTHOR

Copyright (C) 2006-2008 Holger Levsen

Copyright (C) 2006-2008 Micah Anderson

=head1 LICENSE

GNU GPLv2

=begin comment

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; version 2 dated June, 1991.

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.

=end comment

=head1 TODO

=over 4

=item Less shell subprocesses

The plugin uses lots and lots of shell subprocesses.  Maybe factor
common vserver plugin code into Munin::Plugin::Linux::Vserver?

=item Comments

Comment the code or go mad

=item Jiffies per second

Add info how many jiffies per second are available on a machine

=item Split CPU time

User and system cpu are always added to each other, make it optional
to split them?

=item Less use of /proc

use /proc less often (100 times more overhead than talking to the
kernel directly) i.e. use something like pagesize=\`perl -MPOSIX -e
'print POSIX::sysconf(_SC_PAGESIZE), "\n";'\`

(Accoding to many using /proc is a feature not a bug - Nicoali
Langfeldt 2009-12-23)

=back

=head1 MAGIC MARKERS

  #%# family=auto
  #%# capabilities=autoconf suggest

=cut

if [ "$1" = "autoconf" ]; then
	if [ -r /proc/virtual/info ]; then
		echo yes
	else
		echo "no (/proc/virtual/info not found)"
	fi
	exit 0
fi

if [ "$1" = "suggest" ]; then
	if [ ! -r /proc/virtual/info ]; then
		exit 1
	fi
	#
	# 'else' clause is after XIDS definition
	#
fi

VSERVERS="${vservers:-}"

# shellcheck disable=SC2207
INFO=($(sed 's/.*:\t//' /proc/virtual/info 2>/dev/null || echo '<none>'))
KCIN=$(( 16#${INFO[2]} ))

# If this is 1, then VCI_SPACES is present in the kernel (new in 2.6.19)
if [ $(( (KCIN >> 10) & 1 )) -eq 1 ]
then
    NAMELOC="nsproxy"
else
    NAMELOC="cvirt"
fi

if [ -z "$VSERVERS" ] ; then
    XIDS=$(find /proc/virtual/* -type d -exec basename {} \;)
else
    # it's really more performant to specify vservers by ids or by linking but not in the configuration-file by name
    XIDS=""
    for i in $VSERVERS ; do
        if [ -d "/proc/virtual/$i" ]; then
            XIDS="${XIDS}${i} "
        else
            # shellcheck disable=SC2044
            for j in $(find /proc/virtual/* -type d -exec basename {} \;); do
                if [ "$i" = "$(grep "NodeName" "/proc/virtual/$j/$NAMELOC" | cut -f 2)" ] ; then
                    XIDS="${XIDS}${j} "
                fi
            done
        fi
    done
fi

if [ "$1" = "suggest" ]; then
	if [ -r /proc/virtual/info ]; then
	        for i in $XIDS ; do
			LABEL=$(grep "NodeName" "/proc/virtual/$i/$NAMELOC" | cut -f 2)
			echo "$LABEL"
		done
		exit 0
	fi
fi

# shellcheck disable=SC2001
BASEPARAM=$(basename "$0" | sed 's/^vserver_//')
# shellcheck disable=SC2001
MODE=$(echo "$BASEPARAM" | sed 's/^hold.*//')

debug=${debug:-}

if [ -z "$MODE" ] ; then
	MODE=hold
	# shellcheck disable=SC2001
	TARGET=$(echo "$BASEPARAM" | sed 's/^hold_//')
else
	MODE=cpu
	# shellcheck disable=SC2001
	TARGET=$(echo "$BASEPARAM" | sed 's/^cpu_//')
fi

CPU1=0
if [ -n "$TARGET" ] ; then
	if [ "${#TARGET}" == 1 ] ; then
		if [ -n "$debug" ]; then echo "$MODE, only on cpu $TARGET, for all vservers"; fi
		WHAT=ALLVSERVER
		CPU1=$TARGET
	else
		if [ -n "$debug" ]; then echo "$MODE on all cpus together, only for vserver $TARGET"; fi
		WHAT=VSERVER
	fi
else
	if [ -n "$debug" ] ; then echo "$MODE for all cpus, for all vservers"; fi
	WHAT=ALLVSERVER
fi

CPUS=$(( $(grep ^processor /proc/cpuinfo | wc -l) - 1 ))
CPUS=$(seq "$CPU1" "$CPUS")

if [ -n "$debug" ] ; then
	echo "cpus= $CPUS"
	echo "baseparam= $BASEPARAM"
	echo "mode= $MODE "
	echo "target= $TARGET"
	echo "what= $WHAT"
fi

if [ "$1" = "config" ]; then
	echo 'graph_category vserver'
	echo 'graph_args --base 1000'
	if [ "$MODE" == "cpu" ] ; then
		echo 'graph_title Vserver cpu usage'
		# shellcheck disable=SC2016
		echo 'graph_vlabel jiffies used per cpu per ${graph_period}'
		echo 'graph_info Shows jiffies used per cpu on each vserver.'
	else
		echo 'graph_title Vserver cpu on hold'
		# shellcheck disable=SC2016
		echo 'graph_vlabel jiffies on hold per cpu per ${graph_period}'
		echo 'graph_info Shows jiffies on hold used per cpu on each vserver.'
	fi

 	for j in $CPUS ; do
		A=0
	        for i in $XIDS ; do
			LABEL=$(grep "NodeName" "/proc/virtual/$i/$NAMELOC" | cut -f 2)
			if [ "$WHAT" == "ALLVSERVER" ] || [ "$TARGET" == "$LABEL" ] ; then
				NAME=$(echo "$LABEL" | cut -d. -f1 |  tr '-' '_')
	    			if [ "$MODE" == "cpu" ] ; then
					echo "${NAME}_$j.label cpu usage for cpu $j on $LABEL"
					echo "${NAME}_$j.info cpu usage for cpu $j on $LABEL."
				else
					echo "${NAME}_$j.label on hold for cpu $j on $LABEL"
					echo "${NAME}_$j.info on hold for cpu $j on $LABEL."
				fi
				echo "${NAME}_$j.type COUNTER"
				if [ "$A" == 0 ] ; then
					echo "${NAME}_$j.draw AREA"
					A=1
				else
					echo "${NAME}_$j.draw STACK"
 				fi
			fi
		done
	done
	exit 0
fi

for j in $CPUS ; do
	for i in $XIDS ; do
		LABEL=$(grep "NodeName" "/proc/virtual/$i/$NAMELOC" | cut -f 2)
		if [ "$WHAT" == "ALLVSERVER" ] || [ "$TARGET" == "$LABEL" ] ; then
			NAME=$(echo "$LABEL" | cut -d. -f1 |  tr '-' '_')
			echo -n "${NAME}_$j.value "
			if [ "$MODE" == "cpu" ] ; then
				USERCPU=$(grep "cpu $j:" "/proc/virtual/$i/sched" | cut -d' ' -f 3)
				SYSCPU=$(grep "cpu $j:" "/proc/virtual/$i/sched" | cut -d' ' -f 4)
				echo $((USERCPU + SYSCPU))
			else
				grep "cpu $j:" "/proc/virtual/$i/sched" | cut -d ' ' -f 5
			fi
		fi
	done
done
