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