summaryrefslogtreecommitdiffstats
path: root/roles/common
diff options
context:
space:
mode:
authorGuilhem Moulin <guilhem@fripost.org>2015-06-10 15:35:13 +0200
committerGuilhem Moulin <guilhem@fripost.org>2015-06-10 18:37:19 +0200
commitb408390ae9311b7d703ce57c25a78dce23c31b16 (patch)
treed9b1c795c0ef8b75dbaef709aa8622863d636942 /roles/common
parenta82e3759627a0612592d853796f2a1137f9189f5 (diff)
Configure munin nodes & master.
Interhost communications are protected by stunnel4. The graphs are only visible on the master itself, and content is generated by Fast CGI.
Diffstat (limited to 'roles/common')
-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
15 files changed, 1056 insertions, 5 deletions
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