|  | 
|  | 1 | +#!/bin/sh | 
|  | 2 | + | 
|  | 3 | +set -e | 
|  | 4 | + | 
|  | 5 | +: << =cut | 
|  | 6 | +
 | 
|  | 7 | +=head1 NAME | 
|  | 8 | +
 | 
|  | 9 | +arcconf - Monitor RAID adapters, logical devices and physical disks with arcconf | 
|  | 10 | +
 | 
|  | 11 | +=head1 APPLICABLE SYSTEMS | 
|  | 12 | +
 | 
|  | 13 | +Raid adapters managed with arcconf | 
|  | 14 | +
 | 
|  | 15 | +=head1 CONFIGURATION | 
|  | 16 | +
 | 
|  | 17 | + With "arcconf list" you find available controllers. Link arcconf_ with  | 
|  | 18 | + specified controller id. | 
|  | 19 | +  | 
|  | 20 | + ln -s /usr/share/munin/plugins/arcconf_ /etc/munin/plugins/arcconf_1 | 
|  | 21 | +
 | 
|  | 22 | + arcconf_bin   - Path to arcconf binary | 
|  | 23 | +
 | 
|  | 24 | + [arcconf_*] | 
|  | 25 | + user root | 
|  | 26 | + env.arcconf_bin /usr/local/sbin/arcconf | 
|  | 27 | +  | 
|  | 28 | + [arcconf_1] | 
|  | 29 | + env.min_online_disks 12 # Miniaml online disks | 
|  | 30 | + env.max_adapter_temp 50 # Adapter temperature threshold | 
|  | 31 | +  | 
|  | 32 | +=head1 AUTHOR | 
|  | 33 | +
 | 
|  | 34 | +Copyright (C) 2020 Sebastian L. (https://momou.ch) | 
|  | 35 | +
 | 
|  | 36 | +=head1 LICENSE | 
|  | 37 | +
 | 
|  | 38 | +GPLv2 | 
|  | 39 | +
 | 
|  | 40 | +=head1 MAGIC MARKERS | 
|  | 41 | +
 | 
|  | 42 | + #%# family=auto | 
|  | 43 | + #%# capabilities=autoconf | 
|  | 44 | +
 | 
|  | 45 | +=cut | 
|  | 46 | + | 
|  | 47 | +. "$MUNIN_LIBDIR/plugins/plugin.sh" | 
|  | 48 | + | 
|  | 49 | +if [ "${MUNIN_DEBUG:-0}" = 1 ]; then | 
|  | 50 | +    set -x | 
|  | 51 | +fi | 
|  | 52 | + | 
|  | 53 | +arcconf_bin="${arcconf_bin:-/usr/local/sbin/arcconf}" | 
|  | 54 | +adapter_id="${0##*arcconf_}" | 
|  | 55 | + | 
|  | 56 | +ARCCONF=$($arcconf_bin getconfig "$adapter_id") | 
|  | 57 | +ARCCONF_DISKS=$(echo "$ARCCONF" | grep -Pzo 'Device\ #(.|\n)*Service Hours.*[0-9]{1,6}' | tr '\0' '\n') | 
|  | 58 | +ARCCONF_LOGICALDISKS=$(echo "$ARCCONF" | grep -Pzo 'Logical Device number (.|\n)*Parity Initialization Status' | tr '\0' '\n') | 
|  | 59 | +ARCCONF_SMARTSTATS=$($arcconf_bin getsmartstats "$adapter_id") | 
|  | 60 | + | 
|  | 61 | +logicaldisks=$(echo "$ARCCONF_LOGICALDISKS" | grep -oE 'Logical Device number [0-9]+' | sed 's/Logical Device number //g') | 
|  | 62 | +disks=$(echo "$ARCCONF_DISKS" | grep -oE 'Device #[0-9]+' | sed 's/Device #//g') | 
|  | 63 | + | 
|  | 64 | +case $1 in | 
|  | 65 | + | 
|  | 66 | +    autoconf) | 
|  | 67 | +        if [ -x "$arcconf_bin" ]; then | 
|  | 68 | +            if [ -z "$(command -v arcconf)" ]; then | 
|  | 69 | +                echo "no (arcconf not found)" | 
|  | 70 | +                exit 0 | 
|  | 71 | +            else | 
|  | 72 | +                echo "yes" | 
|  | 73 | +                exit 0 | 
|  | 74 | +            fi | 
|  | 75 | +        else | 
|  | 76 | +            echo "no (/usr/local/sbin/arcconf not found)" | 
|  | 77 | +            exit 0 | 
|  | 78 | +        fi | 
|  | 79 | +        ;; | 
|  | 80 | + | 
|  | 81 | +   config) | 
|  | 82 | +        adaptername=$(echo "$ARCCONF" | grep "Controller Model" | cut -d ":" -f 2 | xargs) | 
|  | 83 | + | 
|  | 84 | +        echo "multigraph arcconf_${adapter_id}_logicaldisks" | 
|  | 85 | +        echo "graph_title arcconf_${adapter_id} - Status of logical disks" | 
|  | 86 | +		echo "graph_info arcconf_${adapter_id} - Status of logical disks on $adaptername adapter" | 
|  | 87 | +        echo "graph_args -u 1 -l 0" | 
|  | 88 | +        echo "graph_category disk" | 
|  | 89 | +        echo "graph_vlabel Online status" | 
|  | 90 | +        for logicaldisk in $logicaldisks; do | 
|  | 91 | +        	raid_level=$(echo "$ARCCONF_LOGICALDISKS" | grep 'RAID level' | cut -d ":" -f 2 | xargs) | 
|  | 92 | +			echo "status_logicaldisk_$logicaldisk.label Logical disk $logicaldisk (raid $raid_level) status is optimal" | 
|  | 93 | +			echo "status_logicaldisk_$logicaldisk.info Status of logical disk $logicaldisk (raid $raid_level) is optimal" | 
|  | 94 | +			echo "status_logicaldisk_$logicaldisk.min 0" | 
|  | 95 | +			echo "status_logicaldisk_$logicaldisk.warning 1:" | 
|  | 96 | +		done | 
|  | 97 | +		 | 
|  | 98 | +        echo "multigraph arcconf_${adapter_id}_online_disks" | 
|  | 99 | +        echo "graph_title arcconf_${adapter_id} - Online disks" | 
|  | 100 | +        echo "graph_info arcconf_${adapter_id} - Online disks on $adaptername adapter" | 
|  | 101 | +        echo "graph_args -A -l 0" | 
|  | 102 | +        echo "graph_category disk" | 
|  | 103 | +        echo "graph_vlabel Number of disks" | 
|  | 104 | +        echo "online_disks.label Online disks" | 
|  | 105 | +        echo "online_disks.info Current number of online disks on $adaptername adapter" | 
|  | 106 | +        echo "online_disks.min 0" | 
|  | 107 | +		if [ -n "${min_online_disks}" ]; then | 
|  | 108 | +			echo "online_disks.warning $min_online_disks:" | 
|  | 109 | +		fi | 
|  | 110 | +		 | 
|  | 111 | +        echo "multigraph arcconf_${adapter_id}_temp" | 
|  | 112 | +        echo "graph_title arcconf_${adapter_id} - Temperature of adapter" | 
|  | 113 | +        echo "graph_info arcconf_${adapter_id} - Temperature of $adaptername adapter" | 
|  | 114 | +        echo "graph_args -Y -A -l 0" | 
|  | 115 | +        echo "graph_category disk" | 
|  | 116 | +        echo "graph_vlabel C" | 
|  | 117 | +        echo "adapter_temp.label Adapter temperature" | 
|  | 118 | +        echo "adapter_temp.info Current $adaptername adapter temperature" | 
|  | 119 | +        echo "adapter_temp.min 0" | 
|  | 120 | +		if [ -n "${max_adapter_temp}" ]; then | 
|  | 121 | +			echo "adapter_temp.warning $max_adapter_temp" | 
|  | 122 | +		fi | 
|  | 123 | +		 | 
|  | 124 | +        echo "multigraph arcconf_${adapter_id}_disks_temp" | 
|  | 125 | +        echo "graph_title arcconf_${adapter_id} - Temperature of disks on adapter" | 
|  | 126 | +        echo "graph_info arcconf_${adapter_id} - Temperature of disks on adapter $adaptername" | 
|  | 127 | +        echo "graph_args -Y -A -l 0" | 
|  | 128 | +        echo "graph_category disk" | 
|  | 129 | +        echo "graph_vlabel C" | 
|  | 130 | +        for disk in $disks; do | 
|  | 131 | +			echo "temp_disk_$disk.label Temperature of disk $disk" | 
|  | 132 | +			echo "temp_disk_$disk.info Temperature of disk $disk" | 
|  | 133 | +			echo "temp_disk_$disk.min 0" | 
|  | 134 | +		done | 
|  | 135 | +		 | 
|  | 136 | +        echo "multigraph arcconf_${adapter_id}_disks_usage" | 
|  | 137 | +        echo "graph_title arcconf_${adapter_id} - Remaining usage of disks" | 
|  | 138 | +        echo "graph_info arcconf_${adapter_id} - Remaining usage of disks in percent on adapter $adaptername" | 
|  | 139 | +        echo "graph_args -u 100 -l 0" | 
|  | 140 | +        echo "graph_category disk" | 
|  | 141 | +        echo "graph_vlabel %" | 
|  | 142 | +        for disk in $disks; do | 
|  | 143 | +			echo "remaining_usage_disk_$disk.label Remaining usage on disk $disk" | 
|  | 144 | +			echo "remaining_usage_disk_$disk.info Remaining usage on disk $disk" | 
|  | 145 | +			echo "remaining_usage_disk_$disk.min 0" | 
|  | 146 | +			echo "remaining_usage_disk_$disk.warning 80:" | 
|  | 147 | +		done | 
|  | 148 | +		 | 
|  | 149 | +        for disk in $disks; do | 
|  | 150 | +            echo "multigraph arcconf_${adapter_id}_disk_${disk}" | 
|  | 151 | +            echo "graph_title arcconf_${adapter_id} - Disk $disk" | 
|  | 152 | +			echo "graph_info arcconf_${adapter_id} - Error counters of disk $disk on adapter $adaptername" | 
|  | 153 | +		    echo "graph_args -Y -A -l 0" | 
|  | 154 | +		    echo "graph_category disk" | 
|  | 155 | +		    echo "graph_vlabel Errors" | 
|  | 156 | +		    error_counters=$(echo "$ARCCONF" | sed -n "/Device #$disk/,/Device #/ p" | grep -Pzo 'Aborted(.|\n)*Scsi Bus Faults.*[0-9]{1,6}' | tr '\0' '\n') | 
|  | 157 | +			echo "$error_counters" | while read -r error_counter; do | 
|  | 158 | +				name=$(echo "$error_counter" | sed -n 's/\([[:alpha:] ]*\).*/\1/p' | sed 's/ *$//g') | 
|  | 159 | +				if [ -n "$name" ]; then | 
|  | 160 | +					name=$(clean_fieldname "$name") | 
|  | 161 | +					key="${name}_${disk}" | 
|  | 162 | +					echo "$key.label $name" && echo "$key.info $name" && echo "$key.min 0" | 
|  | 163 | +					# Sparse disks are "not ready", so don't warn | 
|  | 164 | +					echo "$name" | grep -q "Not_Ready_Error" || echo "$key.critical 1"  | 
|  | 165 | +				fi | 
|  | 166 | +			done | 
|  | 167 | +		done | 
|  | 168 | +		 | 
|  | 169 | +		for disk in $disks; do | 
|  | 170 | +			echo "multigraph arcconf_${adapter_id}_smartstats_${disk}" | 
|  | 171 | +			echo "graph_title arcconf_${adapter_id} - S.M.A.R.T values disk $disk" | 
|  | 172 | +			echo "graph_vlabel Attribute S.M.A.R.T value" | 
|  | 173 | +			echo "graph_args -u 100 -l 0" | 
|  | 174 | +			echo "graph_category disk" | 
|  | 175 | +			echo "graph_info This graph shows the value of all S.M.A.R.T attributes of disk $disk." | 
|  | 176 | +			smartstats=$(echo "$ARCCONF_SMARTSTATS" | sed -n "/\<PhysicalDriveSmartStats channel=\"[[:digit:]]\" id=\"$disk\"/,/\/PhysicalDriveSmartStats\>/ p") | 
|  | 177 | +			echo "$smartstats" | while read -r attribute; do | 
|  | 178 | +				name=$(echo "$attribute" | sed -n 's/.*name="\([[:alnum:] ()-/]*\)\".*/\1/p') | 
|  | 179 | +				if [ -n "$name" ]; then | 
|  | 180 | +					name=$(clean_fieldname "$name")  | 
|  | 181 | +					key="${name}_${disk}" | 
|  | 182 | +					echo "$key.label $name" && echo "$key.info $name" && echo "$key.min 0" | 
|  | 183 | +					threshold=$(echo "$attribute" | sed -n 's/.*thresholdValue="\([[:digit:]]*\).*/\1/p') | 
|  | 184 | +					[ "$threshold" ] && echo "$key.critical $threshold:" | 
|  | 185 | +				fi | 
|  | 186 | +			done | 
|  | 187 | +		done | 
|  | 188 | + | 
|  | 189 | +		exit 0 | 
|  | 190 | + | 
|  | 191 | +        ;; | 
|  | 192 | + | 
|  | 193 | +esac | 
|  | 194 | + | 
|  | 195 | +echo "multigraph arcconf_${adapter_id}_logicaldisks" | 
|  | 196 | +for logicaldisk in $logicaldisks; do | 
|  | 197 | +	status=$(echo "$ARCCONF" | sed -n "/Logical Device number $logicaldisk/,/Parity Initialization Status/ p" | grep 'Status of Logical Device' | grep -c 'Optimal') | 
|  | 198 | +	[ "$status" ] || status="U" | 
|  | 199 | +	echo "status_logicaldisk_$logicaldisk.value $status" | 
|  | 200 | +done | 
|  | 201 | + | 
|  | 202 | +echo "multigraph arcconf_${adapter_id}_online_disks" | 
|  | 203 | +online_disks=$(echo "$ARCCONF" | grep -cE 'State.*: Online') | 
|  | 204 | +[ "$online_disks" ] || online_disks="U" | 
|  | 205 | +echo "online_disks.value $online_disks" | 
|  | 206 | + | 
|  | 207 | +echo "multigraph arcconf_${adapter_id}_temp" | 
|  | 208 | +adapter_temp=$(echo "$ARCCONF" | grep -oE "Temperature[\ ]+:\ [0-9]{1,3} C\/" | grep -oE '[0-9]+') | 
|  | 209 | +[ "$adapter_temp" ] || adapter_temp="U" | 
|  | 210 | +echo "adapter_temp.value $adapter_temp" | 
|  | 211 | + | 
|  | 212 | +echo "multigraph arcconf_${adapter_id}_disks_temp" | 
|  | 213 | +for disk in $disks; do | 
|  | 214 | +	disk_temp=$(echo "$ARCCONF" | sed -n "/Device #$disk/,/Device #/ p" | grep 'Current Temperature' | grep -oE '[0-9]+') | 
|  | 215 | +	[ "$disk_temp" ] || disk_temp="U" | 
|  | 216 | +	echo "temp_disk_$disk.value $disk_temp" | 
|  | 217 | +done | 
|  | 218 | + | 
|  | 219 | +echo "multigraph arcconf_${adapter_id}_disks_usage" | 
|  | 220 | +for disk in $disks; do | 
|  | 221 | +	usage=$(echo "$ARCCONF" | sed -n "/Device #$disk/,/Device #/ p" | grep 'Usage Remaining' | grep -oE '[0-9]+') | 
|  | 222 | +	[ "$usage" ] || usage="U" | 
|  | 223 | +	echo "remaining_usage_disk_$disk.value $usage" | 
|  | 224 | +done | 
|  | 225 | + | 
|  | 226 | +for disk in $disks; do | 
|  | 227 | +    echo "multigraph arcconf_${adapter_id}_disk_${disk}" | 
|  | 228 | +	error_counters=$(echo "$ARCCONF" | sed -n "/Device #$disk/,/Device #/ p" | grep -Pzo 'Aborted(.|\n)*Scsi Bus Faults.*[0-9]{1,6}' | tr '\0' '\n') | 
|  | 229 | +	echo "$error_counters" | while read -r error_counter; do | 
|  | 230 | +		name=$(echo "$error_counter" | sed -n 's/\([[:alpha:] ]*\).*/\1/p' | sed 's/ *$//g') | 
|  | 231 | +		if [ -n "$name" ]; then | 
|  | 232 | +			name=$(clean_fieldname "$name") | 
|  | 233 | +			key="${name}_${disk}" | 
|  | 234 | +			value=$(echo "$error_counter" | grep -oE '[0-9]+') | 
|  | 235 | +			[ "$value" ] || value="U" | 
|  | 236 | +			echo "$key.value $value" | 
|  | 237 | +		fi | 
|  | 238 | +	done | 
|  | 239 | +done | 
|  | 240 | + | 
|  | 241 | +for disk in $disks; do | 
|  | 242 | +	echo "multigraph arcconf_${adapter_id}_smartstats_${disk}" | 
|  | 243 | +	smartstats=$(echo "$ARCCONF_SMARTSTATS" | sed -n "/\<PhysicalDriveSmartStats channel=\"[[:digit:]]\" id=\"$disk\"/,/\/PhysicalDriveSmartStats\>/ p") | 
|  | 244 | +	echo "$smartstats" | while read -r attribute; do | 
|  | 245 | +		name=$(echo "$attribute" | sed -n 's/.*name="\([[:alnum:] ()-/]*\)\".*/\1/p') | 
|  | 246 | +		if [ -n "$name" ]; then | 
|  | 247 | +			name=$(clean_fieldname "$name")  | 
|  | 248 | +			key="${name}_${disk}" | 
|  | 249 | +			value=$(echo "$attribute" | sed -n 's/.*normalizedCurrent="\([[:digit:]]*\).*/\1/p') | 
|  | 250 | +			[ "$value" ] || value="U" | 
|  | 251 | +			echo "$key.value $value" | 
|  | 252 | +		fi | 
|  | 253 | +	done | 
|  | 254 | +done | 
|  | 255 | + | 
0 commit comments