#!/bin/bash
# A better df for NetApp 7.1 .. 7.3
# 20060520 rzm@icm.edu.pl
# 20060901 multiple arguments
# 20070303 date
# 20070523 do not show vols if there are none; -A option (Aggr-sum)
# 20080627 multi-line Volumes after aggr status!:
#                Volumes: bioinfo_backup, rzm, backup_hpc, backup_kam,
#                         backup_pub
# 2011-12-28 take into account "snap reserve" entries, use $(NF-x) to accomodate to changing format (6 or 7 fields); add 0.01 to snap size, limit % to 9999
# 2012-01-05 -n option added to ssh; -t option - show commands' timing
# TODO:
# Total-vol-sum, Total-aggr-sum - as options?
# option for sums only
# option to count percentage of used space from only 80% of total (recomended filling coeficient)
# specified aggregates/vols only
awk=/local/bin/gawk

#while [ "$1" = "-A" -o "$1" = "" -o "$1" = "-h" -o "$1" = "--help" ]; do
while [[ "$1" =~ -[Aht] ]]; do
	case "$1" in
		"-A")			shift; aggrsum=1;;
		"-t")			shift; prtime=1;;
		"" | "-h" | "--help")	shift; echo 'Usage: netapp-df [--help] [-A] [NAME ...]'; echo "  -A   show aggregates sums"; exit 0;;
	esac
done

name="$1"
while [ "$name" != "" ]; do

echo | $awk -v name="$name" -v aggrsum="$aggrsum" -v prtime="$prtime" 'BEGIN {
	cmd = "ssh -n root@"name
	cmddfaggr = cmd " df -A"
	cmddfvol = cmd " df"
	cmdaggrst = cmd " aggr status"
	scale = 1024^2		# scales KB to GB
}

function percent(used, size) {
	if (size > 0) { return 100 * used/size } else { return 0 }
}

END {
#print "CMD:", cmddfaggr
	t00 = t0 = systime()
	while (cmddfaggr | getline) {
		if ($1 == "Aggregate") continue
#print
		aggr = $1
		if ($1 !~ /.*\.snapshot$/) {
			aggrsize[$1] = $2; aggrused[$1] = $3; aggravail[$1] = $4
		} else {
			gsub("/.snapshot$", "", aggr)
			aggrsnapsize[aggr] = $2; aggrsnapused[aggr] = $3; aggrsnapavail[aggr] = $4
		}
	}
	close(cmddfaggr)
if (prtime) print "TIME", cmddfaggr, systime() - t0

	for (iaggr in aggrsize) {
#print "iaggr:", iaggr
		cmd = cmdaggrst " " iaggr
		invol = 0
		t0 = systime()
		while (cmd | getline) {
#print
			if ($2 == "<none>") break;
			if ($0 == "") invol = 0;
			if ( invol || ($1 == "Volumes:") ) {
				vols = $0; gsub("^.*Volumes: ", "", vols); gsub(",", "", vols)
#print "Volumes: <"vols">"
				aggrvols[iaggr] = aggrvols[iaggr] " " vols
				invol = 1
			}
		}
if (prtime) print "TIME", cmd, systime() - t0
	}

	t0 = systime()
	while (cmddfvol | getline) {
		if ($1 !~ /(^\/vol\/|^snap)/) continue				# dont loose "^snap reserve"
#print
		vol = $NF; gsub("^/vol/", "", vol); gsub("/$", "", vol)		# $6/$7 is similar to $1 but does not loose vol name for snaps
#print "vol:", vol
		if ($1 ~ /(\/\.snapshot$|^snap$)/) {
			gsub("/\\.snapshot$", "", vol)
			gsub("/\\.\\.$", "", vol)
			volsnapsize[vol] = $(NF-4); volsnapused[vol] = $(NF-3); volsnapavail[vol] = $(NF-2)	# irregular format
			if ($0 ~ /^snap reserve/) { volsnapres[vol] = 1 } else { volsnapres[vol] = 0 } 
#print "snap:", vol, volsnapsize[vol], volsnapused[vol], volsnapavail[vol], volsnapres[vol]
		} else {
			volsize[vol] = $2; volused[vol] = $3; volavail[vol] = $4
		}
	}
if (prtime) print "TIME", cmddfvol, systime() - t0
if (prtime) print "TIME", "total", systime() - t00

	i = 0
	for (iaggr in aggrsize) aggrind[i++] = iaggr
	naggr = asort(aggrind)

	svolused = svolsize = svolavai = svolsnapused = svolsnapsize = svolsnapavail = 0

	printf "\n-> %-16.16s         aggregate/volume  [GB]  snap [%s]\n", name, strftime()
	print "name                      used  size avail   %     used size avail   %"
	for (ia = 1; ia <= naggr; ia++) {
		aggr = aggrind[ia]
		if (aggrsize[aggr] > 0) { acap = 100 * aggrused[aggr]/aggrsize[aggr] } else { acap = 0 }
		if (aggrsnapsize[aggr] > 0) { ascap = 100 * aggrsnapused[aggr]/aggrsnapsize[aggr] } else { ascap = 0 }
		printf "%-24s %5d %5d %5d %3d   %5d %5d %5d %3d\n", aggr, aggrused[aggr]/scale, aggrsize[aggr]/scale, aggravail[aggr]/scale, acap, aggrsnapused[aggr]/scale, aggrsnapsize[aggr]/scale, aggrsnapavail[aggr]/scale, ascap
		saggrused += aggrused[aggr]; saggrsize += aggrsize[aggr]; saggravail += aggravail[aggr]
		saggrsnapused += aggrsnapused[aggr]; saggrsnapsize += aggrsnapsize[aggr]; saggrsnapavail += aggrsnapavail[aggr]


		split(aggrvols[aggr], volind)
		nvols = asort(volind)
#print nvols

		for (iv = 1; iv <= nvols; iv++) {
			vol = volind[iv]
			vcap = 100 * volused[vol]/(volsize[vol] + 0.01); if (vcap > 9999) vcap = 9999
			vscap = 100 * volsnapused[vol]/(volsnapsize[vol] + 0.01); if (vscap > 9999) vscap = 9999
			printf "  %-22s %5d %5d %5d %3d   %5d %5d %5d %3d\n", vol, volused[vol]/scale, volsize[vol]/scale, volavail[vol]/scale, vcap, volsnapused[vol]/scale, volsnapsize[vol]/scale, volsnapavail[vol]/scale, vscap
#print vol, volsnapsize[vol], volsnapused[vol], volsnapavail[vol], vscap
			svolused += volused[vol]; svolsize += volsize[vol]; svolavail += volavail[vol]
			svolsnapused += volsnapused[vol]; svolsnapsize += volsnapsize[vol]; svolsnapavail += volsnapavail[vol]
		}
	}
	printf "%-24s %5d %5d %5d %3d   %5d %5d %5d %3d\n", "Vol-sum:", svolused/scale, svolsize/scale, svolavail/scale, percent(svolused, svolsize), svolsnapused/scale, svolsnapsize/scale, svolsnapavail/scale, percent(svolsnapused, svolsnapsize)
	if (aggrsum) printf "%-24s %5d %5d %5d %3d   %5d %5d %5d %3d\n", "Aggr-sum:", saggrused/scale, saggrsize/scale, saggravail/scale, percent(saggrused, saggrsize), saggrsnapused/scale, saggrsnapsize/scale, saggrsnapavail/scale, percent(saggrsnapused, saggrsnapsize)
}'


shift
name=$1
done

exit
# ssh root@sata2 df -A
Aggregate               kbytes       used      avail capacity
s2_1a2a             12896275508 9346973816 3549301692      72%
s2_1a2a/.snapshot            0          0          0     ---%
...
# ssh root@sata2 df
Filesystem              kbytes       used      avail capacity  Mounted on
/vol/umpl_db/       2899102928 1411087408 1488015520      49%  /vol/umpl_db/
/vol/umpl_db/.snapshot  322122544    2058212  320064332       1%  /vol/umpl_db/.snapshot
...
# ssh root@sata2 aggr status s2_1a
           Aggr State      Status            Options
          s2_1a online     raid_dp, aggr     nosnap=on, raidsize=16

                Volumes: meteo_obs

                Plex /s2_1a/plex0: online, normal, active
                    RAID group /s2_1a/plex0/rg0: normal

...
                Volumes: umpl_db, umpl_archiwum, rzm, backup_hpc
