root / plugins / disk / smart_raw__ @ c96bafa1
Historique | Voir | Annoter | Télécharger (3,94 ko)
| 1 |
#!/usr/bin/python |
|---|---|
| 2 |
# |
| 3 |
# Copyright (C) 2011 Andreas Thienemann <andreas@bawue.net> |
| 4 |
# |
| 5 |
# This program is free software: you can redistribute it and/or modify |
| 6 |
# it under the terms of the GNU General Public License as published by |
| 7 |
# the Free Software Foundation, either version 3 of the License, or |
| 8 |
# (at your option) any later version. |
| 9 |
# |
| 10 |
# This program is distributed in the hope that it will be useful, |
| 11 |
# but WITHOUT ANY WARRANTY; without even the implied warranty of |
| 12 |
# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the |
| 13 |
# GNU General Public License for more details. |
| 14 |
# |
| 15 |
# You should have received a copy of the GNU General Public License |
| 16 |
# along with this program. If not, see <http://www.gnu.org/licenses/>. |
| 17 |
# |
| 18 |
|
| 19 |
""" |
| 20 |
=head1 NAME |
| 21 |
|
| 22 |
smart_raw__ - Munin plugin to retreive raw SMART values from a disk. |
| 23 |
|
| 24 |
=head1 APPLICABLE SYSTEMS |
| 25 |
|
| 26 |
All machines with a SMART capable disk and smartmontools installed. |
| 27 |
|
| 28 |
This plugin is very useful if you want to need to monitor a single raw S.M.A.R.T. |
| 29 |
value reported by a disk. Load Cycle Counts or Pending Sectors come to mind as |
| 30 |
these are a good indicator of problems with a disk. |
| 31 |
|
| 32 |
=head1 CONFIGURATION |
| 33 |
|
| 34 |
The plugin should be installed as smart_raw_sda_193 which means that the smart value |
| 35 |
numbered 193 will be read from the disk sda. |
| 36 |
|
| 37 |
|
| 38 |
Basic configuration for every system is that the plugin needs to be called as root |
| 39 |
in order to execute smartmontools. |
| 40 |
|
| 41 |
Add the following to your /etc/munin/plugin-conf.d/smart_raw: |
| 42 |
|
| 43 |
[smart_raw_sda_193] |
| 44 |
user root |
| 45 |
|
| 46 |
=head1 INTERPRETATION |
| 47 |
|
| 48 |
Smart RAW values are provided as is. You need to undertand what you are monitoring... |
| 49 |
|
| 50 |
=head1 MAGIC MARKERS |
| 51 |
|
| 52 |
#%# family=contrib |
| 53 |
#%# capabilities= |
| 54 |
|
| 55 |
=head1 VERSION |
| 56 |
|
| 57 |
0.0.1 |
| 58 |
|
| 59 |
=head1 BUGS |
| 60 |
|
| 61 |
None known. |
| 62 |
|
| 63 |
=head1 AUTHOR |
| 64 |
|
| 65 |
Andreas Thienemann <andreas@bawue.net> |
| 66 |
|
| 67 |
=head1 LICENSE |
| 68 |
|
| 69 |
GPLv3+ |
| 70 |
|
| 71 |
=cut |
| 72 |
""" |
| 73 |
|
| 74 |
import subprocess |
| 75 |
import sys |
| 76 |
import os |
| 77 |
import re |
| 78 |
import pprint |
| 79 |
|
| 80 |
# We are a wildcard plugin, figure out what we are being called for |
| 81 |
try: |
| 82 |
disk = sys.argv[0].split('_')[2]
|
| 83 |
value = sys.argv[0].split('_')[3]
|
| 84 |
except IndexError: |
| 85 |
sys.exit(1) |
| 86 |
|
| 87 |
def normalize_name(name): |
| 88 |
name = re.sub("[^a-z0-9A-Z]","_", name)
|
| 89 |
return name |
| 90 |
|
| 91 |
# Code sniplet from Philipp Keller |
| 92 |
# http://code.pui.ch/2007/02/19/set-timeout-for-a-shell-command-in-python/ |
| 93 |
def timeout_command(command, timeout): |
| 94 |
"""call shell-command and either return its output or kill it |
| 95 |
if it doesn't normally exit within timeout seconds and return None""" |
| 96 |
import subprocess, datetime, os, time, signal |
| 97 |
start = datetime.datetime.now() |
| 98 |
process = subprocess.Popen(command.split(), stdout=subprocess.PIPE, stderr=subprocess.PIPE) |
| 99 |
while process.poll() is None: |
| 100 |
time.sleep(0.1) |
| 101 |
now = datetime.datetime.now() |
| 102 |
if (now - start).seconds> timeout: |
| 103 |
os.kill(process.pid, signal.SIGKILL) |
| 104 |
os.waitpid(-1, os.WNOHANG) |
| 105 |
return None |
| 106 |
return process.stdout.read() |
| 107 |
|
| 108 |
def read_smart(): |
| 109 |
"""Read SMART attributes""" |
| 110 |
out = timeout_command("/usr/sbin/smartctl -A -d ata /dev/%s" % (disk), 2)
|
| 111 |
smart_attribs = dict() |
| 112 |
for line in out.split('\n')[7:-2]: # Cut away the header and the footer
|
| 113 |
line = line.split() |
| 114 |
smart_attribs[line[0]] = {
|
| 115 |
'name' : line[1], |
| 116 |
'label' : normalize_name(line[1]), |
| 117 |
'raw' : line [-1], |
| 118 |
} |
| 119 |
return smart_attribs |
| 120 |
|
| 121 |
def print_config(): |
| 122 |
"""Return configuration arguments for munin""" |
| 123 |
attribs = read_smart() |
| 124 |
print "graph_title S.M.A.R.T raw value %s for drive %s" % (attribs[value]['name'], disk) |
| 125 |
print "graph_vlabel Raw value" |
| 126 |
print "graph_info RAW smartctl value" |
| 127 |
print "graph_category disk" |
| 128 |
print "graph_args --base 1000 -l 0" |
| 129 |
|
| 130 |
print "%s.label %s" % (value, attribs[value]['label']) |
| 131 |
sys.exit(0) |
| 132 |
|
| 133 |
def fetch(): |
| 134 |
attribs = read_smart() |
| 135 |
print "%s.value %s" % (value, attribs[value]['raw']) |
| 136 |
sys.exit(0) |
| 137 |
|
| 138 |
if "config" in sys.argv[1:]: |
| 139 |
print_config() |
| 140 |
elif "autoconf" in sys.argv[1:]: |
| 141 |
pass |
| 142 |
elif "suggest" in sys.argv[1:]: |
| 143 |
pass |
| 144 |
else: |
| 145 |
fetch() |
