-
Notifications
You must be signed in to change notification settings - Fork 0
/
Copy pathdf-check
executable file
·155 lines (123 loc) · 3.28 KB
/
df-check
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
#!/usr/bin/python3
#
# Sends email about disks getting full. Run nightly.
# Needs no special privileges.
#
# Assumptions: Linux, Python 3, mailx.
#
import sys
import os
import math
import subprocess
def usage():
m = '''Usage: df-check [-n] [-t]'''
print(m)
###############################################################################
class dfcheck_t:
addr = 'name@example.com'
subject = 'DISK FULL ALERT'
filePct = 95
blockPct = 95
passGigs = 100
units = 'bkMGTPEZY'
def __init__(self):
self.header = None
self.msgs = []
self.sendmail = True
self.test = False
un = os.uname()
self.host = un.nodename
def run(self):
try:
overs = self.findOvers()
if self.msgs:
self.notify()
except Exception as ex:
print(ex)
return -1
return 0
def findOvers(self):
for part in self.getParts():
self.checkPart(part)
def notify(self):
msg = 'Host: %s\n\n' % self.host
if self.header:
msg += self.header + '\n'
msg += '\n'.join(self.msgs) + '\n'
if not self.sendmail:
print(msg)
return
subj = self.subject + ' ' + self.host
args = ['/usr/bin/mailx', '-s', subj, self.addr]
res = subprocess.Popen(args,
stdin = subprocess.PIPE,
stdout = subprocess.DEVNULL,
stderr = subprocess.DEVNULL)
res.stdin.write(msg.encode('utf-8'))
res.stdin.close()
res.wait()
def getParts(self):
rv = []
fil = open('/proc/mounts')
for lin in fil:
exp = lin.split()
if exp[0].startswith('/'):
rv.append(exp[1])
fil.close()
return rv
def checkPart(self, pth):
# do not match df output, because ordinary users can't use all 100%
rec = os.statvfs(pth)
bpct = math.ceil(100.0 * (rec.f_blocks - rec.f_bavail) / rec.f_blocks)
fpct = math.ceil(100.0 * (rec.f_files - rec.f_favail) / rec.f_files)
blkPerGig = 1024.0 * 1024.0 * 1024.0 / rec.f_bsize
availGigs = rec.f_bavail / blkPerGig
emit = self.test
if fpct >= self.filePct:
emit = True
elif (bpct >= self.blockPct) and (availGigs < self.passGigs):
emit = True
if emit:
val = self.fmt(rec.f_bavail, rec.f_bsize)
self.header = 'Block Inode BkAvail Mountpoint'
msg = (':%3d%% %3d%% %s %s' %
(bpct, fpct, val, pth))
self.msgs.append(msg)
def fmt(self, blocks, bsize):
bytes = float(blocks) * bsize
cnt = 0
while bytes > 1024.0:
cnt += 1
bytes /= 1024.0
return '%6.1f%c' % (bytes, self.units[cnt])
###############################################################################
def main(args = None):
if args is None:
args = sys.argv[1:]
dfc = dfcheck_t()
try:
while args and args[0].startswith('-'):
arg = args.pop(0)
if arg == '-n':
dfc.sendmail = False
elif arg == '-t':
dfc.test = True
else:
raise RuntimeError('unknown option ' + arg)
if args:
raise RuntimeError('too many arguments')
except Exception as ex:
usage()
print(ex)
return 1
res = dfc.run()
if res < 0:
return 1
return 0
if __name__ == "__main__":
sys.exit(main())
###############################################################################
# Local Variables:
# mode: indented-text
# indent-tabs-mode: nil
# End: