From b408390ae9311b7d703ce57c25a78dce23c31b16 Mon Sep 17 00:00:00 2001 From: Guilhem Moulin Date: Wed, 10 Jun 2015 15:35:13 +0200 Subject: 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. --- roles/IMAP/handlers/main.yml | 3 + roles/IMAP/tasks/imap.yml | 26 +++ roles/IMAP/tasks/mda.yml | 28 +++ roles/MSA/handlers/main.yml | 3 + roles/MSA/tasks/main.yml | 38 ++++ roles/MX/handlers/main.yml | 3 + roles/MX/tasks/main.yml | 29 +++ roles/amavis/handlers/main.yml | 3 + roles/amavis/tasks/main.yml | 12 ++ roles/common-SQL/handlers/main.yml | 3 + roles/common-SQL/tasks/main.yml | 35 ++++ .../etc/logcheck/ignore.d.server/common-local | 2 + .../usr/local/share/munin/plugins/dovecot_logins | 119 ++++++++++++ .../usr/local/share/munin/plugins/dovecot_stats_ | 135 ++++++++++++++ .../usr/local/share/munin/plugins/dovecot_who | 43 +++++ .../local/share/munin/plugins/postfix_mailqueue_ | 57 ++++++ .../local/share/munin/plugins/postfix_mailvolume2 | 62 ++++++ .../usr/local/share/munin/plugins/postfix_sasl_ | 63 +++++++ .../usr/local/share/munin/plugins/postfix_stats_ | 113 +++++++++++ roles/common/handlers/main.yml | 3 + roles/common/tasks/main.yml | 9 +- roles/common/tasks/munin-node.yml | 207 +++++++++++++++++++++ roles/common/templates/etc/iptables/services.j2 | 7 +- .../common/templates/etc/munin/munin-node.conf.j2 | 51 +++++ .../etc/munin/plugin-conf.d/munin-node.j2 | 137 ++++++++++++++ .../templates/etc/stunnel/munin-node.conf.j2 | 53 ++++++ roles/lists/handlers/main.yml | 3 + roles/lists/tasks/mail.yml | 28 +++ .../files/etc/nginx/sites-available/munin | 31 +++ .../lib/systemd/system/munin-cgi-graph.service | 14 ++ .../lib/systemd/system/munin-cgi-graph.socket | 11 ++ .../lib/systemd/system/munin-cgi-html.service | 14 ++ .../files/lib/systemd/system/munin-cgi-html.socket | 11 ++ roles/munin-master/handlers/main.yml | 24 +++ roles/munin-master/tasks/main.yml | 136 ++++++++++++++ .../munin-master/templates/etc/munin/munin.conf.j2 | 115 ++++++++++++ .../templates/etc/stunnel/munin-master.conf.j2 | 62 ++++++ roles/out/handlers/main.yml | 3 + roles/out/tasks/main.yml | 27 +++ 39 files changed, 1718 insertions(+), 5 deletions(-) create mode 100755 roles/common/files/usr/local/share/munin/plugins/dovecot_logins create mode 100755 roles/common/files/usr/local/share/munin/plugins/dovecot_stats_ create mode 100755 roles/common/files/usr/local/share/munin/plugins/dovecot_who create mode 100755 roles/common/files/usr/local/share/munin/plugins/postfix_mailqueue_ create mode 100755 roles/common/files/usr/local/share/munin/plugins/postfix_mailvolume2 create mode 100755 roles/common/files/usr/local/share/munin/plugins/postfix_sasl_ create mode 100755 roles/common/files/usr/local/share/munin/plugins/postfix_stats_ create mode 100644 roles/common/tasks/munin-node.yml create mode 100644 roles/common/templates/etc/munin/munin-node.conf.j2 create mode 100644 roles/common/templates/etc/munin/plugin-conf.d/munin-node.j2 create mode 100644 roles/common/templates/etc/stunnel/munin-node.conf.j2 create mode 100644 roles/munin-master/files/etc/nginx/sites-available/munin create mode 100644 roles/munin-master/files/lib/systemd/system/munin-cgi-graph.service create mode 100644 roles/munin-master/files/lib/systemd/system/munin-cgi-graph.socket create mode 100644 roles/munin-master/files/lib/systemd/system/munin-cgi-html.service create mode 100644 roles/munin-master/files/lib/systemd/system/munin-cgi-html.socket create mode 100644 roles/munin-master/handlers/main.yml create mode 100644 roles/munin-master/tasks/main.yml create mode 100644 roles/munin-master/templates/etc/munin/munin.conf.j2 create mode 100644 roles/munin-master/templates/etc/stunnel/munin-master.conf.j2 (limited to 'roles') 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]+|): 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 +# +# 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 . + +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 + +=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 < +# +# 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 . + +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 +# +# 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 . + +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 +# +# 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 . + +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 +# +# 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 . + +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 +# +# 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 . + +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 # Set the user to run the plugin as. +# group # Set the group to run the plugin as. +# command # Run instead of the plugin. %c expands to +# what would normally be run. +# env. # Sets 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 -- cgit v1.2.3