Skip to content
This repository
Browse code

Merge pull request #122 from C-Duv/netatalk

Adding "netatalk" plugin: monitors number of files held open by the Netatalk/AFP clients
  • Loading branch information...
commit 17604e11ec49ffc438f283106f4e7c8a55aa3a45 2 parents d569cb8 + e94af31
Steve Schnepp authored June 01, 2012

Showing 1 changed file with 159 additions and 0 deletions. Show diff stats Hide diff stats

  1. 159  plugins/network/netatalk
159  plugins/network/netatalk
... ...
@@ -0,0 +1,159 @@
  1
+#!/bin/bash
  2
+
  3
+: << =cut
  4
+
  5
+=head1 NAME
  6
+
  7
+netatalk - Plugin to monitor number of files held open by the Netatalk/AFP clients
  8
+
  9
+=head1 CONFIGURATION
  10
+
  11
+This plugin uses the following configuration variables
  12
+
  13
+  [netatalk]
  14
+  user root		- Plugin must run under root for lsof
  15
+  env.afpd		- Path to "afpd" executable (defaults to what afpd -v says, usually "/usr/sbin/afpd")
  16
+  env.afpdconf	- Path to "afpd.conf" file (defaults to what afpd -v says, usually "/etc/netatalk/afpd.conf")
  17
+
  18
+=head1 VERSION
  19
+
  20
+0.1 (2012-05-23)
  21
+
  22
+=head1 AUTHOR
  23
+
  24
+DUVERGIER Claude (http://claude.duvergier.fr)
  25
+
  26
+=head1 LICENSE
  27
+
  28
+GPLv2
  29
+
  30
+=head1 BUGS
  31
+
  32
+Known bugs:
  33
+* A bug can occur if a shared path is located inside another shared path (eg. "/mnt/afpShares/foo" and  "/mnt/afpShares/foo/subFoo/bar").
  34
+  Depending of the order the shares are found, the script might say the less-deeper one is opened whereas he is processing the other one.
  35
+
  36
+=head1 TODO
  37
+
  38
+Features to-do list:
  39
+* Support multiple servers
  40
+
  41
+=head1 MAGIC MARKERS
  42
+
  43
+ #%# family=contrib
  44
+ #%# capabilities=autoconf
  45
+
  46
+=cut
  47
+
  48
+# Find "afpd" location:
  49
+afpdPath=${afpd:-`which afpd`}
  50
+afpdPath=${afpdPath:-/usr/sbin/afpd}
  51
+
  52
+
  53
+
  54
+#####
  55
+## Munin configuration ("autoconf" and "config")
  56
+#####
  57
+
  58
+if [ "$1" = "autoconf" ]; then
  59
+	if [ -x $afpdPath ]; then
  60
+		echo yes
  61
+		exit 0
  62
+	else
  63
+		echo no '(afpd not found)'
  64
+		exit 0
  65
+	fi
  66
+fi
  67
+
  68
+if [ "$1" = "config" ]; then
  69
+	echo 'graph_title Netatalk status'
  70
+	echo 'graph_args --logarithmic --lower-limit 0.1'
  71
+	echo 'graph_vlabel Number'
  72
+	echo 'graph_category network'
  73
+	echo 'proc.label Running processes'
  74
+	echo 'proc.info Number of running afpd processes'
  75
+	echo 'proc.min 0'
  76
+	echo 'user.label Connected users'
  77
+	echo 'user.info Number of users connected to netatalk service'
  78
+	echo 'user.min 0'
  79
+	echo 'lock.label Locked files'
  80
+	echo 'lock.info Number of files locked by afpd'
  81
+	echo 'lock.min 0'
  82
+	echo 'share.label Open shares'
  83
+	echo 'share.info Number of open netatalk shares'
  84
+	echo 'share.min 0'
  85
+	exit 0
  86
+fi
  87
+
  88
+##########
  89
+
  90
+
  91
+
  92
+#####
  93
+## Script environment
  94
+#####
  95
+
  96
+# Find "afpd.conf" location:
  97
+afpdConfPath=${afpdconf:-`$afpdPath -v 2>/dev/null | grep "afpd.conf" | awk '{print $2}'`}
  98
+
  99
+baseLsofCommand="lsof -a -c $(basename $afpdPath) -d ^DEL,^err,^jld,^ltx,^Mxx,^m86,^mem,^mmap,^pd,^rtd,^tr,^txt,^v86"
  100
+
  101
+#TODO: Support multiple servers
  102
+defaultServer_defaultVolConfigLine=$(cat $afpdConfPath | grep "^[^#]" | grep "\-defaultvol")
  103
+if [ -z "$defaultServer_defaultVolConfigLine" ]; then
  104
+	defaultServer_volumesFile=`$afpdPath -v 2>/dev/null | grep "AppleVolumes.default" | awk '{print $2}'` # Default location "AppleVolumes.default"
  105
+else
  106
+	defaultVol_pathIsQuoted="-defaultvol ('|\")"
  107
+	defaultVol_quotedPattern="-defaultvol ('|\")([^\1]*)\1"
  108
+	# Following regex is from http://stackoverflow.com/questions/537772/what-is-the-most-correct-regular-expression-for-a-unix-file-path
  109
+	defaultVol_nonQuotedPattern='-defaultvo(l) (([^\0 !$`&*()+]|\\( |!|$|`|&|\*|\(|\)|\+))+)'
  110
+	defaultVol_pathPattern=$defaultVol_nonQuotedPattern
  111
+	[[ $defaultServer_defaultVolConfigLine =~ $defaultVol_pathIsQuoted ]] && defaultVol_pathPattern=$defaultVol_quotedPattern
  112
+	[[ $defaultServer_defaultVolConfigLine =~ $defaultVol_pathPattern ]] && defaultServer_volumesFile = ${BASH_REMATCH[2]}
  113
+fi
  114
+
  115
+##########
  116
+
  117
+
  118
+
  119
+#####
  120
+## Actual monitoring
  121
+#####
  122
+
  123
+# Running processes (proc):
  124
+echo "proc.value" $(ps ax --no-headers -o command | grep "^$afpdPath" | wc -l)
  125
+
  126
+# Connected users (user):
  127
+# We will ignore root (having UID=0 it's line will be first) (assomption done: there will have only one line corresponding to root in `ps` output)
  128
+connectedUsers=$(ps anx --no-headers -o uid,command | sed 's/^ *//g' | grep "^[0-9]* $afpdPath" | sort -n | tail -n +2 | awk '{print $1}')
  129
+echo "user.value" `echo $connectedUsers | wc -w`
  130
+
  131
+# Locked files (lock):
  132
+echo "lock.value" $($baseLsofCommand -F l | grep "^l[rRwWu]" | wc -l)
  133
+
  134
+# Open shares (share):
  135
+openShares=0
  136
+
  137
+#TOFIX: A bug can occur if a shared path is located inside another shared path (eg. "/mnt/afpShares/foo" and  "/mnt/afpShares/foo/subFoo/bar"):
  138
+#       Depending of the order the shares are found, the script might say the less-deeper one is opened whereas he is processing the other one
  139
+#       Solution: sort shares per descending depth
  140
+
  141
+# Following regex is from http://stackoverflow.com/questions/10134129/generic-shell-bash-method-to-parse-string-for-possibly-quoted-fields
  142
+for shareName in `cat $defaultServer_volumesFile | grep "^[^#:]" | grep -oP "^(['\"]).*?\1|^(\\\\ |[^ '\"])*"`; do
  143
+	if [[ "$shareName" =~ "~" ]]; then
  144
+		for currentUid in $connectedUsers; do # For each connected users
  145
+			currentUserHomeDir=`getent passwd $currentUid | cut -d ':' -f6` # Fetch it's the home directory
  146
+			currentUserHomeDir=`readlink -f "$currentUserHomeDir"` # We want the realpath (resolves symbolic links and normalize the path)
  147
+			
  148
+			#FIX: We use pipe `lsof` outputs to `echo -e` with `xargs` because lsof "displays only printable ASCII characters" (cf. http://ftp.cerias.purdue.edu/pub/tools/unix/sysutils/lsof/00FAQ #14.5)
  149
+			#     Then if a share with non-ASCII characters in it's path were to be opened, lsof would return them on \xNN form and grep wouldn't match: `echo -e /the/path` fixes this
  150
+			[ `$baseLsofCommand -F n | xargs -0 echo -e | grep "^n$currentUserHomeDir" | wc -l` -gt 0 ] && let openShares++ # If found in lsof output: increment the openShares counter
  151
+		done
  152
+	else
  153
+		shareName=`readlink -f "$shareName"` # We want the realpath (resolves symbolic links and normalize the path)
  154
+		[ `$baseLsofCommand -F n | xargs -0 echo -e | grep "^n$shareName" | wc -l` -gt 0 ] && let openShares++ # If found in lsof output: increment the openShares counter
  155
+	fi
  156
+done
  157
+echo "share.value" $openShares
  158
+
  159
+##########

0 notes on commit 17604e1

Please sign in to comment.
Something went wrong with that request. Please try again.