Projet

Général

Profil

Paste
Télécharger au format
Statistiques
| Branche: | Révision:

root / plugins / postfix / greyfix @ 17f78427

Historique | Voir | Annoter | Télécharger (5,49 ko)

1 682f0f40 Tom Hendrikx
#!/usr/bin/env python
2
#%# family=auto
3
#%# capabilities=autoconf
4
5
"""
6
Munin plugin that monitors the greyfix triplet database.
7
Author: Tom Hendrikx <tom@whyscream.net> 2011-08-05
8
9
This plugin monitors the Greyfix greylisting tool for Postfix.
10
It creates a nice overview of the number of triplets in the greyfix database,
11
dividing the database population in configurable ages.
12
13
For more information about greyfix: http://trac.kim-minh.com/greyfix/
14
15
Installation
16
============
17
18
To install, create a symlink to the plugin in the munin plugin directory:
19
$ ln -s /path/to/plugin/greyfix /etc/munin/plugins/greyfix
20
21
Configuration
22
=============
23
24 17f78427 Lars Kruse
There are some settings that can be tweaked by adding statements to the
25 682f0f40 Tom Hendrikx
munin-node config:
26
27
[greyfix]
28
# run plugin as the same user as postfix does
29
user nobody
30
# path to greyfix binary (default: /usr/sbin/greyfix)
31
env.greyfix /usr/local/sbin/greyfix
32
# the length of each graph step in days (default: 7)
33
env.step_size 3
34
# the number of steps to graph (default: 11)
35
env.num_steps 47
36
# graph the greylisted triplets separate from the whitelisted ones (default: yes)
37
env.greylist_step no
38
39 17f78427 Lars Kruse
Please note that the last step has no end date, so it includes all triplets
40
older than the second last step. I.e., the defaults (as named above) create a
41
graph that shows 10 steps of one week each, and one last step for everything
42
older than 10 weeks. Also, the separate greylist step is not considered
43 682f0f40 Tom Hendrikx
when applying num_steps.
44
45
"""
46
47
# Settings: all of these can be redefined in the munin-node config
48
settings = {
49
	'greyfix': '/usr/sbin/greyfix',
50
	'step_size': 7,
51
	'num_steps': 11,
52
	'greylist_step': 'yes'
53
}
54
55
56
import os
57
import sys
58
import subprocess
59
import datetime
60
61
62
def greyfix_parse_triplets():
63
	"""Parse output of greyfix --dump-triplets into something that we can use.
64
65
	The output of the command has the following columns:
66
	sender_ip, sender_email, recipient_email, timestamp_first_seen, timestamp_last_seen, block_count, pass_count
67
68
	Also see http://groups.google.com/group/greyfix/browse_thread/thread/510687a9ed94fc2c"""
69
70
	greyfix = subprocess.Popen(args=[ settings['greyfix'], '--dump-triplets'], stdout=subprocess.PIPE)
71
	stdout = greyfix.communicate()[0]
72
	if greyfix.returncode > 0:
73
		print '# greyfix exited with exit code %i' % (greyfix.returncode)
74
		sys.exit(greyfix.returncode)
75 17f78427 Lars Kruse
76 682f0f40 Tom Hendrikx
	triplets = []
77
	for line in stdout.split("\n"):
78
		triplet = line.split("\t")
79
		if len(triplet) == 7:
80
			triplet[3] = datetime.datetime.strptime(triplet[3], '%c')
81
			triplet[4] = datetime.datetime.strptime(triplet[4], '%c')
82
			triplet[5] = int(triplet[5])
83
			triplet[6] = int(triplet[6])
84
			triplets.append(triplet)
85
86
	return triplets
87
88
89
def convert_step_to_days(step):
90
	"""Compute the days that are contained in a step, according to the configuration"""
91
92
	start = settings['step_size'] * step
93
	end = (settings['step_size'] * (step + 1)) - 1
94
	if step >= (settings['num_steps'] -1):
95
		return (start, '')
96
	else:
97
		return (start, end)
98
99
100
def print_fetch():
101
	"""Generates and prints the values as retrieved from greyfix."""
102
103
	triplets = greyfix_parse_triplets()
104
	now = datetime.datetime.now()
105
	steps = [0 for i in range(0, settings['num_steps'])]
106
	greylist_step = 0
107
108
	for triplet in triplets:
109
		if settings['greylist_step'] == 'yes' and triplet[6] == 0:
110
			greylist_step = greylist_step +1
111
			continue;
112
113
		delta = now - triplet[3]
114
		step = delta.days / settings['step_size']
115
		step = min(step, settings['num_steps'] -1)
116
		# count the number of triplets in a group
117
		steps[ step ] = steps[ step ] +1
118
119
	# print result counts for each group
120
	if settings['greylist_step'] == 'yes':
121
		print 'gl.value %i' % greylist_step
122
	for step, count in enumerate(steps):
123
		fieldname = 'd%s_%s' % convert_step_to_days(step)
124
		print '%s.value %i' % (fieldname, count)
125
126
127
def print_config():
128
	"""Generates and prints a munin config for a given chart."""
129
130
	print 'graph_title Greyfix triplets by age'
131
	print 'graph_vlabel Number of triplets'
132
	print 'graph_info The amount of triplets in the greyfix database with a certain age'
133 7042351e dipohl
	print 'graph_category mail'
134 682f0f40 Tom Hendrikx
	print 'graph_total All triplets'
135
	print 'graph_args --lower-limit 0 --base 1000'
136
137
	if settings['greylist_step'] == 'yes':
138
		print 'gl.label Greylisted'
139
		print 'gl.info The number of greylisted triplets. These did not have a single pass (yet)'
140
		print 'gl.draw AREASTACK'
141
		print 'gl.colour aaaaaa'
142
143
	steps = range(0, settings['num_steps'])
144
	for step in steps:
145
		days = convert_step_to_days(step)
146
147
		fieldname = 'd%s_%s' % days
148
		label = 'Whitelisted for %s - %s days' % (days[0], days[1] if days[1] != '' else '...')
149
		info = 'The number of whitelisted triplets that is between %s and %s days old' % (days[0], days[1] if days[1] != '' else '...')
150
151
		print '%s.label %s' % (fieldname, label)
152
		print '%s.info %s' % (fieldname, info)
153
		print '%s.draw AREASTACK' % fieldname
154
155
156
if __name__ == '__main__':
157
158
	# read settings from config file / environment
159
	for key in settings.iterkeys():
160
		if key in os.environ:
161
			if os.environ[ key ].isdigit():
162
				settings[ key ] = int(os.environ[ key ])
163
			else:
164
				settings[ key ] = os.environ[ key ]
165
			#print '# setting %s updated to: %s' % (key, settings[ key ])
166
167
	commands = ['fetch', 'autoconf', 'config']
168
	if len(sys.argv) > 1:
169
		command = sys.argv[1]
170
	else:
171
		command = commands[0]
172
173
	if command not in commands:
174
		print '# command %s unknown, choose one of: %s' % (command, commands)
175
		sys.exit(1)
176
177
	if command == 'fetch':
178
		print_fetch()
179
	elif command == 'config':
180
		print_config()
181
	elif command == 'autoconf':
182
		if os.path.exists( settings['greyfix'] ):
183
			print 'yes'
184
		else:
185
			print 'no (binary not found at %s)' % settings['greyfix']