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
#!/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
There are some settings that can be tweaked by adding statements to the
25
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
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
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

    
76
	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
	print 'graph_category mail'
134
	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']