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'] |
