summaryrefslogtreecommitdiffstats
path: root/roles
diff options
context:
space:
mode:
Diffstat (limited to 'roles')
-rw-r--r--roles/IMAP/handlers/main.yml3
-rw-r--r--roles/IMAP/tasks/imap.yml26
-rw-r--r--roles/IMAP/tasks/mda.yml28
-rw-r--r--roles/MSA/handlers/main.yml3
-rw-r--r--roles/MSA/tasks/main.yml38
-rw-r--r--roles/MX/handlers/main.yml3
-rw-r--r--roles/MX/tasks/main.yml29
-rw-r--r--roles/amavis/handlers/main.yml3
-rw-r--r--roles/amavis/tasks/main.yml12
-rw-r--r--roles/common-SQL/handlers/main.yml3
-rw-r--r--roles/common-SQL/tasks/main.yml35
-rw-r--r--roles/common/files/etc/logcheck/ignore.d.server/common-local2
-rwxr-xr-xroles/common/files/usr/local/share/munin/plugins/dovecot_logins119
-rwxr-xr-xroles/common/files/usr/local/share/munin/plugins/dovecot_stats_135
-rwxr-xr-xroles/common/files/usr/local/share/munin/plugins/dovecot_who43
-rwxr-xr-xroles/common/files/usr/local/share/munin/plugins/postfix_mailqueue_57
-rwxr-xr-xroles/common/files/usr/local/share/munin/plugins/postfix_mailvolume262
-rwxr-xr-xroles/common/files/usr/local/share/munin/plugins/postfix_sasl_63
-rwxr-xr-xroles/common/files/usr/local/share/munin/plugins/postfix_stats_113
-rw-r--r--roles/common/handlers/main.yml3
-rw-r--r--roles/common/tasks/main.yml9
-rw-r--r--roles/common/tasks/munin-node.yml207
-rw-r--r--roles/common/templates/etc/iptables/services.j27
-rw-r--r--roles/common/templates/etc/munin/munin-node.conf.j251
-rw-r--r--roles/common/templates/etc/munin/plugin-conf.d/munin-node.j2137
-rw-r--r--roles/common/templates/etc/stunnel/munin-node.conf.j253
-rw-r--r--roles/lists/handlers/main.yml3
-rw-r--r--roles/lists/tasks/mail.yml28
-rw-r--r--roles/munin-master/files/etc/nginx/sites-available/munin31
-rw-r--r--roles/munin-master/files/lib/systemd/system/munin-cgi-graph.service14
-rw-r--r--roles/munin-master/files/lib/systemd/system/munin-cgi-graph.socket11
-rw-r--r--roles/munin-master/files/lib/systemd/system/munin-cgi-html.service14
-rw-r--r--roles/munin-master/files/lib/systemd/system/munin-cgi-html.socket11
-rw-r--r--roles/munin-master/handlers/main.yml24
-rw-r--r--roles/munin-master/tasks/main.yml136
-rw-r--r--roles/munin-master/templates/etc/munin/munin.conf.j2115
-rw-r--r--roles/munin-master/templates/etc/stunnel/munin-master.conf.j262
-rw-r--r--roles/out/handlers/main.yml3
-rw-r--r--roles/out/tasks/main.yml27
39 files changed, 1718 insertions, 5 deletions
diff --git a/roles/IMAP/handlers/main.yml b/roles/IMAP/handlers/main.yml
index 46cf1fb..10a717d 100644
--- a/roles/IMAP/handlers/main.yml
+++ b/roles/IMAP/handlers/main.yml
@@ -26,3 +26,6 @@
mysql_db: name=spamassassin state=import
target=/tmp/spamassassin.sql
encoding=latin1 collation=latin1_unicode_ci
+
+- name: Restart munin-node
+ service: name=munin-node state=restarted
diff --git a/roles/IMAP/tasks/imap.yml b/roles/IMAP/tasks/imap.yml
index e7023e7..0c55535 100644
--- a/roles/IMAP/tasks/imap.yml
+++ b/roles/IMAP/tasks/imap.yml
@@ -142,3 +142,29 @@
when: not (r1.changed or r2.changed or r3.changed)
- meta: flush_handlers
+
+
+- name: Install 'dovecot_stats_' Munin wildcard plugin
+ file: src=/usr/local/share/munin/plugins/dovecot_stats_
+ dest=/etc/munin/plugins/dovecot_stats_fripost.org
+ owner=root group=root
+ state=link force=yes
+ tags:
+ - munin
+ - munin-node
+ notify:
+ - Restart munin-node
+
+- name: Install 'dovecot_logins' and 'dovecot_who' Munin plugin
+ file: src=/usr/local/share/munin/plugins/{{ item }}
+ dest=/etc/munin/plugins/{{ item }}
+ owner=root group=root
+ state=link force=yes
+ with_items:
+ - dovecot_logins
+ - dovecot_who
+ tags:
+ - munin
+ - munin-node
+ notify:
+ - Restart munin-node
diff --git a/roles/IMAP/tasks/mda.yml b/roles/IMAP/tasks/mda.yml
index 04d2b54..ac4b733 100644
--- a/roles/IMAP/tasks/mda.yml
+++ b/roles/IMAP/tasks/mda.yml
@@ -49,3 +49,31 @@
- name: Start Postfix
service: name=postfix state=started
+
+
+- name: Install 'postfix_mailqueue_' Munin wildcard plugin
+ file: src=/usr/local/share/munin/plugins/postfix_mailqueue_
+ dest=/etc/munin/plugins/postfix_mailqueue_postfix-{{ postfix_instance[inst].name }}
+ owner=root group=root
+ state=link force=yes
+ tags:
+ - munin
+ - munin-node
+ notify:
+ - Restart munin-node
+
+- name: Install 'postfix_stats_' Munin wildcard plugin
+ file: src=/usr/local/share/munin/plugins/postfix_stats_
+ dest=/etc/munin/plugins/postfix_stats_{{ item }}_postfix-{{ postfix_instance[inst].name }}
+ owner=root group=root
+ state=link force=yes
+ with_items:
+ - smtpd
+ - qmgr
+ - smtp
+ - lmtp
+ tags:
+ - munin
+ - munin-node
+ notify:
+ - Restart munin-node
diff --git a/roles/MSA/handlers/main.yml b/roles/MSA/handlers/main.yml
index 99a5db2..9edf610 100644
--- a/roles/MSA/handlers/main.yml
+++ b/roles/MSA/handlers/main.yml
@@ -1,3 +1,6 @@
---
- name: Reload Postfix
service: name=postfix state=reloaded
+
+- name: Restart munin-node
+ service: name=munin-node state=restarted
diff --git a/roles/MSA/tasks/main.yml b/roles/MSA/tasks/main.yml
index c7424d8..6b1551f 100644
--- a/roles/MSA/tasks/main.yml
+++ b/roles/MSA/tasks/main.yml
@@ -23,3 +23,41 @@
- name: Start Postfix
service: name=postfix state=started
+
+
+- name: Install 'postfix_mailqueue_' Munin wildcard plugin
+ file: src=/usr/local/share/munin/plugins/postfix_mailqueue_
+ dest=/etc/munin/plugins/postfix_mailqueue_postfix-{{ postfix_instance[inst].name }}
+ owner=root group=root
+ state=link force=yes
+ tags:
+ - munin
+ - munin-node
+ notify:
+ - Restart munin-node
+
+- name: Install 'postfix_stats_' Munin wildcard plugin
+ file: src=/usr/local/share/munin/plugins/postfix_stats_
+ dest=/etc/munin/plugins/postfix_stats_{{ item }}_postfix-{{ postfix_instance[inst].name }}
+ owner=root group=root
+ state=link force=yes
+ with_items:
+ - smtpd
+ - qmgr
+ - smtp
+ tags:
+ - munin
+ - munin-node
+ notify:
+ - Restart munin-node
+
+- name: Install 'postfix_sasl_' Munin wildcard plugin
+ file: src=/usr/local/share/munin/plugins/postfix_sasl_
+ dest=/etc/munin/plugins/postfix_sasl_postfix-{{ postfix_instance[inst].name }}
+ owner=root group=root
+ state=link force=yes
+ tags:
+ - munin
+ - munin-node
+ notify:
+ - Restart munin-node
diff --git a/roles/MX/handlers/main.yml b/roles/MX/handlers/main.yml
index 99a5db2..9edf610 100644
--- a/roles/MX/handlers/main.yml
+++ b/roles/MX/handlers/main.yml
@@ -1,3 +1,6 @@
---
- name: Reload Postfix
service: name=postfix state=reloaded
+
+- name: Restart munin-node
+ service: name=munin-node state=restarted
diff --git a/roles/MX/tasks/main.yml b/roles/MX/tasks/main.yml
index 3c96fad..4302502 100644
--- a/roles/MX/tasks/main.yml
+++ b/roles/MX/tasks/main.yml
@@ -77,3 +77,32 @@
- name: Start Postfix
service: name=postfix state=started
+
+
+- name: Install 'postfix_mailqueue_' Munin wildcard plugin
+ file: src=/usr/local/share/munin/plugins/postfix_mailqueue_
+ dest=/etc/munin/plugins/postfix_mailqueue_postfix-{{ postfix_instance[inst].name }}
+ owner=root group=root
+ state=link force=yes
+ tags:
+ - munin
+ - munin-node
+ notify:
+ - Restart munin-node
+
+- name: Install 'postfix_stats_' Munin wildcard plugin
+ file: src=/usr/local/share/munin/plugins/postfix_stats_
+ dest=/etc/munin/plugins/postfix_stats_{{ item }}_postfix-{{ postfix_instance[inst].name }}
+ owner=root group=root
+ state=link force=yes
+ with_items:
+ - postscreen
+ - smtpd
+ - qmgr
+ - smtp
+ - pipe
+ tags:
+ - munin
+ - munin-node
+ notify:
+ - Restart munin-node
diff --git a/roles/amavis/handlers/main.yml b/roles/amavis/handlers/main.yml
index ab974e6..62cc6fc 100644
--- a/roles/amavis/handlers/main.yml
+++ b/roles/amavis/handlers/main.yml
@@ -8,3 +8,6 @@
- name: Restart Amavis
service: name=amavis state=restarted
+
+- name: Restart munin-node
+ service: name=munin-node state=restarted
diff --git a/roles/amavis/tasks/main.yml b/roles/amavis/tasks/main.yml
index a30772d..4009c05 100644
--- a/roles/amavis/tasks/main.yml
+++ b/roles/amavis/tasks/main.yml
@@ -71,3 +71,15 @@
- name: Start Amavis
service: name=amavis state=started
+
+
+- name: Install 'amavis' Munin plugin
+ file: src=/usr/share/munin/plugins/amavis
+ dest=/etc/munin/plugins/amavis
+ owner=root group=root
+ state=link force=yes
+ tags:
+ - munin
+ - munin-node
+ notify:
+ - Restart munin-node
diff --git a/roles/common-SQL/handlers/main.yml b/roles/common-SQL/handlers/main.yml
index 435c20e..d1d355f 100644
--- a/roles/common-SQL/handlers/main.yml
+++ b/roles/common-SQL/handlers/main.yml
@@ -1,3 +1,6 @@
---
- name: Restart MySQL
service: name=mysql state=restarted
+
+- name: Restart munin-node
+ service: name=munin-node state=restarted
diff --git a/roles/common-SQL/tasks/main.yml b/roles/common-SQL/tasks/main.yml
index b5c6773..9541be8 100644
--- a/roles/common-SQL/tasks/main.yml
+++ b/roles/common-SQL/tasks/main.yml
@@ -10,6 +10,8 @@
- mysql-common
- mysql-server
- python-mysqldb
+ # for the 'mysql_' munin plugin
+ - libcache-cache-perl
- name: Copy MySQL's configuration
copy: src=etc/mysql/my.cnf
@@ -43,3 +45,36 @@
- name: Start MySQL
service: name=mysql state=started
+
+
+- name: Install 'mysql_' Munin wildcard plugin
+ file: src=/usr/share/munin/plugins/mysql_
+ dest=/etc/munin/plugins/mysql_{{ item }}
+ owner=root group=root
+ state=link force=yes
+ with_items:
+ # sudo /usr/share/munin/plugins/mysql_ suggest
+ - bin_relay_log
+ - commands
+ - connections
+ - files_tables
+ - innodb_bpool
+ - innodb_bpool_act
+ - innodb_io
+ - innodb_log
+ - innodb_rows
+ - innodb_semaphores
+ - innodb_tnx
+ - myisam_indexes
+ - qcache
+ - qcache_mem
+ - select_types
+ - slow
+ - sorts
+ - table_locks
+ - tmp_tables
+ tags:
+ - munin
+ - munin-node
+ notify:
+ - Restart munin-node
diff --git a/roles/common/files/etc/logcheck/ignore.d.server/common-local b/roles/common/files/etc/logcheck/ignore.d.server/common-local
index 887688a..67e9335 100644
--- a/roles/common/files/etc/logcheck/ignore.d.server/common-local
+++ b/roles/common/files/etc/logcheck/ignore.d.server/common-local
@@ -31,3 +31,5 @@
^\w{3} [ :[:digit:]]{11} [._[:alnum:]-]+ ansible-([_a-z]+|<stdin>): Invoked with
^\w{3} [ :[:digit:]]{11} [._[:alnum:]-]+ (sympa\((command|distribute)\)|wwsympa|archived|bounced|bulk|task_manager)\[[[:digit:]]+\]: (info|notice)\s
^\w{3} [ :[:digit:]]{11} [._[:alnum:]-]+ wwsympa\[[[:digit:]]+\]: err .* main::check_action_parameters\(\) user not logged in$
+^\w{3} [ :[:digit:]]{11} [._[:alnum:]-]+ rrdcached\[[[:digit:]]+\]: (flushing old values|rotating journals|started new journal /\S+$|removing old journal /\S+$)
+^\w{3} [ :[:digit:]]{11} [._[:alnum:]-]+ rrdcached\[[[:digit:]]+\]: queue_thread_main: rrd_update_r \(([^)]+)\) failed with status -1. \(opening '\1': No such file or directory\)
diff --git a/roles/common/files/usr/local/share/munin/plugins/dovecot_logins b/roles/common/files/usr/local/share/munin/plugins/dovecot_logins
new file mode 100755
index 0000000..09b79d9
--- /dev/null
+++ b/roles/common/files/usr/local/share/munin/plugins/dovecot_logins
@@ -0,0 +1,119 @@
+#!/bin/sh
+
+# Munin plugin for monitoring Dovecot logins and IMAP throughput.
+# Copyright © 2015 Guilhem Moulin <guilhem@fripost.org>
+#
+# This program is free software: you can redistribute it and/or modify
+# it under the terms of the GNU General Public License as published by
+# the Free Software Foundation, either version 3 of the License, or
+# (at your option) any later version.
+#
+# This program is distributed in the hope that it will be useful,
+# but WITHOUT ANY WARRANTY; without even the implied warranty of
+# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+# GNU General Public License for more details.
+#
+# You should have received a copy of the GNU General Public License
+# along with this program. If not, see <http://www.gnu.org/licenses/>.
+
+PATH=/usr/bin:/bin:/usr/sbin:/sbin
+
+LOGFILE="/var/log/${logfile:-mail.log}"
+STATEFILE="$MUNIN_PLUGSTATE/${0##*/}.offset"
+
+. $MUNIN_LIBDIR/plugins/plugin.sh
+is_multigraph
+
+case "${1:-}" in
+ config) cat <<- EOF
+ multigraph dovecot_login_status
+ graph_title Dovecot login status
+ graph_vlabel logins per \${graph_period}
+ graph_args --base 1000 -l 0
+ graph_scale no
+ graph_period minute
+ graph_category dovecot
+ successful.label auth successful
+ successful.type DERIVE
+ successful.draw AREA
+ successful.min 0
+ failed.label auth failed
+ failed.type DERIVE
+ failed.draw STACK
+ failed.min 0
+ noauth.label no auth attempt
+ noauth.type DERIVE
+ noauth.draw STACK
+ noauth.min 0
+
+ multigraph dovecot_login_types
+ graph_title Dovecot login types
+ graph_vlabel logins per \${graph_period}
+ graph_args --base 1000 -l 0
+ graph_scale no
+ graph_period minute
+ graph_category dovecot
+ imap.label IMAP
+ imap.type DERIVE
+ imap.draw AREA
+ imap.min 0
+ pop3.label POP3
+ pop3.type DERIVE
+ pop3.draw STACK
+ pop3.min 0
+ managesieve.label managesieve
+ managesieve.type DERIVE
+ managesieve.draw STACK
+ managesieve.min 0
+
+ multigraph dovecot_imap_throughput
+ graph_title Dovecot IMAP throughput
+ graph_vlabel bytes per \${graph_period}
+ graph_args --base 1024 -l 0
+ graph_scale yes
+ graph_period minute
+ graph_category dovecot
+ read.label read
+ read.type DERIVE
+ read.min 0
+ written.label written
+ written.type DERIVE
+ written.min 0
+ EOF
+ exit 0
+ ;;
+esac
+
+if [ ! -f "$LOGFILE" ]; then
+ for field in successful failed noauth imap pop3 managesieve read written; do
+ echo $field.value U
+ done
+ exit 0;
+fi
+
+tmpfile="$(mktemp --tmpdir)"
+trap 'rm -f "$tmpfile"' EXIT
+
+logtail -f"$LOGFILE" -o"$STATEFILE" | sed -nr "s#^\w{3} [ :[:digit:]]{11} [._[:alnum:]-]+ dovecot: ##p" >"$tmpfile"
+
+sum() {
+ awk 'BEGIN{x=0} {x+=$0} END{print x}'
+}
+
+prefix="^(pop3|imap|managesieve)-login"
+echo multigraph dovecot_login_status
+echo successful.value $(grep -Ec "$prefix: Login: user=<[^>]+>,\s" "$tmpfile")
+echo failed.value $(sed -nr "s#$prefix: Aborted login \(auth failed, ([[:digit:]]+) attempts in [[:digit:]]+ secs\): user=<[^>]*>, .*#\2#p" "$tmpfile" | sum)
+echo noauth.value $(grep -Ec "$prefix: Aborted login \(no auth attempts in [[:digit:]]+ secs\): user=<>,\s" "$tmpfile")
+
+
+echo multigraph dovecot_login_types
+for type in imap pop3 managesieve; do
+ echo $type.value $(grep -Ec "^$type-login:\s" "$tmpfile")
+done
+
+
+regexp="^imap\([-_.@[:alnum:]]+\): .* in=([[:digit:]]+) out=([[:digit:]]+)$"
+echo multigraph dovecot_imap_throughput
+echo read.value $(sed -nr "s#$regexp#\1#p" "$tmpfile" | sum)
+echo written.value $(sed -nr "s#$regexp#\2#p" "$tmpfile" | sum)
diff --git a/roles/common/files/usr/local/share/munin/plugins/dovecot_stats_ b/roles/common/files/usr/local/share/munin/plugins/dovecot_stats_
new file mode 100755
index 0000000..7f0f51a
--- /dev/null
+++ b/roles/common/files/usr/local/share/munin/plugins/dovecot_stats_
@@ -0,0 +1,135 @@
+#!/bin/bash
+: <<=cut
+
+=head1 NAME
+
+dovecot_stats_ - Munin plugin to display statistics for the dovecot mail server
+
+=head1 CONFIGURATION
+
+This plugin must be run with permissions to run "doveadm". That usually means root, but to test, run the following as any user:
+
+ doveadm who
+
+If you get a permission denied message, check the permissions on the socket mentioned in the error line.
+
+=head1 MAGIC MARKERS
+
+ #%# family=contrib
+ #%# capability=autoconf suggest
+
+=head1 AUTHOR
+
+Paul Saunders <darac+munin@darac.org.uk>
+
+=cut
+
+. $MUNIN_LIBDIR/plugins/plugin.sh
+is_multigraph
+
+if [[ "$1" == "autoconf" ]]; then
+ if [[ -x /usr/bin/doveadm ]]; then
+ echo yes
+ else
+ echo no
+ fi
+ exit 0
+fi
+
+if [[ "$1" == "suggest" ]]; then
+ doveadm stats dump domain|awk 'NR!=1 {print $1}'
+ exit 0
+fi
+
+domain=$(basename $0)
+domain=${domain#dovecot_stats_}
+
+if [[ -z $domain ]]; then
+ exit 1
+fi
+
+if [[ "$1" == "config" ]]; then
+ cat <<EOF
+multigraph dovecot_cpu_${domain//\./_}
+graph_title Dovecot CPU Usage for $domain
+graph_vlabel Seconds
+graph_category dovecot
+user_cpu.label User CPU
+user_cpu.type DERIVE
+user_cpu.min 0
+user_cpu.cdef user_cpu,1000000,/
+sys_cpu.label System CPU
+sys_cpu.type DERIVE
+sys_cpu.min 0
+sys_cpu.cdef sys_cpu,1000000,/
+
+multigraph dovecot_system_${domain//\./_}
+graph_title Dovecot System Usage for $domain
+graph_category dovecot
+min_faults.label Minor page faults
+min_faults.type DERIVE
+min_faults.min 0
+maj_faults.label Major page faults
+maj_faults.type DERIVE
+maj_faults.min 0
+vol_cs.label Voluntary context switches
+vol_cs.type DERIVE
+vol_cs.min 0
+invol_cs.label Involuntary context switches
+invol_cs.type DERIVE
+invol_cs.min 0
+read_count.label read() syscalls
+read_count.type DERIVE
+read_count.min 0
+write_count.label write() syscalls
+write_count.type DERIVE
+write_count.min 0
+
+multigraph dovecot_mail_${domain//\./_}
+graph_title Dovecot Mail Access for $domain
+graph_category dovecot
+num_logins.label Logins
+num_logins.type DERIVE
+num_logins.min 0
+num_cmds.label Commands
+num_cmds.type DERIVE
+num_cmds.min 0
+mail_lookup_path.label Path Lookups
+mail_lookup_path.type DERIVE
+mail_lookup_path.min 0
+mail_lookup_attr.label Attr lookups
+mail_lookup_attr.type DERIVE
+mail_lookup_attr.min 0
+mail_read_count.label Messages read
+mail_read_count.type DERIVE
+mail_read_count.min 0
+mail_cache_hits.label Cache hits
+mail_cache_hits.type DERIVE
+mail_cache_hits.min 0
+EOF
+ exit 0
+fi
+
+# Fetch data
+# Gawk script cadged from http://awk.info/?JanisP
+doveadm stats dump domain domain=$domain | gawk -F\\t -v cols="user_cpu sys_cpu min_faults maj_faults vol_cs invol_cs read_count write_count num_logins num_cmds mail_lookup_path mail_lookup_attr mail_read_count mail_cache_hits " -v domain=${domain//\./_} '
+ BEGIN {
+ n=split(cols,col," ")
+ for (i=1; i<=n; i++) s[col[i]]=i
+ }
+ NR==1 {
+ for (f=1;f<=NF; f++)
+ if ($f in s) c[s[$f]]=f
+ next
+ }
+ { for (f=1; f<=n; f++) {
+ if (col[f] == "user_cpu") printf ("\nmultigraph dovecot_cpu_%s\n", domain)
+ if (col[f] == "min_faults") printf ("\nmultigraph dovecot_system_%s\n", domain)
+ if (col[f] == "num_logins") printf ("\nmultigraph dovecot_mail_%s\n", domain)
+ if (col[f] == "user_cpu" || col[f] == "sys_cpu")
+ printf("%s.value %d\n",col[f],$c[f] * 1000000)
+ else
+ printf("%s.value %d\n",col[f],$c[f])
+ }
+ }
+'
diff --git a/roles/common/files/usr/local/share/munin/plugins/dovecot_who b/roles/common/files/usr/local/share/munin/plugins/dovecot_who
new file mode 100755
index 0000000..fe3c743
--- /dev/null
+++ b/roles/common/files/usr/local/share/munin/plugins/dovecot_who
@@ -0,0 +1,43 @@
+#!/bin/sh
+
+# Munin plugin for monitoring Dovecot IMAP connections and unique users.
+# Copyright © 2015 Guilhem Moulin <guilhem@fripost.org>
+#
+# This program is free software: you can redistribute it and/or modify
+# it under the terms of the GNU General Public License as published by
+# the Free Software Foundation, either version 3 of the License, or
+# (at your option) any later version.
+#
+# This program is distributed in the hope that it will be useful,
+# but WITHOUT ANY WARRANTY; without even the implied warranty of
+# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+# GNU General Public License for more details.
+#
+# You should have received a copy of the GNU General Public License
+# along with this program. If not, see <http://www.gnu.org/licenses/>.
+
+PATH=/usr/bin:/bin:/usr/sbin:/sbin
+set -u
+
+case "${1:-}" in
+ config) cat <<- EOF
+ graph_title Dovecot concurrent IMAP usage
+ graph_args --base 1000 -l 0
+ graph_scale no
+ graph_category dovecot
+ connections.label connections
+ connections.min 0
+ users.label unique users
+ users.min 0
+ EOF
+ exit 0
+ ;;
+esac
+
+tmpfile="$(mktemp --tmpdir)"
+trap 'rm -f "$tmpfile"' EXIT
+
+doveadm -f flow who -1 | sed -nr 's/^username=(\S+)\s+proto=imap\s.*/\1/p' >"$tmpfile"
+
+echo connections.value $(wc -l <"$tmpfile")
+echo users.value $(sort -u "$tmpfile" | wc -l)
diff --git a/roles/common/files/usr/local/share/munin/plugins/postfix_mailqueue_ b/roles/common/files/usr/local/share/munin/plugins/postfix_mailqueue_
new file mode 100755
index 0000000..31b6269
--- /dev/null
+++ b/roles/common/files/usr/local/share/munin/plugins/postfix_mailqueue_
@@ -0,0 +1,57 @@
+#!/bin/sh
+
+# Munin plugin for monitoring the Postfix mail queue in multi-instance
+# systems. Symlink/rename to 'postfix_mailqueue_$SPOOLDIR'.
+# Copyright © 2015 Guilhem Moulin <guilhem@fripost.org>
+#
+# This program is free software: you can redistribute it and/or modify
+# it under the terms of the GNU General Public License as published by
+# the Free Software Foundation, either version 3 of the License, or
+# (at your option) any later version.
+#
+# This program is distributed in the hope that it will be useful,
+# but WITHOUT ANY WARRANTY; without even the implied warranty of
+# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+# GNU General Public License for more details.
+#
+# You should have received a copy of the GNU General Public License
+# along with this program. If not, see <http://www.gnu.org/licenses/>.
+
+PATH=/usr/bin:/bin:/usr/sbin:/sbin
+
+name="${0##*/}"
+[ "${name#postfix_mailqueue_}" != "$name" ] && postfix="${name#postfix_mailqueue_}" || postfix=
+SPOOLDIR="/var/spool/${postfix:-postfix}"
+
+. $MUNIN_LIBDIR/plugins/plugin.sh
+
+case "${1:-}" in
+ config) cat <<- EOF
+ graph_title Postfix mailqueue ($([ -n "$postfix" -a "$postfix" != postfix ] && echo "'${postfix#postfix-}'" || echo default) instance)
+ graph_vlabel Mails in queue
+ graph_args --base 1000 -l 0
+ graph_scale no
+ graph_category postfix
+ graph_total Total
+ active.label active
+ deferred.label deferred
+ maildrop.label maildrop
+ incoming.label incoming
+ corrupt.label corrupt
+ hold.label held
+ EOF
+ for field in active deferred maildrop incoming corrupt hold; do
+ print_warning "$field"
+ print_critical "$field"
+ done
+ exit 0
+ ;;
+esac
+
+for field in active deferred maildrop incoming corrupt hold; do
+ if [ -d "$SPOOLDIR/$field" ]; then
+ echo $field.value $(find "$SPOOLDIR/$field" -type f | wc -l)
+ else
+ echo $field.value U
+ fi
+done
diff --git a/roles/common/files/usr/local/share/munin/plugins/postfix_mailvolume2 b/roles/common/files/usr/local/share/munin/plugins/postfix_mailvolume2
new file mode 100755
index 0000000..d16d88e
--- /dev/null
+++ b/roles/common/files/usr/local/share/munin/plugins/postfix_mailvolume2
@@ -0,0 +1,62 @@
+#!/bin/sh
+
+# Munin plugin for monitoring Postfix per-instance mail throughput.
+# Copyright © 2015 Guilhem Moulin <guilhem@fripost.org>
+#
+# This program is free software: you can redistribute it and/or modify
+# it under the terms of the GNU General Public License as published by
+# the Free Software Foundation, either version 3 of the License, or
+# (at your option) any later version.
+#
+# This program is distributed in the hope that it will be useful,
+# but WITHOUT ANY WARRANTY; without even the implied warranty of
+# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+# GNU General Public License for more details.
+#
+# You should have received a copy of the GNU General Public License
+# along with this program. If not, see <http://www.gnu.org/licenses/>.
+
+PATH=/usr/bin:/bin:/usr/sbin:/sbin
+set -u
+
+LOGFILE="/var/log/${logfile:-mail.log}"
+STATEFILE="$MUNIN_PLUGSTATE/${0##*/}.offset"
+
+case "${1:-}" in
+ config) cat <<- EOF
+ graph_title Postfix per-instance bytes throughput
+ graph_vlabel bytes per \${graph_period}
+ graph_args --base 1024 -l 0
+ graph_scale yes
+ graph_period minute
+ graph_category postfix
+ EOF
+ if [ $(echo "${postmulti:-postfix}" | wc -w) -gt 1 ]; then
+ echo graph_total total throughput
+ fi
+ for postfix in ${postmulti:-postfix}; do
+ echo "${postfix}_volume.label" "$postfix throughput"
+ echo "${postfix}_volume.type" DERIVE
+ echo "${postfix}_volume.min" 0
+ done
+ exit 0
+ ;;
+esac
+
+if [ ! -f "$LOGFILE" ]; then
+ for postfix in ${postmulti:-postfix}; do
+ echo "${postfix}_volume.value U"
+ done
+ exit 0;
+fi
+
+tmpfile="$(mktemp --tmpdir)"
+trap 'rm -f "$tmpfile"' EXIT
+
+logtail -f"$LOGFILE" -o"$STATEFILE" >"$tmpfile"
+
+for postfix in ${postmulti:-postfix}; do
+ echo -n "${postfix}_volume.value "
+ sed -nr "s#^\w{3} [ :[:digit:]]{11} [._[:alnum:]-]+ $postfix/qmgr\[[[:digit:]]+\]: [[:xdigit:]]+: from=<[^>]*>, size=([[:digit:]]+), nrcpt=[[:digit:]]+ \(queue active\)\$#\1#p" "$tmpfile" \
+ | awk 'BEGIN{x=0} {x+=$0} END{print x}'
+done
diff --git a/roles/common/files/usr/local/share/munin/plugins/postfix_sasl_ b/roles/common/files/usr/local/share/munin/plugins/postfix_sasl_
new file mode 100755
index 0000000..8dc1219
--- /dev/null
+++ b/roles/common/files/usr/local/share/munin/plugins/postfix_sasl_
@@ -0,0 +1,63 @@
+#!/bin/sh
+
+# Munin plugin for monitoring Postfix SASL logins. Symlink/rename to
+# 'postfix_sasl_$SYSLOGNAME'.
+# Copyright © 2015 Guilhem Moulin <guilhem@fripost.org>
+#
+# This program is free software: you can redistribute it and/or modify
+# it under the terms of the GNU General Public License as published by
+# the Free Software Foundation, either version 3 of the License, or
+# (at your option) any later version.
+#
+# This program is distributed in the hope that it will be useful,
+# but WITHOUT ANY WARRANTY; without even the implied warranty of
+# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+# GNU General Public License for more details.
+#
+# You should have received a copy of the GNU General Public License
+# along with this program. If not, see <http://www.gnu.org/licenses/>.
+
+PATH=/usr/bin:/bin:/usr/sbin:/sbin
+set -u
+
+LOGFILE="/var/log/${logfile:-mail.log}"
+STATEFILE="$MUNIN_PLUGSTATE/${0##*/}.offset"
+
+name="${0##*/}"
+[ "${name#postfix_sasl_}" != "$name" ] && postfix="${name#postfix_sasl_}" || postfix=
+
+case "${1:-}" in
+ config) cat <<- EOF
+ graph_title Postfix SASL ($([ -n "$postfix" -a "$postfix" != postfix ] && echo "'${postfix#postfix-}'" || echo default) instance)
+ graph_vlabel logins per \${graph_period}
+ graph_args --base 1000 -l 0
+ graph_scale no
+ graph_period minute
+ graph_category postfix
+ successful.label successful
+ successful.type DERIVE
+ successful.draw AREA
+ successful.min 0
+ failed.label failed
+ failed.type DERIVE
+ failed.draw STACK
+ failed.min 0
+ EOF
+ exit 0
+ ;;
+esac
+
+if [ ! -f "$LOGFILE" ]; then
+ for postfix in ${postmulti:-postfix}; do
+ echo "${postfix}_volume.value U"
+ done
+ exit 0;
+fi
+
+tmpfile="$(mktemp --tmpdir)"
+trap 'rm -f "$tmpfile"' EXIT
+
+logtail -f"$LOGFILE" -o"$STATEFILE" | sed -nr "s#^\w{3} [ :[:digit:]]{11} [._[:alnum:]-]+ $postfix/smtpd\[[[:digit:]]+\]: ##p" >"$tmpfile"
+
+echo successful.value $(grep -Ec "^warning: [-._[:alnum:]]+\[[.[:digit:]]+\]: SASL \S+ authentication failed(:.*)?$" "$tmpfile")
+echo failed.value $(grep -Ec "^[[:xdigit:]]{10}: client=\S+, sasl_method=\S+, sasl_username=" "$tmpfile")
diff --git a/roles/common/files/usr/local/share/munin/plugins/postfix_stats_ b/roles/common/files/usr/local/share/munin/plugins/postfix_stats_
new file mode 100755
index 0000000..5678870
--- /dev/null
+++ b/roles/common/files/usr/local/share/munin/plugins/postfix_stats_
@@ -0,0 +1,113 @@
+#!/bin/sh
+
+# Munin plugin for monitoring Postfix per-service and per-instance
+# usage. Symlink/rename to 'postfix_sasl_$SERVICE_$SYSLOGNAME'.
+# Copyright © 2015 Guilhem Moulin <guilhem@fripost.org>
+#
+# This program is free software: you can redistribute it and/or modify
+# it under the terms of the GNU General Public License as published by
+# the Free Software Foundation, either version 3 of the License, or
+# (at your option) any later version.
+#
+# This program is distributed in the hope that it will be useful,
+# but WITHOUT ANY WARRANTY; without even the implied warranty of
+# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+# GNU General Public License for more details.
+#
+# You should have received a copy of the GNU General Public License
+# along with this program. If not, see <http://www.gnu.org/licenses/>.
+
+PATH=/usr/bin:/bin:/usr/sbin:/sbin
+set -u
+
+LOGFILE="/var/log/${logfile:-mail.log}"
+STATEFILE="$MUNIN_PLUGSTATE/${0##*/}.offset"
+
+name="${0##*/}"
+name="${name#postfix_stats_}"
+
+if [ "${name#postscreen_}" != "$name" ]; then
+ postfix="${name#postscreen_}"
+ service=postscreen
+ fields='connected accepted passed'
+elif [ "${name#smtpd_}" != "$name" ]; then
+ postfix="${name#smtpd_}"
+ service=smtpd
+ fields='connected accepted queued'
+elif [ "${name#qmgr_}" != "$name" ]; then
+ postfix="${name#qmgr_}"
+ service=qmgr
+ fields='queued'
+elif [ "${name#smtp_}" != "$name" ]; then
+ postfix="${name#smtp_}"
+ service=smtp
+ fields='sent deliverable deferred undeliverable bounced'
+elif [ "${name#lmtp_}" != "$name" ]; then
+ postfix="${name#lmtp_}"
+ service=lmtp
+ fields='sent deliverable deferred undeliverable bounced'
+elif [ "${name#pipe_}" != "$name" ]; then
+ postfix="${name#pipe_}"
+ service=pipe
+ fields='sent deliverable deferred undeliverable bounced'
+fi
+
+case "${1:-}" in
+ config) cat <<- EOF
+ graph_title Postfix $service message throughput ($([ -n "$postfix" -a "$postfix" != postfix ] && echo "'${postfix#postfix-}'" || echo default) instance)
+ graph_vlabel mails per \${graph_period}
+ graph_args --base 1000 -l 0
+ graph_scale no
+ graph_period minute
+ graph_category postfix
+ EOF
+ for field in $fields; do
+ echo "$field.label $field"
+ echo "$field.type DERIVE"
+ echo "$field.draw AREA"
+ echo "$field.min 0"
+ done
+ exit 0
+ ;;
+esac
+
+if [ ! -f "$LOGFILE" ]; then
+ for field in $fields; do
+ echo "$field.value U"
+ done
+ exit 0;
+fi
+
+tmpfile="$(mktemp --tmpdir)"
+trap 'rm -f "$tmpfile"' EXIT
+
+logtail -f"$LOGFILE" -o"$STATEFILE" | sed -nr "s#^\w{3} [ :[:digit:]]{11} [._[:alnum:]-]+ $postfix/$service\[[[:digit:]]+\]: ##p" >"$tmpfile"
+
+case "$service" in
+ postscreen)
+ connected=$(grep -Ec "^CONNECT from\s" "$tmpfile")
+ rejected=$( grep -Ec "^NOQUEUE: reject:\s" "$tmpfile")
+ passed=$( grep -Ec "^(PASS (OLD|NEW)|WHITELISTED)\s" "$tmpfile")
+ echo connected.value $connected
+ echo accepted.value $(($rejected + $passed))
+ echo passed.value $passed
+ ;;
+ smtpd)
+ connected=$(grep -Ec "^connect from\s" "$tmpfile")
+ rejected=$( grep -Ec "^NOQUEUE: reject:\s" "$tmpfile")
+ queued=$( grep -Ec "^[[:xdigit:]]+: client=" "$tmpfile")
+ echo connected.value $connected
+ echo accepted.value $(($rejected + $queued))
+ echo queued.value $queued
+ ;;
+ qmgr)
+ queued=$(grep -Ec "^[[:xdigit:]]+: from=<\S+>, .*\(queue active\)$" "$tmpfile")
+ echo queued.value $queued
+ ;;
+ smtp|lmtp|pipe)
+ for field in $fields; do
+ v=$(grep -Ec "^[[:xdigit:]]+:( [^ =]+=\S+,)+ status=$field(\s.*)?$" "$tmpfile")
+ echo $field.value $v
+ done
+ ;;
+esac
diff --git a/roles/common/handlers/main.yml b/roles/common/handlers/main.yml
index b7ecaab..3dbbf90 100644
--- a/roles/common/handlers/main.yml
+++ b/roles/common/handlers/main.yml
@@ -46,3 +46,6 @@
- name: Update certificate
command: update-ca-certificates
+
+- name: Restart munin-node
+ service: name=munin-node state=restarted
diff --git a/roles/common/tasks/main.yml b/roles/common/tasks/main.yml
index 477bd34..df609d3 100644
--- a/roles/common/tasks/main.yml
+++ b/roles/common/tasks/main.yml
@@ -27,10 +27,11 @@
- name: Generate DH parameters
command: gendhparam.sh /etc/ssl/private/dhparams.pem creates=/etc/ssl/private/dhparams.pem
tags: genkey
-- include: logging.yml tags=logging
-- include: ntp.yml tags=ntp
-- include: mail.yml tags=mail,postfix
-- include: bacula.yml tags=bacula-fd,bacula
+- include: logging.yml tags=logging
+- include: ntp.yml tags=ntp
+- include: mail.yml tags=mail,postfix
+- include: bacula.yml tags=bacula-fd,bacula
+- include: munin-node.yml tags=munin-node,munin
- name: Install common packages
apt: pkg={{ item }}
diff --git a/roles/common/tasks/munin-node.yml b/roles/common/tasks/munin-node.yml
new file mode 100644
index 0000000..9e5d8f4
--- /dev/null
+++ b/roles/common/tasks/munin-node.yml
@@ -0,0 +1,207 @@
+- name: Install munin-node
+ apt: pkg={{ item }}
+ with_items:
+ - munin-node
+ - munin-plugins-extra
+ ###
+ - acpi
+ - lm-sensors
+ - ethtool
+ - hdparm
+ - libwww-perl
+ - libxml-simple-perl
+ - logtail
+
+- name: Create directory /usr/local/share/munin/plugins
+ file: path=/usr/local/share/munin/plugins
+ state=directory
+ owner=root group=root
+ mode=0755
+
+- name: Copy our own Munin plugins
+ copy: src={{ item }}
+ dest=/usr/local/share/munin/plugins/
+ owner=root group=root
+ mode=0755
+ with_fileglob:
+ - usr/local/share/munin/plugins/*
+
+- name: Configure munin-node
+ template: src=etc/munin/{{ item }}.j2
+ dest=/etc/munin/{{ item }}
+ owner=root group=root
+ mode=0644
+ register: r1
+ with_items:
+ - munin-node.conf
+ - plugin-conf.d/munin-node
+ notify:
+ - Restart munin-node
+
+- name: Install Munin plugins
+ file: src=/usr/share/munin/plugins/{{ item }}
+ dest=/etc/munin/plugins/{{ item }}
+ owner=root group=root
+ state=link force=yes
+ register: r2
+ with_items:
+ - cpu
+ - df
+ - df_inode
+ - diskstats
+ - entropy
+ - fail2ban
+ - forks
+ - fw_conntrack
+ - fw_forwarded_local
+ - fw_packets
+ - hddtemp_smartctl
+ - interrupts
+ - irqstats
+ - load
+ - memory
+ - netstat
+ - ntp_kernel_err
+ - ntp_kernel_pll_freq
+ - ntp_kernel_pll_off
+ - ntp_offset
+ - open_files
+ - open_inodes
+ - processes
+ - proc_pri
+ - swap
+ - threads
+ - uptime
+ - users
+ - vmstat
+ notify:
+ - Restart munin-node
+
+- name: Delete Munin plugins
+ file: path=/etc/munin/plugins/{{ item }}
+ state=absent
+ register: r3
+ with_items:
+ - http_loadtime
+ - ip_255.255.255.255
+ - postfix_mailqueue
+ - postfix_mailvolume
+ notify:
+ - Restart munin-node
+
+- name: Install 'if_' Munin wildcard plugin
+ file: src=/usr/share/munin/plugins/{{ item.0 }}_
+ dest=/etc/munin/plugins/{{ item.0 }}_{{ item.1 }}
+ owner=root group=root
+ state=link force=yes
+ register: r4
+ with_nested:
+ - [ if, if_err ]
+ - [ lo, "{{ ansible_default_ipv4.interface }}" ]
+ notify:
+ - Restart munin-node
+
+- name: Install 'postfix_mailvolume2' Munin plugin
+ file: src=/usr/local/share/munin/plugins/postfix_mailvolume2
+ dest=/etc/munin/plugins/postfix_mailvolume2
+ owner=root group=root
+ state=link force=yes
+ register: r5
+ notify:
+ - Restart munin-node
+
+- name: Install 'postfix_mailqueue_' Munin wildcard plugin
+ file: src=/usr/local/share/munin/plugins/postfix_mailqueue_
+ dest=/etc/munin/plugins/postfix_mailqueue_postfix
+ owner=root group=root
+ state=link force=yes
+ register: r6
+ notify:
+ - Restart munin-node
+
+- name: Install 'postfix_stats_' Munin wildcard plugin
+ file: src=/usr/local/share/munin/plugins/postfix_stats_
+ dest=/etc/munin/plugins/postfix_stats_{{ item }}_postfix
+ owner=root group=root
+ state=link force=yes
+ register: r7
+ with_items:
+ - smtpd
+ - qmgr
+ - smtp
+ notify:
+ - Restart munin-node
+
+- name: Start munin-node
+ service: name=munin-node state=started
+ when: not (r1.changed or r2.changed or r3.changed or r4.changed or r5.changed or r6.changed or r7.changed)
+
+- meta: flush_handlers
+
+
+
+- name: Install stunnel
+ apt: pkg=stunnel4
+
+- name: Auto-enable stunnel
+ lineinfile: dest=/etc/default/stunnel4
+ regexp='^(\s*#)?\s*ENABLED='
+ line='ENABLED=1'
+ owner=root group=root
+ mode=0644
+
+- name: Create /etc/stunnel/certs
+ file: path=/etc/stunnel/certs
+ state=directory
+ owner=root group=root
+ mode=0755
+
+- name: Generate a private key and a X.509 certificate for munin-node
+ command: genkeypair.sh x509
+ --pubkey=/etc/stunnel/certs/munin-{{ inventory_hostname_short }}.pem
+ --privkey=/etc/stunnel/certs/munin-{{ inventory_hostname_short }}.key
+ --ou=Munin --cn={{ inventory_hostname }} --dns={{ inventory_hostname }}
+ -t rsa -b 4096 -h sha512
+ register: r1
+ changed_when: r1.rc == 0
+ failed_when: r1.rc > 1
+ notify:
+ - Restart stunnel
+ tags:
+ - genkey
+
+- name: Fetch Munin X.509 certificate
+ # Ensure we don't fetch private data
+ sudo: False
+ fetch: src=/etc/stunnel/certs/munin-{{ inventory_hostname_short }}.pem
+ dest=certs/munin/{{ inventory_hostname }}.pem
+ fail_on_missing=yes
+ flat=yes
+ tags:
+ - genkey
+
+- name: Copy munin-master X.509 certificates
+ assemble: src=certs/munin regexp="{{ groups['munin-master'] | join('|') }}\.pem$" remote_src=no
+ dest=/etc/stunnel/certs/munin-master.pem
+ owner=root group=root
+ mode=0644
+ register: r2
+ when: "'munin-master' not in group_names"
+ notify:
+ - Restart stunnel
+
+- name: Configure stunnel
+ template: src=etc/stunnel/munin-node.conf.j2
+ dest=/etc/stunnel/munin-node.conf
+ owner=root group=root
+ mode=0644
+ register: r3
+ when: "'munin-master' not in group_names"
+ notify:
+ - Restart stunnel
+
+- name: Start stunnel
+ service: name=stunnel4 pattern=/usr/bin/stunnel4 state=started
+ when: not (r1.changed or r2.changed or r3.changed)
+
+- meta: flush_handlers
diff --git a/roles/common/templates/etc/iptables/services.j2 b/roles/common/templates/etc/iptables/services.j2
index a0bb714..8792771 100644
--- a/roles/common/templates/etc/iptables/services.j2
+++ b/roles/common/templates/etc/iptables/services.j2
@@ -69,7 +69,12 @@ in tcp 9103 # BACULA-SD
{% elif groups['bacula-sd'] | difference([inventory_hostname]) %}
out tcp 9103 # BACULA-SD
{% endif %}
-
+{% if 'munin-master' in group_names and groups.all | difference([inventory_hostname]) %}
+out tcp 4949 # MUNIN
+{% endif %}
+{% if groups['munin-master'] | difference([inventory_hostname]) %}
+in tcp 4949 # MUNIN
+{% endif %}
{% if 'LDAP-provider' in group_names %}
out tcp 11371 # HKP
out tcp 43 # WHOIS
diff --git a/roles/common/templates/etc/munin/munin-node.conf.j2 b/roles/common/templates/etc/munin/munin-node.conf.j2
new file mode 100644
index 0000000..de4098a
--- /dev/null
+++ b/roles/common/templates/etc/munin/munin-node.conf.j2
@@ -0,0 +1,51 @@
+#
+# Example config-file for munin-node
+#
+
+log_level 4
+log_file /var/log/munin/munin-node.log
+pid_file /var/run/munin/munin-node.pid
+
+background 1
+setsid 1
+
+user root
+group root
+
+# This is the timeout for the whole transaction.
+# Units are in sec. Default is 15 min
+#
+# global_timeout 900
+
+# This is the timeout for each plugin.
+# Units are in sec. Default is 1 min
+#
+# timeout 60
+
+# Regexps for files to ignore
+ignore_file [\#~]$
+ignore_file DEADJOE$
+ignore_file \.bak$
+ignore_file %$
+ignore_file \.dpkg-(tmp|new|old|dist)$
+ignore_file \.rpm(save|new)$
+ignore_file \.pod$
+
+# Set this if the client doesn't report the correct hostname when
+# telnetting to localhost, port 4949
+#
+host_name {{ inventory_hostname_short }}
+
+# A list of addresses that are allowed to connect. This must be a
+# regular expression, since Net::Server does not understand CIDR-style
+# network notation unless the perl module Net::CIDR is installed. You
+# may repeat the allow line as many times as you'd like
+
+allow ^127\.0\.0\.1$
+allow ^::1$
+
+# Which address to bind to;
+host 127.0.0.1
+
+# And which port
+port 4994
diff --git a/roles/common/templates/etc/munin/plugin-conf.d/munin-node.j2 b/roles/common/templates/etc/munin/plugin-conf.d/munin-node.j2
new file mode 100644
index 0000000..fa05327
--- /dev/null
+++ b/roles/common/templates/etc/munin/plugin-conf.d/munin-node.j2
@@ -0,0 +1,137 @@
+# This file is used to configure how the plugins are invoked.
+# Place in /etc/munin/plugin-conf.d/ or corresponding directory.
+#
+# PLEASE NOTE: Changes in the plugin-conf.d directory are only
+# read at munin-node startup, so restart at any changes.
+#
+# user <user> # Set the user to run the plugin as.
+# group <group> # Set the group to run the plugin as.
+# command <command> # Run <command> instead of the plugin. %c expands to
+# what would normally be run.
+# env.<variable> <value> # Sets <variable> in the plugin's environment, see the
+# individual plugins to find out which variables they
+# care about.
+
+
+[amavis]
+group adm
+env.MUNIN_MKTEMP /bin/mktemp -p /tmp/ $1
+env.amavislog /var/log/mail.info
+
+[apt]
+user root
+
+[courier_mta_mailqueue]
+group daemon
+
+[courier_mta_mailstats]
+group adm
+
+[courier_mta_mailvolume]
+group adm
+
+[cps*]
+user root
+
+[df*]
+env.warning 92
+env.critical 98
+
+[exim_mailqueue]
+group adm, (Debian-exim)
+
+[exim_mailstats]
+group adm, (Debian-exim)
+env.logdir /var/log/exim4/
+env.logname mainlog
+
+[fw_conntrack]
+user root
+
+[fw_forwarded_local]
+user root
+
+[hddtemp_smartctl]
+user root
+
+[hddtemp2]
+user root
+
+[if_*]
+user root
+
+[if_err_*]
+user nobody
+
+[ip_*]
+user root
+
+[ipmi_*]
+user root
+
+[mysql*]
+user root
+env.mysqlopts --defaults-file=/etc/mysql/debian.cnf
+env.mysqluser debian-sys-maint
+env.mysqlconnection DBI:mysql:mysql;mysql_read_default_file=/etc/mysql/debian.cnf
+
+[postfix_mailqueue_*]
+user postfix
+
+[postfix_stats_*]
+group adm
+
+[postfix_sasl_*]
+group adm
+
+[postfix_mailvolume2]
+group adm
+env.postmulti postfix{% for g in postfix_instance.keys() | sort %}{% if g in group_names %} postfix-{{ postfix_instance[g].name }}{% endif %}{% endfor %}
+
+
+[dovecot_logins]
+group adm
+
+[dovecot_stats_*]
+user root
+
+[dovecot_who]
+user root
+
+[sendmail_*]
+user smmta
+
+[smart_*]
+user root
+
+[vlan*]
+user root
+
+[ejabberd*]
+user ejabberd
+env.statuses available away chat xa
+env.days 1 7 30
+
+[dhcpd3]
+user root
+env.leasefile /var/lib/dhcp3/dhcpd.leases
+env.configfile /etc/dhcp3/dhcpd.conf
+
+[jmx_*]
+env.ip 127.0.0.1
+env.port 5400
+
+[samba]
+user root
+
+[munin_stats]
+user munin
+group munin
+
+[postgres_*]
+user postgres
+env.PGUSER postgres
+env.PGPORT 5432
+
+[fail2ban]
+user root
diff --git a/roles/common/templates/etc/stunnel/munin-node.conf.j2 b/roles/common/templates/etc/stunnel/munin-node.conf.j2
new file mode 100644
index 0000000..de6c156
--- /dev/null
+++ b/roles/common/templates/etc/stunnel/munin-node.conf.j2
@@ -0,0 +1,53 @@
+; **************************************************************************
+; * Global options *
+; **************************************************************************
+
+; setuid()/setgid() to the specified user/group in daemon mode
+setuid = stunnel4
+setgid = stunnel4
+
+; PID is created inside the chroot jail
+pid = /var/run/stunnel4/munin-node.pid
+
+; Only log messages at severity warning (4) and higher
+debug = 4
+
+; **************************************************************************
+; * Service defaults may also be specified in individual service sections *
+; **************************************************************************
+
+; Certificate/key is needed in server mode and optional in client mode
+cert = /etc/stunnel/certs/munin-{{ inventory_hostname_short }}.pem
+key = /etc/stunnel/certs/munin-{{ inventory_hostname_short }}.key
+
+; Some performance tunings
+socket = l:TCP_NODELAY=1
+socket = r:TCP_NODELAY=1
+
+; Prevent MITM attacks
+verify = 4
+
+; Disable support for insecure protocols
+options = NO_SSLv2
+options = NO_SSLv3
+options = NO_TLSv1
+options = NO_TLSv1.1
+
+; These options provide additional security at some performance degradation
+options = SINGLE_ECDH_USE
+options = SINGLE_DH_USE
+
+; Select permitted SSL ciphers
+ciphers = EECDH+AES:EDH+AES:!MEDIUM:!LOW:!EXP:!aNULL:!eNULL:!SSLv2:!SSLv3:!TLSv1:!TLSv1.1
+
+; **************************************************************************
+; * Service definitions (remove all services for inetd mode) *
+; **************************************************************************
+
+[munin-node]
+client = no
+accept = 4949
+connect = 127.0.0.1:4994
+CAfile = /etc/stunnel/certs/munin-master.pem
+
+; vim:ft=dosini
diff --git a/roles/lists/handlers/main.yml b/roles/lists/handlers/main.yml
index d4dd998..57a35db 100644
--- a/roles/lists/handlers/main.yml
+++ b/roles/lists/handlers/main.yml
@@ -13,3 +13,6 @@
- name: Restart wwsympa
service: name=wwsympa state=restarted
+
+- name: Restart munin-node
+ service: name=munin-node state=restarted
diff --git a/roles/lists/tasks/mail.yml b/roles/lists/tasks/mail.yml
index 6d1a4f5..85d3103 100644
--- a/roles/lists/tasks/mail.yml
+++ b/roles/lists/tasks/mail.yml
@@ -52,3 +52,31 @@
dest=/usr/local/bin/sympa-queue
owner=root group=root
mode=0755
+
+
+- name: Install 'postfix_mailqueue_' Munin wildcard plugin
+ file: src=/usr/local/share/munin/plugins/postfix_mailqueue_
+ dest=/etc/munin/plugins/postfix_mailqueue_postfix-{{ postfix_instance[inst].name }}
+ owner=root group=root
+ state=link force=yes
+ tags:
+ - munin
+ - munin-node
+ notify:
+ - Restart munin-node
+
+- name: Install 'postfix_stats_' Munin wildcard plugin
+ file: src=/usr/local/share/munin/plugins/postfix_stats_
+ dest=/etc/munin/plugins/postfix_stats_{{ item }}_postfix-{{ postfix_instance[inst].name }}
+ owner=root group=root
+ state=link force=yes
+ with_items:
+ - smtpd
+ - qmgr
+ - smtp
+ - pipe
+ tags:
+ - munin
+ - munin-node
+ notify:
+ - Restart munin-node
diff --git a/roles/munin-master/files/etc/nginx/sites-available/munin b/roles/munin-master/files/etc/nginx/sites-available/munin
new file mode 100644
index 0000000..ade1888
--- /dev/null
+++ b/roles/munin-master/files/etc/nginx/sites-available/munin
@@ -0,0 +1,31 @@
+server {
+ listen 127.0.0.1:80;
+ listen [::1]:80;
+
+ server_name munin.fripost.org;
+
+ access_log /var/log/nginx/munin.access.log;
+ error_log /var/log/nginx/munin.error.log info;
+
+ location = / {
+ return 302 /munin$args;
+ }
+
+ location /munin/static/ {
+ alias /etc/munin/static/;
+ }
+
+ location /munin-cgi/munin-cgi-graph/ {
+ fastcgi_split_path_info ^(/munin-cgi/munin-cgi-graph)(.*);
+ include fastcgi/params;
+ fastcgi_pass unix:/run/munin/cgi-graph.socket;
+ gzip off;
+ }
+
+ location /munin/ {
+ fastcgi_split_path_info ^(/munin)(.*);
+ include fastcgi/params;
+ fastcgi_pass unix:/run/munin/cgi-html.socket;
+ gzip off;
+ }
+}
diff --git a/roles/munin-master/files/lib/systemd/system/munin-cgi-graph.service b/roles/munin-master/files/lib/systemd/system/munin-cgi-graph.service
new file mode 100644
index 0000000..9e4d820
--- /dev/null
+++ b/roles/munin-master/files/lib/systemd/system/munin-cgi-graph.service
@@ -0,0 +1,14 @@
+[Unit]
+Description=Munin CGI Graph Service
+After=network.target
+PartOf=munin.service
+Requires=munin-cgi-graph.socket
+
+[Service]
+StandardInput=socket
+User=www-data
+Group=munin
+ExecStart=/usr/lib/munin/cgi/munin-cgi-graph
+
+[Install]
+WantedBy=multi-user.target
diff --git a/roles/munin-master/files/lib/systemd/system/munin-cgi-graph.socket b/roles/munin-master/files/lib/systemd/system/munin-cgi-graph.socket
new file mode 100644
index 0000000..d4d2e27
--- /dev/null
+++ b/roles/munin-master/files/lib/systemd/system/munin-cgi-graph.socket
@@ -0,0 +1,11 @@
+[Unit]
+Description=Munin CGI Graph Listen Socket
+
+[Socket]
+SocketUser=www-data
+SocketGroup=www-data
+SocketMode=0600
+ListenStream=/run/munin/cgi-graph.socket
+
+[Install]
+WantedBy=sockets.target
diff --git a/roles/munin-master/files/lib/systemd/system/munin-cgi-html.service b/roles/munin-master/files/lib/systemd/system/munin-cgi-html.service
new file mode 100644
index 0000000..11a7470
--- /dev/null
+++ b/roles/munin-master/files/lib/systemd/system/munin-cgi-html.service
@@ -0,0 +1,14 @@
+[Unit]
+Description=Munin CGI HTML Service
+After=network.target
+PartOf=munin.service
+Requires=munin-cgi-html.socket
+
+[Service]
+StandardInput=socket
+User=www-data
+Group=munin
+ExecStart=/usr/lib/munin/cgi/munin-cgi-html
+
+[Install]
+WantedBy=multi-user.target
diff --git a/roles/munin-master/files/lib/systemd/system/munin-cgi-html.socket b/roles/munin-master/files/lib/systemd/system/munin-cgi-html.socket
new file mode 100644
index 0000000..77be2cf
--- /dev/null
+++ b/roles/munin-master/files/lib/systemd/system/munin-cgi-html.socket
@@ -0,0 +1,11 @@
+[Unit]
+Description=Munin CGI HTML Listen Socket
+
+[Socket]
+SocketUser=www-data
+SocketGroup=www-data
+SocketMode=0600
+ListenStream=/run/munin/cgi-html.socket
+
+[Install]
+WantedBy=sockets.target
diff --git a/roles/munin-master/handlers/main.yml b/roles/munin-master/handlers/main.yml
new file mode 100644
index 0000000..4c41033
--- /dev/null
+++ b/roles/munin-master/handlers/main.yml
@@ -0,0 +1,24 @@
+---
+- name: systemctl daemon-reload
+ command: /bin/systemctl daemon-reload
+
+- name: Restart rrdcached
+ service: name=rrdcached state=restarted
+
+- name: Restart munin
+ service: name=munin state=restarted
+
+- name: Restart munin-node
+ service: name=munin-node state=restarted
+
+- name: Restart munin-cgi-graph
+ service: name=munin-cgi-graph state=restarted
+
+- name: Restart munin-cgi-html
+ service: name=munin-cgi-html state=restarted
+
+- name: Restart Nginx
+ service: name=nginx state=restarted
+
+- name: Restart stunnel
+ service: name=stunnel4 pattern=/usr/bin/stunnel4 state=restarted
diff --git a/roles/munin-master/tasks/main.yml b/roles/munin-master/tasks/main.yml
new file mode 100644
index 0000000..5dd1151
--- /dev/null
+++ b/roles/munin-master/tasks/main.yml
@@ -0,0 +1,136 @@
+- name: Install munin
+ apt: pkg={{ item }}
+ with_items:
+ - munin
+ - rrdcached
+ - libcgi-fast-perl
+
+- name: Configure rrdcached
+ lineinfile: "dest=/etc/default/rrdcached
+ regexp='^#?OPTS='
+ line='OPTS=\"-s munin -m 660 -l unix:/var/run/rrdcached.sock -w 1800 -z 1800 -f 3600 -j /var/lib/rrdcached/journal -F -b /var/lib/munin -B\"'"
+ register: r
+ notify:
+ - Restart rrdcached
+
+- name: Start rrdcached
+ service: name=rrdcached state=started
+ when: not r.changed
+
+- meta: flush_handlers
+
+
+- name: Configure munin
+ template: src=etc/munin/munin.conf.j2
+ dest=/etc/munin/munin.conf
+ owner=root group=root
+ mode=0644
+ notify:
+ - Restart munin-cgi-graph
+ - Restart munin-cgi-html
+
+- name: chown www-data:adm /var/log/munin/munin-cgi-{graph,html}.log
+ file: path=/var/log/munin/{{ item }}
+ owner=www-data group=adm
+ mode=0640
+ with_items:
+ - munin-cgi-graph.log
+ - munin-cgi-html.log
+
+- name: Copy munin-cgi-graph.{service,socket}
+ copy: src=lib/systemd/system/{{ item }}
+ dest=/lib/systemd/system/{{ item }}
+ owner=root group=root
+ mode=0644
+ notify:
+ - systemctl daemon-reload
+ - Restart munin-cgi-graph
+ with_items:
+ - munin-cgi-graph.service
+ - munin-cgi-graph.socket
+
+- name: Copy munin-cgi-html.{service,socket}
+ copy: src=lib/systemd/system/{{ item }}
+ dest=/lib/systemd/system/{{ item }}
+ owner=root group=root
+ mode=0644
+ notify:
+ - systemctl daemon-reload
+ - Restart munin-cgi-html
+ with_items:
+ - munin-cgi-html.service
+ - munin-cgi-html.socket
+
+- meta: flush_handlers
+
+- name: Start munin-cgi-{graph,html}
+ service: name={{ item }} state=started enabled=yes
+ with_items:
+ - munin-cgi-graph
+ - munin-cgi-html
+
+
+- name: Copy /etc/nginx/sites-available/munin
+ copy: src=etc/nginx/sites-available/munin
+ dest=/etc/nginx/sites-available/munin
+ owner=root group=root
+ mode=0644
+ register: r1
+ notify:
+ - Restart Nginx
+
+- name: Create /etc/nginx/sites-enabled/munin
+ file: src=../sites-available/munin
+ dest=/etc/nginx/sites-enabled/munin
+ owner=root group=root
+ state=link force=yes
+ register: r2
+ notify:
+ - Restart Nginx
+
+- name: Start Nginx
+ service: name=nginx state=started
+ when: not (r1.changed or r2.changed)
+
+- meta: flush_handlers
+
+
+- name: Copy munin-node X.509 certificates
+ copy: src=certs/munin/{{ item }}.pem
+ dest=/etc/stunnel/certs/munin-{{ hostvars[item].inventory_hostname_short }}.pem
+ owner=root group=root
+ mode=0644
+ with_items: groups.all | difference([inventory_hostname])
+ register: r1
+ notify:
+ - Restart stunnel
+
+- name: Configure stunnel
+ template: src=etc/stunnel/munin-master.conf.j2
+ dest=/etc/stunnel/munin-master.conf
+ owner=root group=root
+ mode=0644
+ register: r2
+ notify:
+ - Restart stunnel
+
+- name: Start stunnel
+ service: name=stunnel4 pattern=/usr/bin/stunnel4 state=started
+ when: not (r1.changed or r2.changed)
+
+- meta: flush_handlers
+
+
+- name: Install 'munin_stats' and 'munin_update' plugins
+ file: src=/usr/share/munin/plugins/{{ item }}
+ dest=/etc/munin/plugins/{{ item }}
+ owner=root group=root
+ state=link force=yes
+ with_items:
+ - munin_stats
+ - munin_update
+ tags:
+ - munin-node
+ - munin
+ notify:
+ - Restart munin-node
diff --git a/roles/munin-master/templates/etc/munin/munin.conf.j2 b/roles/munin-master/templates/etc/munin/munin.conf.j2
new file mode 100644
index 0000000..8273a83
--- /dev/null
+++ b/roles/munin-master/templates/etc/munin/munin.conf.j2
@@ -0,0 +1,115 @@
+# Example configuration file for Munin, generated by 'make build'
+
+# The next three variables specifies where the location of the RRD
+# databases, the HTML output, logs and the lock/pid files. They all
+# must be writable by the user running munin-cron. They are all
+# defaulted to the values you see here.
+#
+#dbdir /var/lib/munin
+#htmldir /var/cache/munin/www
+#logdir /var/log/munin
+#rundir /var/run/munin
+
+# Where to look for the HTML templates
+#
+#tmpldir /etc/munin/templates
+
+# Where to look for the static www files
+#
+#staticdir /etc/munin/static
+
+# temporary cgi files are here. note that it has to be writable by
+# the cgi user (usually nobody or httpd).
+#
+# cgitmpdir /var/lib/munin/cgi-tmp
+
+# (Exactly one) directory to include all files from.
+includedir /etc/munin/munin-conf.d
+
+# You can choose the time reference for "DERIVE" like graphs, and show
+# "per minute", "per hour" values instead of the default "per second"
+#
+#graph_period second
+
+# Graphics files are generated either via cron or by a CGI process.
+# See http://munin-monitoring.org/wiki/CgiHowto2 for more
+# documentation.
+# Since 2.0, munin-graph has been rewritten to use the cgi code.
+# It is single threaded *by design* now.
+#
+graph_strategy cgi
+
+# munin-cgi-graph is invoked by the web server up to very many times at the
+# same time. This is not optimal since it results in high CPU and memory
+# consumption to the degree that the system can thrash. Again the default is
+# 6. Most likely the optimal number for max_cgi_graph_jobs is the same as
+# max_graph_jobs.
+#
+#munin_cgi_graph_jobs 6
+
+# If the automatic CGI url is wrong for your system override it here:
+#
+#cgiurl_graph /munin-cgi/munin-cgi-graph
+
+# max_size_x and max_size_y are the max size of images in pixel.
+# Default is 4000. Do not make it too large otherwise RRD might use all
+# RAM to generate the images.
+#
+#max_size_x 4000
+#max_size_y 4000
+
+# HTML files are normally generated by munin-html, no matter if the
+# files are used or not. You can change this to on-demand generation
+# by following the instructions in http://munin-monitoring.org/wiki/CgiHowto2
+#
+# Notes:
+# - moving to CGI for HTML means you cannot have graph generated by cron.
+# - cgi html has some bugs, mostly you still have to launch munin-html by hand
+#
+html_strategy cgi
+
+# munin-update runs in parallel.
+#
+# The default max number of processes is 16, and is probably ok for you.
+#
+# If set too high, it might hit some process/ram/filedesc limits.
+# If set too low, munin-update might take more than 5 min.
+#
+# If you want munin-update to not be parallel set it to 0.
+#
+#max_processes 16
+
+# RRD updates are per default, performed directly on the rrd files.
+# To reduce IO and enable the use of the rrdcached, uncomment it and set it to
+# the location of the socket that rrdcached uses.
+#
+rrdcached_socket /var/run/rrdcached.sock
+
+# Drop somejuser@fnord.comm and anotheruser@blibb.comm an email everytime
+# something changes (OK -> WARNING, CRITICAL -> OK, etc)
+contact.admin.command mail -s "Munin notification" admin@fripost.org
+#
+# For those with Nagios, the following might come in handy. In addition,
+# the services must be defined in the Nagios server as well.
+#contact.nagios.command /usr/bin/send_nsca nagios.host.comm -c /etc/nsca.conf
+
+local_address 127.0.0.1
+
+{% set n = 0 %}
+{% for node in groups.all | sort %}
+{% set n = n + 1 %}
+[all;{{ hostvars[node].inventory_hostname_short }}]
+{% if node == inventory_hostname %}
+ address 127.0.0.1
+{% else %}
+ address 127.0.{{ n }}.1
+{% endif %}
+ port 4994
+
+{% for g in hostvars[node].group_names | sort %}
+[{{ g }};{{ hostvars[node].inventory_hostname_short }}]
+ update no
+
+{% endfor %}
+
+{% endfor %}
diff --git a/roles/munin-master/templates/etc/stunnel/munin-master.conf.j2 b/roles/munin-master/templates/etc/stunnel/munin-master.conf.j2
new file mode 100644
index 0000000..c025183
--- /dev/null
+++ b/roles/munin-master/templates/etc/stunnel/munin-master.conf.j2
@@ -0,0 +1,62 @@
+; **************************************************************************
+; * Global options *
+; **************************************************************************
+
+; setuid()/setgid() to the specified user/group in daemon mode
+setuid = stunnel4
+setgid = stunnel4
+
+; PID is created inside the chroot jail
+pid = /var/run/stunnel4/munin-master.pid
+
+; Only log messages at severity warning (4) and higher
+debug = 4
+
+; **************************************************************************
+; * Service defaults may also be specified in individual service sections *
+; **************************************************************************
+
+; Certificate/key is needed in server mode and optional in client mode
+cert = /etc/stunnel/certs/munin-{{ inventory_hostname_short }}.pem
+key = /etc/stunnel/certs/munin-{{ inventory_hostname_short }}.key
+client = yes
+socket = a:SO_BINDTODEVICE=lo
+
+; Some performance tunings
+socket = l:TCP_NODELAY=1
+socket = r:TCP_NODELAY=1
+
+; Prevent MITM attacks
+verify = 4
+
+; Disable support for insecure protocols
+options = NO_SSLv2
+options = NO_SSLv3
+options = NO_TLSv1
+options = NO_TLSv1.1
+
+; These options provide additional security at some performance degradation
+options = SINGLE_ECDH_USE
+options = SINGLE_DH_USE
+
+; Select permitted SSL ciphers
+ciphers = EECDH+AES:EDH+AES:!MEDIUM:!LOW:!EXP:!aNULL:!eNULL:!SSLv2:!SSLv3:!TLSv1:!TLSv1.1
+
+; **************************************************************************
+; * Service definitions (remove all services for inetd mode) *
+; **************************************************************************
+
+{% set n = 0 %}
+{% for node in groups.all | sort %}
+{% set n = n + 1 %}
+{% if node != inventory_hostname %}
+[{{ hostvars[node].inventory_hostname_short }}]
+accept = 127.0.{{ n }}.1:4994
+connect = {{ node }}:4949
+delay = yes
+CAfile = /etc/stunnel/certs/munin-{{ hostvars[node].inventory_hostname_short }}.pem
+{% endif %}
+
+{% endfor %}
+
+; vim:ft=dosini
diff --git a/roles/out/handlers/main.yml b/roles/out/handlers/main.yml
index 99a5db2..9edf610 100644
--- a/roles/out/handlers/main.yml
+++ b/roles/out/handlers/main.yml
@@ -1,3 +1,6 @@
---
- name: Reload Postfix
service: name=postfix state=reloaded
+
+- name: Restart munin-node
+ service: name=munin-node state=restarted
diff --git a/roles/out/tasks/main.yml b/roles/out/tasks/main.yml
index 2a9cf71..10429b1 100644
--- a/roles/out/tasks/main.yml
+++ b/roles/out/tasks/main.yml
@@ -28,3 +28,30 @@
- name: Start Postfix
service: name=postfix state=started
+
+
+- name: Install 'postfix_mailqueue_' Munin wildcard plugin
+ file: src=/usr/local/share/munin/plugins/postfix_mailqueue_
+ dest=/etc/munin/plugins/postfix_mailqueue_postfix-{{ postfix_instance[inst].name }}
+ owner=root group=root
+ state=link force=yes
+ tags:
+ - munin
+ - munin-node
+ notify:
+ - Restart munin-node
+
+- name: Install 'postfix_stats_' Munin wildcard plugin
+ file: src=/usr/local/share/munin/plugins/postfix_stats_
+ dest=/etc/munin/plugins/postfix_stats_{{ item }}_postfix-{{ postfix_instance[inst].name }}
+ owner=root group=root
+ state=link force=yes
+ with_items:
+ - smtpd
+ - qmgr
+ - smtp
+ tags:
+ - munin
+ - munin-node
+ notify:
+ - Restart munin-node