+
+
+
diff --git a/nginx/templates/default_site.j2 b/evolinux-base/templates/default_www/nginx_default_site.j2
similarity index 95%
rename from nginx/templates/default_site.j2
rename to evolinux-base/templates/default_www/nginx_default_site.j2
index 1e1ceab5..803ff4ad 100644
--- a/nginx/templates/default_site.j2
+++ b/evolinux-base/templates/default_www/nginx_default_site.j2
@@ -18,7 +18,7 @@ server {
access_log /var/log/nginx/access.log;
error_log /var/log/nginx/error.log;
- error_page 403 {{ nginx_default_redirect_url }};
+ error_page 403 {{ evolinux_default_www_redirect_url }};
root /var/www;
diff --git a/evolinux-base/templates/hardware/cciss-vol-statusd.j2 b/evolinux-base/templates/hardware/cciss-vol-statusd.j2
new file mode 100644
index 00000000..275f9373
--- /dev/null
+++ b/evolinux-base/templates/hardware/cciss-vol-statusd.j2
@@ -0,0 +1,191 @@
+#! /bin/sh
+
+# Author: Petter Reinholdtsen
+# Author: Adam Cécile (Le_Vert)
+# License: GNU General Public License v2 or later
+#
+### BEGIN INIT INFO
+# Provides: cciss-vol-statusd
+# Required-Start: $remote_fs $syslog
+# Required-Stop: $remote_fs $syslog
+# Default-Start: 2 3 4 5
+# Default-Stop: 0 1 6
+# Short-Description: Check cciss_vol_status values in the background.
+### END INIT INFO
+
+PATH=/sbin:/bin:/usr/sbin:/usr/bin
+DESC="cciss-vol-status monitor"
+NAME="cciss-vol-statusd"
+PIDFILE=/var/run/$NAME.pid
+STATUSFILE=/var/run/$NAME.status
+SCRIPTNAME=/etc/init.d/$NAME
+
+MAILTO="{{ raid_alert_email or general_alert_email | mandatory }}" # Where to report problems
+PERIOD=600 # Seconds between each check (default 10 minutes)
+REMIND=86400 # Seconds between each reminder (default 2 hours)
+RUN_DAEMON=yes
+ID=/dev/cciss/sda
+
+[ -e /etc/default/cciss-vol-statusd ] && . /etc/default/cciss-vol-statusd
+
+# Gracefully exit if the package has been removed.
+test -x /usr/sbin/cciss_vol_status || exit 0
+
+. /lib/lsb/init-functions
+[ -e /etc/default/rcS ] && . /etc/default/rcS
+
+if [ $RUN_DAEMON = "no" ] ; then
+ log_begin_msg "cciss-vol-statusd is disabled in /etc/default/cciss-vol-statusd, not starting."
+ log_end_msg 0
+ exit 0
+fi
+
+check_cciss() {
+ echo $$ > $PIDFILE.new && mv $PIDFILE.new $PIDFILE
+ while true ; do
+ # Check ever $PERIOD seconds, send email on every status
+ # change and repeat ever $REMIND seconds if the raid is still
+ # bad.
+ if (cciss_vol_status $ID); then
+ BADRAID=false
+ else
+ BADRAID=true
+ logger -t cciss-vol-statusd "detected non-optimal RAID status"
+ fi
+ STATUSCHANGE=false
+ if [ true = "$BADRAID" ] ; then
+ # RAID not OK
+ (cciss_vol_status $ID) > $STATUSFILE.new
+ if [ ! -f $STATUSFILE ] ; then # RAID just became broken
+ STATUSCHANGE=true
+ mv $STATUSFILE.new $STATUSFILE
+ elif cmp -s $STATUSFILE $STATUSFILE.new ; then
+ # No change. Should we send reminder?
+ LASTTIME="`stat -c '%Z' $STATUSFILE`"
+ NOW="`date +%s`"
+ SINCELAST="`expr $NOW - $LASTTIME`"
+ if [ $REMIND -le "$SINCELAST" ]; then
+ # Time to send reminder
+ STATUSCHANGE=true
+ mv $STATUSFILE.new $STATUSFILE
+ else
+ rm $STATUSFILE.new
+ fi
+ else
+ STATUSCHANGE=true
+ mv $STATUSFILE.new $STATUSFILE
+ fi
+ else
+ # RAID OK
+ if [ -f $STATUSFILE ] ; then
+ rm $STATUSFILE
+ STATUSCHANGE=true
+ fi
+ fi
+
+ if [ true = "$STATUSCHANGE" ]; then
+ hostname="`uname -n`"
+ (
+ cat < /dev/null 2>&1
+ rm -f $PIDFILE
+ else
+ log_progress_msg "Daemon is already stopped."
+ return 0
+ fi
+}
+
+# This is a workaround function which does not directly exit and
+# therefore can be used by a restart
+d_stop_by_restart() {
+ if [ -f $PIDFILE ] ; then
+ start-stop-daemon --oknodo --stop --quiet --pidfile $PIDFILE
+ rm -f $PIDFILE
+ log_end_msg 0
+ else
+ log_progress_msg "Daemon is already stopped."
+ log_end_msg 0
+ fi
+}
+
+case "$1" in
+ start)
+ echo -n ""
+ log_begin_msg "Starting $DESC: $NAME"
+ d_start ; CODE=$?
+ log_end_msg $CODE
+ ;;
+ stop)
+ log_begin_msg "Stopping $DESC: $NAME"
+ d_stop ; CODE=$?
+ log_end_msg $CODE
+ ;;
+ check_cciss)
+ check_cciss
+ ;;
+ restart|force-reload)
+ log_begin_msg "Restarting $DESC: $NAME"
+ d_stop_by_restart
+ sleep 1
+ d_start || CODE=$?
+ log_end_msg $CODE
+ ;;
+ *)
+ # echo "Usage: $SCRIPTNAME {start|stop|restart|reload|force-reload}" >&2
+ echo "Usage: $SCRIPTNAME {start|stop|restart|force-reload}" >&2
+ exit 1
+ ;;
+esac
+
+exit 0
diff --git a/evolinux-base/templates/hardware/megaclisas-statusd.j2 b/evolinux-base/templates/hardware/megaclisas-statusd.j2
new file mode 100644
index 00000000..02cd9c69
--- /dev/null
+++ b/evolinux-base/templates/hardware/megaclisas-statusd.j2
@@ -0,0 +1,4 @@
+MAILTO={{ raid_alert_email or general_alert_email | mandatory }} # Where to report problems
+PERIOD=600 # Seconds between each check (default 10 minutes)
+REMIND=86400 # Seconds between each reminder (default 2 hours)
+RUN_DAEMON=yes
diff --git a/evolinux-base/templates/system/init_alert5.j2 b/evolinux-base/templates/system/init_alert5.j2
new file mode 100644
index 00000000..41a5b611
--- /dev/null
+++ b/evolinux-base/templates/system/init_alert5.j2
@@ -0,0 +1,16 @@
+#!/bin/sh
+
+### BEGIN INIT INFO
+# Provides: alert5
+# Required-Start: $local_fs
+# Required-Stop: $local_fs
+# Should-Start: $all
+# Should-Stop: $all
+# Default-Start: 2
+# Default-Stop:
+# Short-Description: Send boot/reboot mail on start
+# Description: Send boot/reboot mail on start
+### END INIT INFO
+
+date | mail -s'boot/reboot' {{ reboot_alert_email or general_alert_email | mandatory }}
+#/etc/init.d/minifirewall start
diff --git a/evolinux-base/vars/main.yml b/evolinux-base/vars/main.yml
new file mode 100644
index 00000000..11aae658
--- /dev/null
+++ b/evolinux-base/vars/main.yml
@@ -0,0 +1,31 @@
+evolinux_default_packages:
+ - serveur-base
+ - strace
+ - htop
+ - iftop
+ - iptraf
+ - ncdu
+ - vim
+ - iotop
+ - rsync
+ - mtr-tiny
+ - sudo
+ - git
+ - subversion
+ - ntp
+ - screen
+ - pv
+ - apg
+ - tcpdump
+ - ntpdate
+ - lsb-release
+ - mutt
+ - pinentry-curses
+ - bc
+ - dnsutils
+ - lm-sensors
+ - conntrack
+ - hdparm
+ - lsb-invalid-mta
+ - smartmontools
+ - tree
diff --git a/evomaintenance/defaults/main.yml b/evomaintenance/defaults/main.yml
new file mode 100644
index 00000000..80c7c189
--- /dev/null
+++ b/evomaintenance/defaults/main.yml
@@ -0,0 +1,23 @@
+---
+general_alert_email: "root@localhost"
+evomaintenance_alert_email: Null
+
+general_scripts_dir: "/usr/local/bin"
+evomaintenance_scripts_dir: Null
+
+evomaintenance_hostname: "{{ ansible_fqdn }}"
+
+evomaintenance_pg_host: Null
+evomaintenance_pg_passwd: Null
+evomaintenance_pg_db: Null
+evomaintenance_pg_table: Null
+
+evomaintenance_from: "evomaintenance@{{ ansible_fqdn }}"
+evomaintenance_full_from: "Evomaintenance <{{ evomaintenance_from }}>"
+
+evomaintenance_urgency_from: mama.doe@example.com
+evomaintenance_urgency_tel: "06.00.00.00.00"
+
+evomaintenance_realm: "{{ ansible_domain }}"
+
+evomaintenance_hosts: []
diff --git a/evomaintenance/meta/main.yml b/evomaintenance/meta/main.yml
new file mode 100644
index 00000000..d3bddff3
--- /dev/null
+++ b/evomaintenance/meta/main.yml
@@ -0,0 +1,3 @@
+---
+dependencies:
+ - { role: evolinux-sources-list }
diff --git a/evomaintenance/tasks/main.yml b/evomaintenance/tasks/main.yml
new file mode 100644
index 00000000..8fa8a36e
--- /dev/null
+++ b/evomaintenance/tasks/main.yml
@@ -0,0 +1,32 @@
+---
+
+- name: evomaintenance is installed
+ command: "apt-get install -yq --allow-unauthenticated evomaintenance"
+ register: installed_evomaintenance
+ changed_when: not (installed_evomaintenance.stdout | search("0 upgraded") and installed_evomaintenance.stdout | search("0 newly installed"))
+
+- name: configuration is applied
+ template:
+ src: evomaintenance.j2
+ dest: /etc/evomaintenance.cf
+
+- name: list users with a shell
+ shell: "cat /etc/passwd | grep -vE \"^root:\" | grep -E \":/[^:]+sh$\" | cut -d: -f6"
+ changed_when: False
+ register: home_of_shell_users
+
+- include: trap.yml home={{ item }}
+ with_items: "{{ home_of_shell_users.stdout_lines }}"
+
+- name: minifirewall section for evomaintenance
+ lineinfile:
+ dest: /etc/default/minifirewall
+ line: "/sbin/iptables -A INPUT -p tcp --sport 5432 --dport 1024:65535 -s {{ item }} -m state --state ESTABLISHED,RELATED -j ACCEPT"
+ insertafter: "^# EvoMaintenance"
+ with_items: "{{ evomaintenance_hosts }}"
+
+- name: remove minifirewall example rule for the proxy
+ lineinfile:
+ dest: /etc/default/minifirewall
+ regexp: '^#.*(--sport 5432).*(-s X\.X\.X\.X)'
+ state: absent
diff --git a/evomaintenance/tasks/trap.yml b/evomaintenance/tasks/trap.yml
new file mode 100644
index 00000000..b3c0ef80
--- /dev/null
+++ b/evomaintenance/tasks/trap.yml
@@ -0,0 +1,26 @@
+- name: is {{ home }}/.bash_profile present?
+ stat:
+ path: "{{ home }}/.bash_profile"
+ register: bash_profile
+
+- name: install shell trap in {{ home }}/.bash_profile
+ lineinfile:
+ dest: "{{ home }}/.bash_profile"
+ line: "trap \"sudo {{ evomaintenance_scripts_dir or general_scripts_dir | mandatory }}/evomaintenance.sh\" 0"
+ insertafter: EOF
+ create: no
+ when: bash_profile.stat.exists
+
+- name: is {{ home }}/.profile present?
+ stat:
+ path: "{{ home }}/.profile"
+ register: profile
+ when: not bash_profile.stat.exists
+
+- name: install shell trap in {{ home }}/.profile
+ lineinfile:
+ dest: "{{ home }}/.profile"
+ line: "trap \"sudo {{ evomaintenance_scripts_dir or general_scripts_dir | mandatory }}/evomaintenance.sh\" 0"
+ insertafter: EOF
+ create: yes
+ when: not bash_profile.stat.exists
diff --git a/evomaintenance/templates/evomaintenance.j2 b/evomaintenance/templates/evomaintenance.j2
new file mode 100644
index 00000000..c7f6c69b
--- /dev/null
+++ b/evomaintenance/templates/evomaintenance.j2
@@ -0,0 +1,13 @@
+HOSTNAME={{ evomaintenance_hostname }}
+EVOMAINTMAIL={{ evomaintenance_alert_email or general_alert_email | mandatory }}
+
+export PGPASSWORD={{ evomaintenance_pg_passwd }}
+
+PGDB={{ evomaintenance_pg_db }}
+PGTABLE={{ evomaintenance_pg_table }}
+PGHOST={{ evomaintenance_pg_host }}
+FROM={{ evomaintenance_from }}
+FULLFROM="{{ evomaintenance_full_from }}"
+URGENCYFROM={{ evomaintenance_urgency_from }}
+URGENCYTEL="{{ evomaintenance_urgency_tel }}"
+REALM={{ evomaintenance_realm }}
diff --git a/fail2ban/README.md b/fail2ban/README.md
new file mode 100644
index 00000000..55168279
--- /dev/null
+++ b/fail2ban/README.md
@@ -0,0 +1,16 @@
+# fail2ban
+
+Install Fail2ban.
+
+## Tasks
+
+Everything is in the `tasks/main.yml` file.
+
+## Available variables
+
+Main variables are :
+
+* `general_alert_email`: email address to send various alert messages (default: `root@localhost`).
+* `fail2ban_alert_email`: email address for messages sent to root (default: `general_alert_email`).
+
+The full list of variables (with default values) can be found in `defaults/main.yml`.
diff --git a/fail2ban/defaults/main.yml b/fail2ban/defaults/main.yml
new file mode 100644
index 00000000..ba35f912
--- /dev/null
+++ b/fail2ban/defaults/main.yml
@@ -0,0 +1,3 @@
+---
+general_alert_email: "root@localhost"
+fail2ban_alert_email: Null
diff --git a/fail2ban/files/dovecot-evolix.conf b/fail2ban/files/dovecot-evolix.conf
new file mode 100644
index 00000000..5ca484af
--- /dev/null
+++ b/fail2ban/files/dovecot-evolix.conf
@@ -0,0 +1,3 @@
+[Definition]
+failregex = (?: pop3-login|imap-login): .*(?:Authentication failure|Aborted login \(auth failed|Aborted login \(tried to use disabled|Disconnected \(auth failed|Aborted login \(\d+ authentication attempts).*rip=(?P\S*),.*
+ignoreregex =
diff --git a/fail2ban/files/sasl-evolix.conf b/fail2ban/files/sasl-evolix.conf
new file mode 100644
index 00000000..4115f017
--- /dev/null
+++ b/fail2ban/files/sasl-evolix.conf
@@ -0,0 +1,3 @@
+[Definition]
+failregex = (?i): warning: [-._\w]+\[\]: SASL (?:LOGIN|PLAIN|(?:CRAM|DIGEST)-MD5) authentication failed:
+ignoreregex =
diff --git a/fail2ban/handlers/main.yml b/fail2ban/handlers/main.yml
new file mode 100644
index 00000000..d83f78d9
--- /dev/null
+++ b/fail2ban/handlers/main.yml
@@ -0,0 +1,5 @@
+---
+- name: restart fail2ban
+ service:
+ name: fail2ban
+ state: restarted
diff --git a/fail2ban/tasks/main.yml b/fail2ban/tasks/main.yml
new file mode 100644
index 00000000..0a25e269
--- /dev/null
+++ b/fail2ban/tasks/main.yml
@@ -0,0 +1,24 @@
+---
+- name: package is installed
+ apt:
+ name: fail2ban
+ state: installed
+ tags:
+ - packages
+
+- name: custom filters are installed
+ copy:
+ src: "{{ item }}"
+ dest: /etc/fail2ban/filter.d/
+ mode: 0644
+ with_items:
+ - dovecot-evolix.conf
+ - sasl-evolix.conf
+ notify: restart fail2ban
+
+- name: local jail is installed
+ template:
+ src: jail.local.j2
+ dest: /etc/fail2ban/jail.local
+ mode: 0644
+ notify: restart fail2ban
diff --git a/fail2ban/templates/jail.local.j2 b/fail2ban/templates/jail.local.j2
new file mode 100644
index 00000000..e7d0545d
--- /dev/null
+++ b/fail2ban/templates/jail.local.j2
@@ -0,0 +1,27 @@
+# EvoLinux Fail2Ban config.
+
+[DEFAULT]
+
+# "ignoreip" can be an IP address, a CIDR mask or a DNS host
+ignoreip = 127.0.0.1/8
+bantime = 600
+maxretry = 3
+
+# "backend" specifies the backend used to get files modification. Available
+# options are "gamin", "polling" and "auto".
+# yoh: For some reason Debian shipped python-gamin didn't work as expected
+# This issue left ToDo, so polling is default backend for now
+backend = auto
+
+destemail = {{ fail2ban_alert_email or general_alert_email | mandatory }}
+
+# ACTIONS
+
+banaction = iptables-multiport
+mta = sendmail
+protocol = tcp
+chain = INPUT
+action_mwl = %(banaction)s[name=%(__name__)s, port="%(port)s", protocol="%(protocol)s", chain="%(chain)s"]
+ %(mta)s-whois-lines[name=%(__name__)s, dest="%(destemail)s", logpath=%(logpath)s, chain="%(chain)s"]
+
+action = %(action_mwl)s
diff --git a/filebeat/defaults/main.yml b/filebeat/defaults/main.yml
index e5d78014..6a950e17 100644
--- a/filebeat/defaults/main.yml
+++ b/filebeat/defaults/main.yml
@@ -1,2 +1,3 @@
+---
filebeat_kibana_dashboards: False
filebeat_logstash_plugin: False
diff --git a/java8/defaults/main.yml b/java8/defaults/main.yml
index 19bf7803..9f57f290 100644
--- a/java8/defaults/main.yml
+++ b/java8/defaults/main.yml
@@ -1 +1,2 @@
+---
java8_default_alternative: True
diff --git a/kibana-proxy-nginx/defaults/main.yml b/kibana-proxy-nginx/defaults/main.yml
index 2d2e6480..28477d87 100644
--- a/kibana-proxy-nginx/defaults/main.yml
+++ b/kibana-proxy-nginx/defaults/main.yml
@@ -1,3 +1,4 @@
+---
kibana_proxy_domain: "kibana.{{ ansible_fqdn }}"
kibana_proxy_ssl_cert: "/etc/ssl/certs/{{ ansible_fqdn }}.crt"
kibana_proxy_ssl_key: "/etc/ssl/private/{{ ansible_fqdn }}.key"
diff --git a/listupgrade/defaults/main.yml b/listupgrade/defaults/main.yml
new file mode 100644
index 00000000..0f0f1395
--- /dev/null
+++ b/listupgrade/defaults/main.yml
@@ -0,0 +1,6 @@
+---
+general_alert_email: "root@localhost"
+listupgrade_alert_email: Null
+
+general_scripts_dir: "/usr/local/bin"
+listupgrade_scripts_dir: Null
diff --git a/listupgrade/tasks/main.yml b/listupgrade/tasks/main.yml
new file mode 100644
index 00000000..e2f67284
--- /dev/null
+++ b/listupgrade/tasks/main.yml
@@ -0,0 +1,39 @@
+---
+- name: Scripts dir is present
+ file:
+ path: "{{ evomaintenance_scripts_dir or general_scripts_dir | mandatory }}"
+ state: directory
+ mode: 0700
+
+- name: Copy listupgrade script
+ template:
+ src: listupgrade.sh.j2
+ dest: "{{ evomaintenance_scripts_dir or general_scripts_dir | mandatory }}/listupgrade.sh"
+ mode: 0700
+ owner: root
+ group: root
+ force: yes
+ backup: yes
+
+- name: Create /etc/evolinux
+ file:
+ path: /etc/evolinux
+ state: directory
+ mode: 0600
+
+- name: Copy listupgrade config
+ template:
+ src: listupgrade.cnf.j2
+ dest: /etc/evolinux/listupgrade.cnf
+ mode: 0600
+ owner: root
+ group: root
+ force: no
+
+- name: Enable listupgrade cron
+ template:
+ src: listupgrade_cron.j2
+ dest: /etc/cron.d/listupgrade
+ mode: 0600
+ owner: root
+ group: root
diff --git a/listupgrade/templates/listupgrade.cnf.j2 b/listupgrade/templates/listupgrade.cnf.j2
new file mode 100644
index 00000000..99b00362
--- /dev/null
+++ b/listupgrade/templates/listupgrade.cnf.j2
@@ -0,0 +1,4 @@
+#date="Ce jeudi entre 18h00 et 23h00."
+#clientmail="client@evolix.net"
+#mailto="{{ listupgrade_alert_email or general_alert_email | mandatory }}"
+#hostname=""
diff --git a/listupgrade/templates/listupgrade.sh.j2 b/listupgrade/templates/listupgrade.sh.j2
new file mode 100644
index 00000000..46d5c005
--- /dev/null
+++ b/listupgrade/templates/listupgrade.sh.j2
@@ -0,0 +1,217 @@
+#!/bin/bash
+
+# Exit codes :
+# - 30 : $skip_releases or $skip_packages is set to "all"
+# - 40 : current release is in $skip_releases list
+# - 50 : all upgradable packages are in the $skip_packages list
+# - 60 : current release is not in the $r_releases list
+# - 70 : at least an upgradable package is not in the $r_packages list
+
+set -e
+
+configFile="/etc/evolinux/listupgrade.cnf"
+
+packages=$(mktemp --tmpdir=/tmp evoupdate.XXX)
+packagesHold=$(mktemp --tmpdir=/tmp evoupdate.XXX)
+servicesToRestart=$(mktemp --tmpdir=/tmp evoupdate.XXX)
+template=$(mktemp --tmpdir=/tmp evoupdate.XXX)
+clientmail=$(grep EVOMAINTMAIL /etc/evomaintenance.cf | cut -d'=' -f2)
+mailto=$clientmail
+date="Ce jeudi entre 18h00 et 23h00."
+hostname=$(grep HOSTNAME /etc/evomaintenance.cf | cut -d'=' -f2)
+hostname=${hostname%%.evolix.net}
+# If hostname is composed with -, remove the first part.
+if [[ $hostname =~ "-" ]]; then
+ hostname=$(echo $hostname | cut -d'-' -f2-)
+fi
+# Edit $configFile to override some variables.
+[ -r $configFile ] && . $configFile
+
+# Remove temporary files on exit.
+trap "rm $packages $packagesHold $servicesToRestart $template" EXIT
+
+# Parse line in retrieved upgrade file and ensure there is no malicious values.
+get_value() {
+ file="$1"
+ variable="$2"
+ value="$(grep "^$2:" $1 |head -n 1 |cut -d ':' -f 2 |sed 's/^ //')"
+ if echo "$value" |grep -q -E '^[-.: [:alnum:]]*$'; then
+ echo $value
+ else
+ printf >&2 "Error parsing value \"$value\" for variable $variables.\n"
+ fi
+}
+
+# Fetch which packages/releases will be upgraded.
+fetch_upgrade_info() {
+ upgradeInfo=$(mktemp --tmpdir=/tmp evoupdate.XXX)
+ wget -q -O $upgradeInfo https://upgrades.evolix.org/upgrade
+ r_releases="$(get_value $upgradeInfo "releases")"
+ r_skip_releases="$(get_value $upgradeInfo "skip_releases")"
+ r_packages="$(get_value $upgradeInfo "packages")"
+ r_skip_packages="$(get_value $upgradeInfo "skip_packages")"
+ rm $upgradeInfo
+}
+
+# Check if element $element is in (space separated) list $list.
+is_in() {
+ list="$1"
+ element="$2"
+
+ for i in $list; do
+ if [ "$element" = "$i" ]; then
+ return 0
+ fi
+ done
+ return 1
+}
+
+
+if [[ "$1" != "--cron" ]]; then
+ echo "À quel date/heure allez vous planifier l'envoi ?"
+ echo "Exemple : le jeudi 6 mars entre 18h00 et 23h00"
+ echo -n ">"
+ read date
+ echo "À qui envoyer le mail ?"
+ echo -n ">"
+ read mailto
+fi
+
+# Update APT cache and get packages to upgrade and packages on hold.
+apt -q2 update 2>&1 | (egrep -ve '^(Listing|WARNING|$)' -e upgraded -e 'up to date' || true )
+apt-mark showhold > $packagesHold
+apt list --upgradable 2>&1 | grep -v -f $packagesHold | egrep -v '^(Listing|WARNING|$)' > $packages
+packagesParsable=$(cut -f 1 -d / <$packages |tr '\n' ' ')
+
+# No updates? Exit!
+test ! -s $packages && exit 0
+test ! -s $packagesHold && echo 'Aucun' > $packagesHold
+
+fetch_upgrade_info
+local_release=$(cut -f 1 -d . >$servicesToRestart
+ elif echo "$pkg" |grep -q "^nginx"; then
+ echo "Nginx" >>$servicesToRestart
+ elif echo "$pkg" |grep -q "^php5-fpm"; then
+ echo "PHP FPM" >>$servicesToRestart
+ elif echo "$pkg" |grep -q "^mysql-server"; then
+ echo "MySQL" >>$servicesToRestart
+ elif echo "$pkg" |grep -q "^mariadb-server"; then
+ echo "MariaDB" >>$servicesToRestart
+ elif echo "$pkg" |grep -qE "^postgresql-[[:digit:]]+\.[[:digit:]]+$"; then
+ echo "PostgreSQL" >>$servicesToRestart
+ elif echo "$pkg" |grep -qE "^tomcat[[:digit:]]+$"; then
+ echo "Tomcat" >>$servicesToRestart
+ elif [ "$pkg" = "redis-server" ]; then
+ echo "redis-server" >>$servicesToRestart
+ elif [ "$pkg" = "mongodb-server" ]; then
+ echo "redis-server" >>$servicesToRestart
+ elif echo "$pkg" |grep -qE "^courier-(pop|imap)"; then
+ echo "Courier POP/IMAP" >>$servicesToRestart
+ elif echo "$pkg" |grep -qE "^dovecot-(pop|imap)d"; then
+ echo "Dovecot POP/IMAP" >>$servicesToRestart
+ elif [ "$pkg" = "samba" ]; then
+ echo "Samba" >>$servicesToRestart
+ elif [ "$pkg" = "slapd" ]; then
+ echo "OpenLDAP" >>$servicesToRestart
+ elif [ "$pkg" = "bind9" ]; then
+ echo "Bind9" >>$servicesToRestart
+ elif [ "$pkg" = "postfix" ]; then
+ echo "Postfix" >>$servicesToRestart
+ elif [ "$pkg" = "haproxy" ]; then
+ echo "HAProxy" >>$servicesToRestart
+ elif [ "$pkg" = "varnish" ]; then
+ echo "Varnish" >>$servicesToRestart
+
+ elif [ "$pkg" = "libc6" ]; then
+ echo "Tous les services (mise à jour de libc6)." >$servicesToRestart
+ break
+ elif echo "$pkg" |grep -q "^libssl"; then
+ echo "Tous les services (mise à jour de libssl)." >$servicesToRestart
+ break
+ fi
+done
+test ! -s $servicesToRestart && echo "Aucun" >$servicesToRestart
+
+cat << EOT > $template
+Content-Type: text/plain; charset="utf-8"
+Reply-To: equipe@evolix.fr
+From: equipe@evolix.net
+To: ${clientmail}
+Subject: Prochain creneau pour mise a jour de votre serveur $hostname
+X-Debian-Release: $local_release
+X-Packages: $packagesParsable
+X-Date: $date
+
+Bonjour,
+
+Des mises-à-jour de sécurité ou mineures sont à réaliser sur votre serveur
+${hostname}.
+Sauf indication contraire de votre part, le prochain créneau prévu pour
+intervenir manuellement pour réaliser ces mises-à-jour est :
+${date}
+
+Si nous intervenons, un redémarrage des éventuels services concernés sera
+réalisé, entraînant a priori quelques secondes de coupure. Si nous ne sommes
+pas intervenus sur ce créneau, vous recevrez une nouvelle notification la
+semaine prochaine.
+
+Voici la listes de packages qui seront mis à jour :
+
+$(cat $packages)
+
+Liste des packages dont la mise-à-jour a été manuellement suspendue :
+
+$(cat $packagesHold)
+
+Liste des services qui seront redémarrés :
+
+$(cat $servicesToRestart)
+
+N'hésitez pas à nous faire toute remarque sur ce créneau d'intervention le plus
+tôt possible.
+
+Cordialement,
+--
+Équipe Evolix
+Evolix - Hébergement et Infogérance Open Source http://www.evolix.fr/
+EOT
+
+<$template /usr/sbin/sendmail $mailto
diff --git a/listupgrade/templates/listupgrade_cron.j2 b/listupgrade/templates/listupgrade_cron.j2
new file mode 100644
index 00000000..0e284d65
--- /dev/null
+++ b/listupgrade/templates/listupgrade_cron.j2
@@ -0,0 +1 @@
+42 9 * * 2 root {{ listupgrade_scripts_dir or general_scripts_dir | mandatory }}/listupgrade.sh --cron
diff --git a/logstash/defaults/main.yml b/logstash/defaults/main.yml
index e853af53..2d3c7b40 100644
--- a/logstash/defaults/main.yml
+++ b/logstash/defaults/main.yml
@@ -1,2 +1,3 @@
+---
logstash_jvm_xms: 256m
logstash_jvm_xmx: 1g
diff --git a/minifirewall/README.md b/minifirewall/README.md
new file mode 100644
index 00000000..2d775a6c
--- /dev/null
+++ b/minifirewall/README.md
@@ -0,0 +1,19 @@
+# minifirewall
+
+Install minifirewall a simple and versatile local firewall.
+
+The firewall is not started by default, but an init script is installed.
+
+## Tasks
+
+Everything is in the `tasks/main.yml` file.
+
+## Available variables
+
+* `minifirewall_int`: which network interface to protect (default: detected default ipv4 interface)
+* `minifirewall_ipv6_enabled`: (default: `on`)
+* `minifirewall_int_lan`: (default: IP/32)
+* `minifirewall_trusted_ips`: with IP/hosts should be trusted for full access (default: none)
+* `minifirewall_privilegied_ips`: with IP/hosts should be trusted for restricted access (default: none)
+
+Some IP/hosts must be configured or the server will be inaccessible via network.
diff --git a/minifirewall/defaults/main.yml b/minifirewall/defaults/main.yml
new file mode 100644
index 00000000..6eb9ca02
--- /dev/null
+++ b/minifirewall/defaults/main.yml
@@ -0,0 +1,8 @@
+---
+minifirewall_git_url: "https://forge.evolix.org/minifirewall.git"
+minifirewall_checkout_path: "/usr/local/src/minifirewall"
+minifirewall_int: "{{ ansible_default_ipv4.interface }}"
+minifirewall_ipv6: "on"
+minifirewall_intlan: "{{ ansible_default_ipv4.address }}/32"
+minifirewall_trusted_ips: []
+minifirewall_privilegied_ips: []
diff --git a/minifirewall/tasks/main.yml b/minifirewall/tasks/main.yml
new file mode 100644
index 00000000..a5ce72a9
--- /dev/null
+++ b/minifirewall/tasks/main.yml
@@ -0,0 +1,42 @@
+---
+
+- name: clone git repository
+ git:
+ repo: "{{ minifirewall_git_url}}"
+ dest: "{{ minifirewall_checkout_path }}"
+ clone: yes
+
+# WARN: these tasks copy the file if there are not already there
+# They don't update files.
+
+- name: is init script present?
+ stat:
+ path: /etc/init.d/minifirewall
+ register: init_minifirewall
+
+- name: init script is copied
+ command: "cp {{ minifirewall_checkout_path }}/minifirewall /etc/init.d/minifirewall"
+ when: not init_minifirewall.stat.exists
+
+
+- name: is configuration present?
+ stat:
+ path: /etc/default/minifirewall
+ register: default_minifirewall
+
+- block:
+ - name: configuration is copied
+ command: "cp {{ minifirewall_checkout_path }}/minifirewall.conf /etc/default/minifirewall"
+
+ - name: configuraion is customized
+ replace:
+ dest: /etc/default/minifirewall
+ regexp: '{{ item.regexp }}'
+ replace: '{{ item.replace }}'
+ with_items:
+ - { regexp: "^(INT)='.*'", replace: "\\1='{{ minifirewall_int }}'" }
+ - { regexp: "^(INTLAN)='.*'", replace: "\\1='{{ minifirewall_intlan }}'" }
+ - { regexp: "^(IPV6)='.*'", replace: "\\1='{{ minifirewall_ipv6 }}'" }
+ - { regexp: "^(TRUSTEDIPS)='.*'", replace: "\\1='{{ minifirewall_trusted_ips | join(' ') }}'" }
+ - { regexp: "^(PRIVILEGIEDIPS)='.*'", replace: "\\1='{{ minifirewall_privilegied_ips | join(' ') }}'" }
+ when: not default_minifirewall.stat.exists
diff --git a/monit/defaults/main.yml b/monit/defaults/main.yml
index d306312a..39d28f24 100644
--- a/monit/defaults/main.yml
+++ b/monit/defaults/main.yml
@@ -1,3 +1,4 @@
+---
monit_daemon_time: 60
monit_alert_dest:
monit_httpd_enable: true
diff --git a/monit/tasks/main.yml b/monit/tasks/main.yml
index da86b4bd..604667a5 100644
--- a/monit/tasks/main.yml
+++ b/monit/tasks/main.yml
@@ -10,8 +10,8 @@
- name: custom config is installed
template:
- src: custom.j2
- dest: /etc/monit/conf.d/custom
+ src: custom.conf.j2
+ dest: /etc/monit/conf.d/custom.conf
mode: 0640
force: yes
notify: restart monit
diff --git a/monit/templates/custom.j2 b/monit/templates/custom.conf.j2
similarity index 100%
rename from monit/templates/custom.j2
rename to monit/templates/custom.conf.j2
diff --git a/munin/tasks/main.yml b/munin/tasks/main.yml
index 38cbfd95..572d6547 100644
--- a/munin/tasks/main.yml
+++ b/munin/tasks/main.yml
@@ -66,7 +66,22 @@
src: /usr/share/munin/plugins/sensors_
dest: /etc/munin/plugins/sensors_temp
state: link
- when: not ansible_virtualization_role == "guest"
+ when: ansible_virtualization_role != "guest"
notify: restart munin-node
tags:
- munin
+
+- name: adjustments for grsec kernel
+ blockinfile:
+ dest: /etc/munin/plugin-conf.d/munin-node
+ block: |
+
+ [processes]
+ user root
+
+ [vmstat]
+ user root
+
+ [swap]
+ user root
+ when: ansible_kernel | search("-grs-")
diff --git a/mysql/README.md b/mysql/README.md
index d4bd34ee..48652b4c 100644
--- a/mysql/README.md
+++ b/mysql/README.md
@@ -24,5 +24,9 @@ Tasks are extracted in several files, included in `tasks/main.yml` :
* `mysql_innodb_buffer_pool_size`: amount of RAM dedicated to InnoDB ;
* `mysql_custom_datadir`: custom datadir
* `mysql_custom_tmpdir`: custom tmpdir.
+* `general_alert_email`: email address to send various alert messages (default: `root@localhost`).
+* `log2mail_alert_email`: email address to send Log2mail messages to (default: `general_alert_email`).
+* `general_scripts_dir`: general directory for scripts installation (default: `/usr/local/bin`).
+* `mysql_scripts_dir`: email address to send Log2mail messages to (default: `general_scripts_dir`).
NB : changing the _datadir_ location can be done multiple times, as long as it is not restored to the default initial location, (because a symlink is created and can't be switched back, yet).
diff --git a/mysql/defaults/main.yml b/mysql/defaults/main.yml
index 58cb3a52..c59f3f1c 100644
--- a/mysql/defaults/main.yml
+++ b/mysql/defaults/main.yml
@@ -1,3 +1,10 @@
+---
+general_alert_email: "root@localhost"
+log2mail_alert_email: Null
+
+general_scripts_dir: "/usr/local/bin"
+mysql_scripts_dir: Null
+
mysql_use_mariadb: False
mysql_replace_root_with_mysqladmin: True
@@ -7,7 +14,3 @@ mysql_custom_tmpdir: ''
mysql_thread_cache_size: '{{ ansible_processor_cores }}'
mysql_innodb_buffer_pool_size: '{{ (ansible_memtotal_mb * 0.3) | int }}M'
-
-default_alert_mail: root
-general_alert_mail: Null
-log2mail_alert_mail: Null
diff --git a/mysql/files/z_evolinux.cnf b/mysql/files/evolinux-defaults.cnf
similarity index 100%
rename from mysql/files/z_evolinux.cnf
rename to mysql/files/evolinux-defaults.cnf
diff --git a/mysql/files/mysql-optimize b/mysql/files/mysql-optimize.sh
similarity index 100%
rename from mysql/files/mysql-optimize
rename to mysql/files/mysql-optimize.sh
diff --git a/mysql/files/zzz_evolinux.cnf b/mysql/files/zzz_evolinux.cnf
deleted file mode 100644
index e3d6334a..00000000
--- a/mysql/files/zzz_evolinux.cnf
+++ /dev/null
@@ -1,2 +0,0 @@
-[mysqld]
-#bind-address = 0.0.0.0
diff --git a/mysql/tasks/config.yml b/mysql/tasks/config.yml
index 8388a022..617f846d 100644
--- a/mysql/tasks/config.yml
+++ b/mysql/tasks/config.yml
@@ -1,35 +1,22 @@
---
-- name: Is zzz_evolinux.cnf already present ?
- stat:
- path: /etc/mysql/conf.d/zzz_evolinux.cnf
- register: mysql_zzz_evolinux
- tags:
- - mysql
- - log2mail
-
-- name: Copy MySQL config files
+- name: Copy MySQL defaults config file
copy:
- src: "{{ item.file }}"
- dest: "/etc/mysql/conf.d/{{ item.file }}"
+ src: evolinux-defaults.cnf
+ dest: /etc/mysql/conf.d/z-evolinux-defaults.cnf
owner: root
group: root
- mode: "{{ item.mode }}"
- force: no
- with_items:
- - { file: z_evolinux.cnf, mode: 0644 }
- - { file: zzz_evolinux.cnf, mode: 0640 }
+ mode: 0644
+ force: yes
tags:
- mysql
-- name: Custom MySQL config
- ini_file:
- dest: /etc/mysql/conf.d/zzz_evolinux.cnf
- section: mysqld
- option: '{{ item.option }}'
- value: '{{ item.value }}'
- with_items:
- - { option: thread_cache_size, value: '{{ mysql_thread_cache_size }}' }
- - { option: innodb_buffer_pool_size, value: '{{ mysql_innodb_buffer_pool_size }}' }
- when: mysql_zzz_evolinux.stat.exists == False
+- name: Copy MySQL custom config file
+ template:
+ src: evolinux-custom.cnf.j2
+ dest: /etc/mysql/conf.d/zzz-evolinux-custom.cnf
+ owner: root
+ group: root
+ mode: 0640
+ force: no
tags:
- mysql
diff --git a/mysql/tasks/log2mail.yml b/mysql/tasks/log2mail.yml
index b0fbd547..f4e4c2e0 100644
--- a/mysql/tasks/log2mail.yml
+++ b/mysql/tasks/log2mail.yml
@@ -9,8 +9,8 @@
- log2mail
- name: Copy log2mail config
- copy:
- src: log2mail.conf
+ template:
+ src: log2mail.j2
dest: /etc/log2mail/config/mysql.conf
mode: 0640
when: log2mail_config_dir.stat.exists
diff --git a/mysql/tasks/users.yml b/mysql/tasks/users.yml
index 8add6ef0..7d861df6 100644
--- a/mysql/tasks/users.yml
+++ b/mysql/tasks/users.yml
@@ -2,7 +2,7 @@
# dependency for mysql_user and mysql_db
-- name: python-mysqldb is installed
+- name: python-mysqldb is installed (Ansible dependency)
apt:
name: python-mysqldb
state: installed
diff --git a/mysql/tasks/utils.yml b/mysql/tasks/utils.yml
index a831f71e..b66c5a3b 100644
--- a/mysql/tasks/utils.yml
+++ b/mysql/tasks/utils.yml
@@ -31,8 +31,8 @@
- name: Install mysqltuner
copy:
src: mysqltuner.pl
- dest: /usr/local/bin/mysqltuner.pl
- mode: 700
+ dest: "{{ mysql_scripts_dir or general_scripts_dir | mandatory }}/mysqltuner.pl"
+ mode: 0700
tags:
- mysql
- mysqltuner
@@ -49,7 +49,7 @@
- name: Weekly cron to optimize MySQL
copy:
src: mysql-optimize
- dest: /etc/cron.monthly/mysql-optimize
+ dest: /etc/cron.weekly/mysql-optimize.sh
mode: 0755
tags:
- mysql
@@ -73,7 +73,7 @@
- name: Install my-add.sh
copy:
src: my-add.sh
- dest: /usr/local/bin/my-add.sh
+ dest: "{{ mysql_scripts_dir or general_scripts_dir | mandatory }}/my-add.sh"
mode: 0700
tags:
- mysql
diff --git a/mysql/templates/evolinux-custom.cnf.j2 b/mysql/templates/evolinux-custom.cnf.j2
new file mode 100644
index 00000000..fa818eaf
--- /dev/null
+++ b/mysql/templates/evolinux-custom.cnf.j2
@@ -0,0 +1,4 @@
+[mysqld]
+#bind-address = 0.0.0.0
+thread_cache_size = {{ mysql_thread_cache_size }}
+innodb_buffer_pool_size = {{ mysql_innodb_buffer_pool_size }}
diff --git a/mysql/files/log2mail.conf b/mysql/templates/log2mail.j2
similarity index 53%
rename from mysql/files/log2mail.conf
rename to mysql/templates/log2mail.j2
index e1fa3a68..948c7f07 100644
--- a/mysql/files/log2mail.conf
+++ b/mysql/templates/log2mail.j2
@@ -1,24 +1,24 @@
file = /var/log/syslog
pattern = "is marked as crashed and should be repaired"
-mailto = {{ log2mail_alert_email | general_alert_email | default_alert_email }}
+mailto = {{ log2mail_alert_email or general_alert_email | mandatory }}
template = /etc/log2mail/mail
file = /var/log/syslog
pattern = "init function returned error"
-mailto = {{ log2mail_alert_email | general_alert_email | default_alert_email }}
+mailto = {{ log2mail_alert_email or general_alert_email | mandatory }}
template = /etc/log2mail/mail
file = /var/log/syslog
pattern = "try to repair it"
-mailto = {{ log2mail_alert_email | general_alert_email | default_alert_email }}
+mailto = {{ log2mail_alert_email or general_alert_email | mandatory }}
template = /etc/log2mail/mail
file = /var/log/syslog
pattern = "InnoDB: Fatal error"
-mailto = {{ log2mail_alert_email | general_alert_email | default_alert_email }}
+mailto = {{ log2mail_alert_email or general_alert_email | mandatory }}
template = /etc/log2mail/mail
file = /var/log/syslog
pattern = "as a STORAGE ENGINE failed"
-mailto = {{ log2mail_alert_email | general_alert_email | default_alert_email }}
+mailto = {{ log2mail_alert_email or general_alert_email | mandatory }}
template = /etc/log2mail/mail
diff --git a/nagios-nrpe/README.md b/nagios-nrpe/README.md
new file mode 100644
index 00000000..05de2d6c
--- /dev/null
+++ b/nagios-nrpe/README.md
@@ -0,0 +1,13 @@
+# nagios-nrpe
+
+Install Nagios NRPE server.
+
+## Tasks
+
+Everything is in the `tasks/main.yml` file.
+
+## Available variables
+
+* `nagios_nrpe_allowed_hosts` : list of IP/hosts authorized (default: none).
+
+The full list of variables (with default values) can be found in `defaults/main.yml`.
diff --git a/nagios-nrpe/defaults/main.yml b/nagios-nrpe/defaults/main.yml
new file mode 100644
index 00000000..4ad1e504
--- /dev/null
+++ b/nagios-nrpe/defaults/main.yml
@@ -0,0 +1,7 @@
+---
+nagios_nrpe_allowed_hosts: []
+nagios_nrpe_ldap_dc: "dc=DOMAIN,dc=EXT"
+nagios_nrpe_ldap_passwd: LDAP_PASSWD
+nagios_nrpe_pgsql_passwd: PGSQL_PASSWD
+nagios_nrpe_mysql_passwd: MYSQL_PASSWD
+nagios_nrpe_amavis_from: "foobar@{{ ansible_domain }}"
diff --git a/nagios-nrpe/files/plugins/check_amavis b/nagios-nrpe/files/plugins/check_amavis
new file mode 100755
index 00000000..43e69bcb
--- /dev/null
+++ b/nagios-nrpe/files/plugins/check_amavis
@@ -0,0 +1,72 @@
+#!/usr/bin/perl
+
+use Getopt::Long;
+use MIME::Entity;
+use Net::SMTP;
+
+my $server = '';
+my $port = 10024;
+my $from = '';
+my $to = '';
+my $debug = 0;
+
+$result = GetOptions (
+ "server|s=s" => \$server,
+ "port|p=s" => \$port,
+ "from|f=s" => \$from,
+ "debug|d" => \$debug,
+ "to|t=s" => \$to,
+);
+
+if (!$server || !$from) {
+ die ("Please specify server, from\n");
+}
+
+if (!$to) { $to = $from; }
+
+my $EICAR = <<'EOF';
+X5O!P%@AP[4\PZX54(P^)7CC)7}$EICAR-STANDARD-ANTIVIRUS-TEST-FILE!$H+H*
+EOF
+
+my $top = MIME::Entity->build(
+ Type =>"multipart/mixed",
+ From => $from,
+ To => $to,
+ Subject => "EICAR test",
+ Data => "This is a test",
+);
+
+$top->attach(
+ Data => $EICAR,
+ Type => "application/x-msdos-program",
+ Encoding => "base64");
+
+my $smtp = new Net::SMTP(
+ $server,
+ Port => $port,
+ Debug => $debug,
+);
+
+if (!$smtp) {
+ print "CRITICAL - amavisd-new server unreachable\n";
+ exit 2;
+}
+
+$smtp->mail($from);
+$smtp->to($to);
+$smtp->data();
+$smtp->datasend($top->stringify);
+$smtp->dataend();
+my $result = $smtp->message();
+$smtp->close();
+
+print "$result\n";
+
+if ($result =~/2.7.0 Ok, discarded/) {
+ print "OK - All fine\n";
+ exit 0;
+} else {
+ print "CRITICAL - amavisd-new returned $result";
+ exit 2;
+}
+
diff --git a/nagios-nrpe/files/plugins/check_cpu b/nagios-nrpe/files/plugins/check_cpu
new file mode 100755
index 00000000..a26fa61f
--- /dev/null
+++ b/nagios-nrpe/files/plugins/check_cpu
@@ -0,0 +1,219 @@
+#!/bin/bash
+# ========================================================================================
+# CPU Utilization Statistics plugin for Nagios
+#
+# Written by : Andreas Baess based on a script by Steve Bosek
+# Release : 1.1
+# Creation date : 3 May 2008
+# Package : DTB Nagios Plugin
+# Description : Nagios plugin (script) to check cpu utilization statistics.
+# This script has been designed and written on Unix plateform (Linux, Aix, Solaris),
+# requiring iostat as external program. The locations of these can easily
+# be changed by editing the variables $IOSTAT at the top of the script.
+# The script is used to query 4 of the key cpu statistics (user,system,iowait,idle)
+# at the same time.
+#
+# Usage : ./check_cpu.sh [-w ] [-c ] [-uc ]
+# [-sw ] [-sc ]
+# [-iw ] [-ic ]
+# [-i ] [-n ]
+# ----------------------------------------------------------------------------------------
+# ========================================================================================
+#
+# HISTORY :
+# Release | Date | Authors | Description
+# --------------+---------------+---------------+------------------------------------------
+# 1.1 | 03.05.08 | Andreas Baess | Changed script to use vmstat on Linux because
+# | | | iostat does not use integers
+# | | | Fixed output to display the IO-wait warning threshhold
+# --------------+---------------+---------------+------------------------------------------
+# 1.0 | 03.05.08 | Andreas Baess | Changed script so that thresholds are global
+# | | | and output can be parsed by perfprocessing
+# | | | changed default warning to 70 critical to 90
+# =========================================================================================
+
+# Paths to commands used in this script. These may have to be modified to match your system setup.
+
+IOSTAT=/usr/bin/iostat
+
+# Nagios return codes
+STATE_OK=0
+STATE_WARNING=1
+STATE_CRITICAL=2
+STATE_UNKNOWN=3
+
+# Plugin parameters value if not define
+WARNING_THRESHOLD=${WARNING_THRESHOLD:="70"}
+CRITICAL_THRESHOLD=${CRITICAL_THRESHOLD:="90"}
+INTERVAL_SEC=${INTERVAL_SEC:="1"}
+NUM_REPORT=${NUM_REPORT:="3"}
+U_CPU_W=${WARNING_THRESHOLD}
+S_CPU_W=${WARNING_THRESHOLD}
+IO_CPU_W=${WARNING_THRESHOLD}
+U_CPU_C=${CRITICAL_THRESHOLD}
+S_CPU_C=${CRITICAL_THRESHOLD}
+IO_CPU_C=${CRITICAL_THRESHOLD}
+
+# Plugin variable description
+PROGNAME=$(basename $0)
+RELEASE="Revision 1.0"
+AUTHOR="by Andreas Baess based on a work from Steve Bosek (sbosek@mac.com)"
+
+if [ ! -x $IOSTAT ]; then
+ echo "UNKNOWN: iostat not found or is not executable by the nagios user."
+ exit $STATE_UNKNOWN
+fi
+
+# Functions plugin usage
+print_release() {
+ echo "$RELEASE $AUTHOR"
+}
+
+print_usage() {
+ echo ""
+ echo "$PROGNAME $RELEASE - CPU Utilization check script for Nagios"
+ echo ""
+ echo "Usage: check_cpu.sh [flags]"
+ echo ""
+ echo "Flags:"
+ echo " -w : Global Warning level in % for user/system/io-wait cpu"
+ echo " -uw : Warning level in % for user cpu"
+ echo " -iw : Warning level in % for IO_wait cpu"
+ echo " -sw : Warning level in % for system cpu"
+ echo " -c : Global Critical level in % for user/system/io-wait cpu"
+ echo " -uc : Critical level in % for user cpu"
+ echo " -ic : Critical level in % for IO_wait cpu"
+ echo " -sc : Critical level in % for system cpu"
+ echo " -i : Interval in seconds for iostat (default : 1)"
+ echo " -n : Number report for iostat (default : 3)"
+ echo " -h Show this page"
+ echo ""
+ echo "Usage: $PROGNAME"
+ echo "Usage: $PROGNAME --help"
+ echo ""
+}
+
+print_help() {
+ print_usage
+ echo ""
+ echo "This plugin will check cpu utilization (user,system,iowait,idle in %)"
+ echo ""
+ exit 0
+}
+
+# Parse parameters
+while [ $# -gt 0 ]; do
+ case "$1" in
+ -h | --help)
+ print_help
+ exit $STATE_OK
+ ;;
+ -v | --version)
+ print_release
+ exit $STATE_OK
+ ;;
+ -w | --warning)
+ shift
+ WARNING_THRESHOLD=$1
+ U_CPU_W=$1
+ S_CPU_W=$1
+ IO_CPU_W=$1
+ ;;
+ -c | --critical)
+ shift
+ CRITICAL_THRESHOLD=$1
+ U_CPU_C=$1
+ S_CPU_C=$1
+ IO_CPU_C=$1
+ ;;
+ -uw | --uwarn)
+ shift
+ U_CPU_W=$1
+ ;;
+ -uc | --ucrit)
+ shift
+ U_CPU_C=$1
+ ;;
+ -sw | --swarn)
+ shift
+ S_CPU_W=$1
+ ;;
+ -sc | --scrit)
+ shift
+ S_CPU_C=$1
+ ;;
+ -iw | --iowarn)
+ shift
+ IO_CPU_W=$1
+ ;;
+ -ic | --iocrit)
+ shift
+ IO_CPU_C=$1
+ ;;
+ -i | --interval)
+ shift
+ INTERVAL_SEC=$1
+ ;;
+ -n | --number)
+ shift
+ NUM_REPORT=$1
+ ;;
+ *) echo "Unknown argument: $1"
+ print_usage
+ exit $STATE_UNKNOWN
+ ;;
+ esac
+shift
+done
+
+# CPU Utilization Statistics Unix Plateform ( Linux,AIX,Solaris are supported )
+case `uname` in
+# Linux ) CPU_REPORT=`iostat -c $INTERVAL_SEC $NUM_REPORT | tr -s ' ' ';' | sed '/^$/d' | tail -1`
+# CPU_USER=`echo $CPU_REPORT | cut -d ";" -f 2`
+# CPU_SYSTEM=`echo $CPU_REPORT | cut -d ";" -f 4`
+# CPU_IOWAIT=`echo $CPU_REPORT | cut -d ";" -f 5`
+# CPU_IDLE=`echo $CPU_REPORT | cut -d ";" -f 6`
+# ;;
+ AIX ) CPU_REPORT=`iostat -t $INTERVAL_SEC $NUM_REPORT | sed -e 's/,/./g'|tr -s ' ' ';' | tail -1`
+ CPU_USER=`echo $CPU_REPORT | cut -d ";" -f 4`
+ CPU_SYSTEM=`echo $CPU_REPORT | cut -d ";" -f 5`
+ CPU_IOWAIT=`echo $CPU_REPORT | cut -d ";" -f 7`
+ CPU_IDLE=`echo $CPU_REPORT | cut -d ";" -f 6`
+ ;;
+ Linux ) CPU_REPORT=`vmstat -n $INTERVAL_SEC $NUM_REPORT | tail -1`
+ CPU_USER=`echo $CPU_REPORT | awk '{ print $13 }'`
+ CPU_SYSTEM=`echo $CPU_REPORT | awk '{ print $14 }'`
+ CPU_IOWAIT=`echo $CPU_REPORT | awk '{ print $16 }'`
+ CPU_IDLE=`echo $CPU_REPORT | awk '{ print $15 }'`
+ ;;
+ SunOS ) CPU_REPORT=`iostat -c $INTERVAL_SEC $NUM_REPORT | tail -1`
+ CPU_USER=`echo $CPU_REPORT | awk '{ print $1 }'`
+ CPU_SYSTEM=`echo $CPU_REPORT | awk '{ print $2 }'`
+ CPU_IOWAIT=`echo $CPU_REPORT | awk '{ print $3 }'`
+ CPU_IDLE=`echo $CPU_REPORT | awk '{ print $4 }'`
+ ;;
+ *) echo "UNKNOWN: `uname` not yet supported by this plugin. Coming soon !"
+ exit $STATE_UNKNOWN
+ ;;
+ esac
+
+# Return
+
+# Are we in a critical state?
+if [ ${CPU_IOWAIT} -ge ${IO_CPU_C} -o ${CPU_USER} -ge ${U_CPU_C} -o ${CPU_SYSTEM} -ge ${S_CPU_C} ];
+then
+ echo "CPU CRITICAL : user=${CPU_USER}% system=${CPU_SYSTEM}% iowait=${CPU_IOWAIT}% idle=${CPU_IDLE}% | cpu_user=${CPU_USER}%;${U_CPU_W};${U_CPU_C}; cpu_sys=${CPU_SYSTEM}%;${S_CPU_W};${S_CPU_C}; cpu_iowait=${CPU_IOWAIT}%;${IO_CPU_W};${IO_CPU_C}; cpu_idle=${CPU_IDLE}%;"
+ exit $STATE_CRITICAL
+fi
+
+# Are we in a warning state?
+if [ ${CPU_IOWAIT} -ge ${IO_CPU_W} -o ${CPU_USER} -ge ${U_CPU_W} -o ${CPU_SYSTEM} -ge ${S_CPU_W} ];
+then
+ echo "CPU WARNING : user=${CPU_USER}% system=${CPU_SYSTEM}% iowait=${CPU_IOWAIT}% idle=${CPU_IDLE}% | cpu_user=${CPU_USER}%;${U_CPU_W};${U_CPU_C}; cpu_sys=${CPU_SYSTEM}%;${S_CPU_W};${S_CPU_C}; cpu_iowait=${CPU_IOWAIT}%;${IO_CPU_W};${IO_CPU_C}; cpu_idle=${CPU_IDLE}%;"
+ exit $STATE_WARNING
+fi
+
+# If we got this far, everything seems to be OK - IDLE has no threshold
+echo "CPU OK : user=${CPU_USER}% system=${CPU_SYSTEM}% iowait=${CPU_IOWAIT}% idle=${CPU_IDLE}% | cpu_user=${CPU_USER}%;${U_CPU_W};${U_CPU_C}; cpu_sys=${CPU_SYSTEM}%;${S_CPU_W};${S_CPU_C}; cpu_iowait=${CPU_IOWAIT}%;${IO_CPU_W};${IO_CPU_C}; cpu_idle=${CPU_IDLE}%;"
+exit $STATE_OK
diff --git a/nagios-nrpe/files/plugins/check_daemon b/nagios-nrpe/files/plugins/check_daemon
new file mode 100755
index 00000000..67e62c6c
--- /dev/null
+++ b/nagios-nrpe/files/plugins/check_daemon
@@ -0,0 +1,64 @@
+#!/bin/sh
+
+usage() {
+ cat <&2; exit 1; fi
+eval set -- "$TEMP"
+
+OPT_USER=""
+OPT_SANE=0
+OPT_UNIQ=0
+
+while true; do
+ case "$1" in
+ -u|--user) OPT_USER="$2" ; shift 2 ;;
+ -U|--uniq) OPT_UNIQ=1; shift ;;
+ -s|--sane) OPT_SANE=1; shift ;;
+ -h|--help) usage; exit 0 ;;
+ --) shift; break ;;
+ *) echo "Erreur interne"; exit -1 ;;
+ esac
+done
+
+ID_USER="`getent passwd $OPT_USER | cut -d: -f3`"
+
+if [ $# -ne 1 ]; then usage; exit -1; fi
+
+NAME="$1"
+STATUS=0
+RES="`ps n -eo pid,user,state,command | egrep "$NAME" | egrep "$ID_USER " | egrep -v "grep|$0"`"
+P_USER="` echo $RES | cut -d' ' -f2`"
+P_STATE="` echo $RES | cut -d' ' -f3`"
+
+if [ -n "$RES" ]; then
+ if [ -n "$OPT_USER" ]; then
+ if [ "`getent passwd $OPT_USER`" != "`getent passwd $P_USER`" ]; then
+ STATUS=2
+ fi
+ fi
+ if [ $OPT_SANE -eq 1 -a "$P_STATE" = "Z" ]; then
+ STATUS=2
+ fi
+ if [ $OPT_UNIQ -eq 1 ]; then
+ if [ `echo -e "$RES" |wc -l` -gt 1 ]; then
+ STATUS=2
+ fi
+ fi
+else
+ STATUS=2
+fi
+
+[ $STATUS -eq 0 ] && echo "$NAME running"
+
+exit $STATUS
diff --git a/nagios-nrpe/files/plugins/check_drbd b/nagios-nrpe/files/plugins/check_drbd
new file mode 100755
index 00000000..aeda397a
--- /dev/null
+++ b/nagios-nrpe/files/plugins/check_drbd
@@ -0,0 +1,456 @@
+#!/usr/bin/perl -w
+
+####################################################
+# check_drbd v0.5.3 #
+# by Brandon Lee Poyner bpoyner / CCAC.edu #
+####################################################
+
+use strict;
+use File::Basename;
+use Getopt::Long;
+
+my $drbd_proc='/proc/drbd';
+my $drbd_devices=0;
+my ($drbd_expect, $drbd_role, $drbd_version, $debug_mode);
+my (%options, %cs, %st, %ld, %ds, %check, %warning, %critical);
+
+my $prog_name=basename($0);
+my $prog_revision='0.5.3';
+
+my %errorcodes = (
+ 'OK' => { 'retvalue' => 0 },
+ 'WARNING' => { 'retvalue' => 1 },
+ 'CRITICAL' => { 'retvalue' => 2 },
+ 'UNKNOWN' => { 'retvalue' => 3 }
+);
+
+#
+# Define various states and default alarm values
+#
+my %state = (
+ 'Primary' => { 'value' => 'OK', 'type' => 'st' },
+ 'Secondary' => { 'value' => 'OK', 'type' => 'st' },
+ 'Unknown' => { 'value' => 'CRITICAL', 'type' => 'st' },
+ 'StandAlone' => { 'value' => 'WARNING', 'type' => 'cs' },
+ 'Unconnected' => { 'value' => 'CRITICAL', 'type' => 'cs' },
+ 'Timeout' => { 'value' => 'CRITICAL', 'type' => 'cs' },
+ 'BrokenPipe' => { 'value' => 'CRITICAL', 'type' => 'cs' },
+ 'WFConnection' => { 'value' => 'CRITICAL', 'type' => 'cs' },
+ 'WFReportParams' => { 'value' => 'CRITICAL', 'type' => 'cs' },
+ 'Connected' => { 'value' => 'OK', 'type' => 'cs' },
+ 'Unconfigured' => { 'value' => 'CRITICAL', 'type' => 'cs' },
+ # DRBD 0.6
+ 'SyncingAll' => { 'value' => 'WARNING', 'type' => 'cs' },
+ 'SyncingQuick' => { 'value' => 'WARNING', 'type' => 'cs' },
+ 'SyncPaused' => { 'value' => 'CRITICAL', 'type' => 'cs' },
+ # DRBD 0.7
+ 'WFBitMapS' => { 'value' => 'CRITICAL', 'type' => 'cs' },
+ 'WFBitMapT' => { 'value' => 'CRITICAL', 'type' => 'cs' },
+ 'SyncSource' => { 'value' => 'WARNING', 'type' => 'cs' },
+ 'SyncTarget' => { 'value' => 'WARNING', 'type' => 'cs' },
+ 'PausedSyncS' => { 'value' => 'CRITICAL', 'type' => 'cs' },
+ 'PausedSyncT' => { 'value' => 'CRITICAL', 'type' => 'cs' },
+ 'NetworkFailure' => { 'value' => 'CRITICAL', 'type' => 'cs' },
+ 'SkippedSyncS' => { 'value' => 'CRITICAL', 'type' => 'cs' },
+ 'SkippedSyncT' => { 'value' => 'CRITICAL', 'type' => 'cs' },
+ 'Consistent' => { 'value' => 'OK', 'type' => 'ld' },
+ 'Inconsistent' => { 'value' => 'CRITICAL', 'type' => 'ld' },
+ # DRBD 8.0
+ 'UpToDate' => { 'value' => 'OK', 'type' => 'ds' },
+ 'Consistent' => { 'value' => 'OK', 'type' => 'ds' },
+ 'Negotiating' => { 'value' => 'WARNING', 'type' => 'ds' },
+ 'Attaching' => { 'value' => 'WARNING', 'type' => 'ds' },
+ 'Diskless' => { 'value' => 'CRITICAL', 'type' => 'ds' },
+ 'Failed' => { 'value' => 'CRITICAL', 'type' => 'ds' },
+ 'Outdated' => { 'value' => 'CRITICAL', 'type' => 'ds' },
+ 'Inconsistent' => { 'value' => 'CRITICAL', 'type' => 'ds' },
+ 'DUnknown' => { 'value' => 'CRITICAL', 'type' => 'ds' },
+ # DRBD 8.2
+ 'VerifyS' => { 'value' => 'WARNING', 'type' => 'cs' },
+ 'VerifyT' => { 'value' => 'WARNING', 'type' => 'cs' },
+ # DRBD 8.3
+ 'Disconnecting' => { 'value' => 'WARNING', 'type' => 'cs' },
+ 'ProtocolError' => { 'value' => 'CRITICAL', 'type' => 'cs' },
+ 'TearDown' => { 'value' => 'WARNING', 'type' => 'cs' },
+ 'StartingSyncS' => { 'value' => 'WARNING', 'type' => 'cs' },
+ 'StartingSyncT' => { 'value' => 'WARNING', 'type' => 'cs' },
+ 'WFSyncUUID' => { 'value' => 'WARNING', 'type' => 'cs' }
+);
+
+&parse_options;
+&parse_proc;
+&parse_drbd_devices;
+&check_drbd_state;
+&report_status;
+&myexit('UNKNOWN',"$prog_name should never reach here");
+
+sub print_usage {
+ print <] [-e expect] [-p proc] [-r role] [-o states] [-w states] [-c states] [--debug]
+ Options:
+ -d STRING [default: $drbd_devices. Example: 0,1,2 ]
+ -p STRING [default: $drbd_proc. Use '-' for stdin]
+ -e STRING [Must be this connected state. Example: Connected]
+ -r STRING [Must be this node state. Example: Primary]
+ -o STRING [Change value to OK. Example: StandAlone]
+ -w STRING [Change value to WARNING. Example: SyncingAll]
+ -c STRING [Change value to CRITICAL. Example: Inconsistent,WFConnection]
+EOF
+}
+
+sub print_revision {
+ print <{'retvalue'};
+}
+
+sub parse_options {
+ my ($help, $version, $debug, $ok_string, $warning_string,
+ $critical_string);
+ #
+ # Get command line options
+ #
+ GetOptions("h|help" => \$help,
+ "V|version" => \$version,
+ "d|device|devices=s" => \$drbd_devices,
+ "e|expect=s" => \$drbd_expect,
+ "p|proc=s" => \$drbd_proc,
+ "r|role=s" => \$drbd_role,
+ "o|ok=s" => \$ok_string,
+ "w|warning=s" => \$warning_string,
+ "c|critical=s" => \$critical_string,
+ "debug" => \$debug);
+ if (defined($help) && ($help ne "")) {
+ &print_help;
+ exit $errorcodes{'UNKNOWN'}->{'retvalue'};
+ }
+ if (defined($version) && ($version ne "")) {
+ &print_revision;
+ exit $errorcodes{'UNKNOWN'}->{'retvalue'};
+ }
+ if (defined($drbd_expect) && ($drbd_expect ne "")) {
+ # User requested the connected state to be very specific
+ &change_values($drbd_expect,'cs','expect','connected state');
+ }
+ if (defined($drbd_role) && ($drbd_role ne "")) {
+ # User requested the node state to be very specific
+ &change_values($drbd_role,'st','role','node state');
+ }
+ if (defined($ok_string) && ($ok_string ne "")) {
+ # User requested certain values to be OK
+ &set_values($ok_string,'OK');
+ }
+ if (defined($warning_string) && ($warning_string ne "")) {
+ # User requested certain values to be WARNING
+ &set_values($warning_string,'WARNING');
+ }
+ if (defined($critical_string) && ($critical_string ne "")) {
+ # User requested certain values to be CRITICAL
+ &set_values($critical_string,'CRITICAL');
+ }
+ if (defined($debug) && ($debug ne "")) {
+ #
+ # Debugging information
+ #
+ $debug_mode=1;
+ print STDERR "<$prog_name settings>\n";
+ print STDERR "DRBD Devices: $drbd_devices\n";
+ printf STDERR "DRBD Proc: %s\n", defined($drbd_proc)?$drbd_proc:"";
+ printf STDERR "DRBD Expect: %s\n", defined($drbd_expect)?$drbd_expect:"";
+ printf STDERR "DRBD Role: %s\n", defined($drbd_role)?$drbd_role:"";
+ my (@ok, @critical, @warning);
+ for my $key ( keys %state ) {
+ if ($state{$key}->{'value'} eq 'OK') {
+ push(@ok,$key);
+ }
+ if ($state{$key}->{'value'} eq 'WARNING') {
+ push(@warning,$key);
+ }
+ if ($state{$key}->{'value'} eq 'CRITICAL') {
+ push(@critical,$key);
+ }
+ }
+ printf STDERR "DRBD OK: %s\n", join(" ",sort(@ok));
+ printf STDERR "DRBD WARNING: %s\n", join(" ",sort(@warning));
+ printf STDERR "DRBD CRITICAL: %s\n", join(" ",sort(@critical));
+ print STDERR "$prog_name settings>\n";
+ }
+}
+
+sub parse_proc {
+ #
+ # Read in contents of proc file, feed results into hashes
+ #
+ my $input;
+ if ( $drbd_proc ne "-" ) {
+ $input = "DRBD";
+ if ( ! -e $drbd_proc ) {
+ &myexit('UNKNOWN',"No such file $drbd_proc");
+ }
+ open(DRBD, "$drbd_proc") ||
+ &myexit('UNKNOWN',"Could not open $drbd_proc");
+ } else {
+ $input = "STDIN";
+ }
+ while(<$input>) {
+ if (/^version: (\d+).(\d+)/) {
+ $drbd_version = "$1.$2";
+ }
+ if (/^\s?(\d+):.* cs:(\w+)/) {
+ $cs{$1} = $2;
+ }
+ if (/^\s?(\d+):.* st:(\w+)\//) {
+ $st{$1} = $2;
+ }
+ if (/^\s?(\d+):.* ld:(\w+)/) {
+ $ld{$1} = $2;
+ }
+ if (/^\s?(\d+):.* ds:(\w+)/) {
+ $ds{$1} = $2;
+ }
+ }
+ if ( $drbd_proc ne "-" ) {
+ close(DRBD);
+ }
+ if (defined($debug_mode) && ($debug_mode == 1)) {
+ #
+ # Debugging information
+ #
+ print STDERR "<$prog_name devices found>\n";
+ for my $key ( sort keys %cs ) {
+ printf STDERR "Found Device $key $cs{$key}%s%s%s\n", defined($st{$key})?" $st{$key}":"", defined($ld{$key})?" $ld{$key}":"", defined($ds{$key})?" $ds{$key}":"";
+ }
+ print STDERR "$prog_name devices found>\n";
+ }
+}
+
+sub parse_drbd_devices {
+ #
+ # Determine which DRBD devices to monitor
+ #
+ my @devices;
+ if ($drbd_devices =~ /^all$/i) {
+ for my $device ( keys %cs ) {
+ push(@devices,$device);
+ }
+ } elsif ($drbd_devices =~ /^configured$/i) {
+ for my $device ( keys %cs ) {
+ next if ($cs{$device} eq "Unconfigured");
+ push(@devices,$device);
+ }
+ } else {
+ @devices = split(/,/,$drbd_devices);
+ }
+ foreach my $device (@devices) {
+ if (!(defined($cs{$device}))) {
+ &myexit('UNKNOWN',"Could not find device $device");
+ }
+ $check{$device} = 1;
+ }
+ if (int(keys %check) == 0) {
+ &myexit('UNKNOWN',"No configured devices found");
+ }
+ if (defined($debug_mode) && ($debug_mode == 1)) {
+ #
+ # Debugging information
+ #
+ print STDERR "<$prog_name devices to check>\n";
+ for my $key ( sort keys %check ) {
+ printf STDERR "Checking enabled for device $key\n";
+ }
+ print STDERR "$prog_name devices to check>\n";
+ }
+}
+
+sub check_drbd_state {
+ for my $drbd_device ( sort keys %check ) {
+ if ((defined($drbd_version)) && ($drbd_version >= '8.0')) {
+ #
+ # We're dealing with version 8.0 or greater
+ # Set data state
+ #
+ if ((defined($ds{$drbd_device})) &&
+ (defined($state{$ds{$drbd_device}}))) {
+ $state{$ds{$drbd_device}}->{$drbd_device}->{'level'} = 1;
+ } elsif (defined($ds{$drbd_device})) {
+ &myexit('CRITICAL',"Data state unknown value '$ds{$drbd_device}' for device $drbd_device");
+ }
+ }
+ if ((defined($drbd_version)) && ($drbd_version == '0.7')) {
+ #
+ # We're dealing with version 0.7
+ # Set local data consistency
+ #
+ if ((defined($ld{$drbd_device})) &&
+ (defined($state{$ld{$drbd_device}}))) {
+ $state{$ld{$drbd_device}}->{$drbd_device}->{'level'} = 1;
+ } elsif (defined($ld{$drbd_device})) {
+ &myexit('CRITICAL',"Local data consistency unknown value '$ld{$drbd_device}' for device $drbd_device");
+ }
+ }
+ #
+ # Check for a state value (Primary, Secondary, etc)
+ #
+ if ((defined($st{$drbd_device})) &&
+ (defined($state{$st{$drbd_device}}))) {
+ $state{$st{$drbd_device}}->{$drbd_device}->{'level'} = 1;
+ } elsif (defined($st{$drbd_device})) {
+ &myexit('CRITICAL',"Node state unknown value '$st{$drbd_device}' for device $drbd_device");
+ }
+ #
+ # Check for a connected state value (Connected, StandAlone, etc)
+ #
+ if (defined($state{$cs{$drbd_device}})) {
+ $state{$cs{$drbd_device}}->{$drbd_device}->{'level'} = 1;
+ } else {
+ &myexit('CRITICAL',"Connection state unknown value '$cs{$drbd_device}' for device $drbd_device");
+ }
+ #
+ # Debugging information
+ #
+ if (defined($debug_mode) && ($debug_mode == 1)) {
+ print STDERR "<$prog_name device $drbd_device status>\n";
+ for my $key ( keys %state ) {
+ if (defined($state{$key}->{$drbd_device}->{'level'})) {
+ print STDERR "$key $state{$key}->{'value'}\n";
+ }
+ }
+ print STDERR "$prog_name device $drbd_device status>\n";
+ }
+ #
+ # Determine if any values are CRITICAL or WARNING
+ #
+ for my $key ( keys %state ) {
+ if (defined($state{$key}->{$drbd_device}->{'level'})) {
+ if ($state{$key}->{'value'} eq "CRITICAL") {
+ $critical{$drbd_device} = 1;
+ }
+ if ($state{$key}->{'value'} eq "WARNING") {
+ $warning{$drbd_device} = 1;
+ }
+ }
+ }
+ }
+}
+
+sub report_status {
+ my $message;
+ my $critical_count=int(keys %critical);
+ my $warning_count=int(keys %warning);
+ if ($critical_count > 0) {
+ #
+ # We found a CRITICAL situation
+ #
+ my $i = 0;
+ for my $device (sort keys %critical) {
+ $message.=sprintf("Device %d%s $cs{$device}%s%s", $device,defined($st{$device})?" $st{$device}":"",defined($ld{$device})?" $ld{$device}":"",defined($ds{$device})?" $ds{$device}":"");
+ $i++;
+ if ($i != $critical_count) {
+ $message.=", ";
+ }
+ }
+ &myexit('CRITICAL',$message);
+ } elsif ($warning_count > 0) {
+ #
+ # We found a WARNING situation
+ #
+ my $i = 0;
+ for my $device (sort keys %warning) {
+ $message.=sprintf("Device %d%s $cs{$device}%s%s", $device,defined($st{$device})?" $st{$device}":"",defined($ld{$device})?" $ld{$device}":"",defined($ds{$device})?" $ds{$device}":"");
+ $i++;
+ if ($i != $warning_count) {
+ $message.=", ";
+ }
+ }
+ &myexit('WARNING',$message);
+ } else {
+ #
+ # Everything checks out OK
+ #
+ my $device_count=int(keys %check);
+ if ($device_count == 1) {
+ for my $device ( sort keys %check ) {
+ $message=sprintf("Device %d%s $cs{$device}%s%s", $device,defined($st{$device})?" $st{$device}":"",defined($ld{$device})?" $ld{$device}":"",defined($ds{$device})?" $ds{$device}":"");
+ }
+ } else {
+ my $i = 0;
+ for my $device ( sort keys %check ) {
+ $message.=sprintf("Dev %d %0.3s%0.3s%0.3s%0.3s", $device,defined($st{$device})?"$st{$device}":"",$cs{$device},defined($ld{$device})?"$ld{$device}":"",defined($ds{$device})?"$ds{$device}":"");
+ $i++;
+ if ($i != $device_count) {
+ $message.=", ";
+ }
+ }
+ }
+ &myexit('OK',$message);
+ }
+}
+
+sub set_values {
+ #
+ # Set item to value requested
+ #
+ my ($items,$value) = @_;
+ my @items = split(/,/,$items);
+ foreach my $item (@items) {
+ if (defined($state{$item})) {
+ $state{$item}->{'value'} = "$value";
+ } else {
+ print STDERR "State '$item' not found\n";
+ }
+ }
+}
+
+sub change_values {
+ #
+ # Look for all values of a given type, set requested value to OK
+ # and all other values to CRITICAL
+ #
+ my ($argument,$type,$error1,$error2) = @_;
+ if ((defined($state{$argument})) &&
+ ($state{$argument}->{'type'} eq "$type")) {
+ for my $key ( keys %state ) {
+ if ($state{$key}->{'type'} eq "$type") {
+ if ($key eq $argument) {
+ &set_values($argument,'OK');
+ } else {
+ &set_values($key,'CRITICAL');
+ }
+ }
+ }
+ } else {
+ &myexit('UNKNOWN',"$error1 option only works for $error2");
+ }
+}
+
+sub myexit {
+ #
+ # Print error message and exit
+ #
+ my ($error, $message) = @_;
+ if (!(defined($errorcodes{$error}))) {
+ printf STDERR "Error code $error not known\n";
+ print "DRBD UNKNOWN: $message\n";
+ exit $errorcodes{'UNKNOWN'}->{'retvalue'};
+ }
+ print "DRBD $error: $message\n";
+ exit $errorcodes{$error}->{'retvalue'};
+}
diff --git a/nagios-nrpe/files/plugins/check_evobackup b/nagios-nrpe/files/plugins/check_evobackup
new file mode 100755
index 00000000..d45b3c58
--- /dev/null
+++ b/nagios-nrpe/files/plugins/check_evobackup
@@ -0,0 +1,10 @@
+#!/bin/sh
+ports="2222 2223"
+
+for port in $ports; do
+ /usr/lib/nagios/plugins/check_ssh -p $port localhost
+ exitCode=$?
+ [ $exitCode -ne 0 ] && exit $exitCode
+done
+
+exit 0
diff --git a/nagios-nrpe/files/plugins/check_fs b/nagios-nrpe/files/plugins/check_fs
new file mode 100755
index 00000000..4dc07338
--- /dev/null
+++ b/nagios-nrpe/files/plugins/check_fs
@@ -0,0 +1,146 @@
+#!/bin/bash
+
+TUNE2FS="/sbin/tune2fs"
+
+MOUNT_MAX=14
+INTERVAL_MAX=200
+MAIL_ALERT="alert3@evolix.fr"
+
+PROGNAME=`/usr/bin/basename $0`
+
+# Nagios compatibility
+STATE_OK=0
+STATE_WARNING=1
+STATE_CRITICAL=2
+STATE_UNKNOWN=3
+STATE_DEPENDENT=4
+
+print_usage() {
+ echo "Usage: $PROGNAME --dev /dev/sdaX [--mount-max $MOUNT_MAX] [--interval-max $INTERVAL_MAX] [--alert]"
+ echo "Usage: $PROGNAME -d /dev/sdaX [-c $MOUNT_MAX] [-i $INTERVAL_MAX] [-a]"
+ echo "Usage: $PROGNAME --help"
+}
+
+print_help() {
+ print_usage
+ echo ""
+ echo "Options:"
+ echo "--dev, -d /dev/sdNX"
+ echo "--mount-max, -c X"
+ echo "--interval-max, -i X (days)"
+ echo "--alert, -a (send a mail to $MAIL_ALERT if state critical)"
+}
+
+alert_mail() {
+# $1 max_mount
+# $2 days
+
+ if [ "$send_mail" = "1" ]; then
+ if [ "$exitstatus" = "$STATE_CRITICAL" ]; then
+ echo "From: Equipe Evolix
+To: $MAIL_ALERT
+Subject: [alert] Fsck on $(hostname)
+
+Number of mount since last fsck: $1
+Days since last fsck: $2
+
+"|/usr/lib/sendmail -oi -t -f "$MAIL_ALERT"
+ fi
+ fi
+}
+
+send_mail=0
+exitstatus=$STATE_OK
+
+# check command line arguments
+
+if [ $# -lt 1 ]; then
+ print_usage
+ exit $STATE_UNKNOWN
+fi
+
+while test -n "$1"; do
+ case "$1" in
+ --help)
+ print_help
+ exit $STATE_OK
+ ;;
+ -h)
+ print_help
+ exit $STATE_OK
+ ;;
+ --dev)
+ dev=$2
+ shift
+ ;;
+ -d)
+ dev=$2
+ shift
+ ;;
+ --mount-max)
+ mount_max=$2
+ shift
+ ;;
+ -c)
+ mount_max=$2
+ shift
+ ;;
+ --interval-max)
+ interval_max=$2
+ shift
+ ;;
+ -i)
+ interval_max=$2
+ shift
+ ;;
+ --alert)
+ send_mail=1
+ ;;
+ -a)
+ send_mail=1
+ ;;
+ *)
+ echo "Unknown argument: $1"
+ print_usage
+ exit $STATE_UNKNOWN
+ ;;
+ esac
+ shift
+done
+
+[ -z "$dev" ] && print_usage && exit $STATE_UNKNOWN
+[ -z "$mount_max" ] && mount_max=$MOUNT_MAX
+[ -z "$interval_max" ] && interval_max=$INTERVAL_MAX
+
+# is $dev support tune2fs ?
+bad_magic=$($TUNE2FS -l $dev|grep "Bad magic number")
+[ -n "$bad_magic" ] && echo "Bad magic number in super-block while trying to open $dev" && exit $STATE_UNKNOWN
+
+# grep max_count && last_checked
+max_count=$($TUNE2FS -l $dev|grep "Mount count" | awk -F":" '{ print $2 }'| sed 's/^\s*//')
+last_checked=$($TUNE2FS -l $dev|grep "Last checked"| awk -F":" '{ print $2":"$3":"$4 }'|sed 's/^\s*//')
+
+[ -z "$max_count" ] && echo "No Mount count value on $TUNE2FS $dev" && exit $STATE_UNKNOWN
+[ -z "$last_checked" ] && echo "No Last checked value on $TUNE2FS $dev" && exit $STATE_UNKNOWN
+
+# check max mount
+if [ $max_count -ge $mount_max ]; then
+ echo "Number of mount since last fsck: $max_count"
+ echo " - threshold $mount_max reached !\n"
+ exitstatus=$STATE_CRITICAL;
+fi
+
+# compute day interval
+timestamp=$( date -d "$last_checked" "+%s" )
+today=$( date "+%s" )
+days=$(( ($today - $timestamp) / 86400 ))
+
+if [ $days -ge $interval_max ]; then
+ echo "Days since last fsck: $days"
+ echo " - threshold $interval_max reached !\n"
+ exitstatus=$STATE_CRITICAL;
+fi
+
+alert_mail $max_count $days
+
+exit $exitstatus
diff --git a/nagios-nrpe/files/plugins/check_glusterfs b/nagios-nrpe/files/plugins/check_glusterfs
new file mode 100755
index 00000000..b933fc33
--- /dev/null
+++ b/nagios-nrpe/files/plugins/check_glusterfs
@@ -0,0 +1,150 @@
+#!/bin/bash
+
+# This Nagios script was written against version 3.3 & 3.4 of Gluster. Older
+# versions will most likely not work at all with this monitoring script.
+#
+# Gluster currently requires elevated permissions to do anything. In order to
+# accommodate this, you need to allow your Nagios user some additional
+# permissions via sudo. The line you want to add will look something like the
+# following in /etc/sudoers (or something equivalent):
+#
+# Defaults:nagios !requiretty
+# nagios ALL=(root) NOPASSWD:/usr/sbin/gluster volume status [[\:graph\:]]* detail,/usr/sbin/gluster volume heal [[\:graph\:]]* info
+#
+# That should give us all the access we need to check the status of any
+# currently defined peers and volumes.
+
+# Inspired by a script of Mark Nipper
+#
+# 2013, Mark Ruys, mark.ruys@peercode.nl
+
+PATH=/sbin:/bin:/usr/sbin:/usr/bin
+
+PROGNAME=$(basename -- $0)
+PROGPATH=`echo $0 | sed -e 's,[\\/][^\\/][^\\/]*$,,'`
+REVISION="1.0.0"
+
+. /usr/lib/nagios/plugins/utils.sh
+
+# parse command line
+usage () {
+ echo ""
+ echo "USAGE: "
+ echo " $PROGNAME -v VOLUME -n BRICKS [-w GB -c GB]"
+ echo " -n BRICKS: number of bricks"
+ echo " -w and -c values in GB"
+ exit $STATE_UNKNOWN
+}
+
+while getopts "v:n:w:c:" opt; do
+ case $opt in
+ v) VOLUME=${OPTARG} ;;
+ n) BRICKS=${OPTARG} ;;
+ w) WARN=${OPTARG} ;;
+ c) CRIT=${OPTARG} ;;
+ *) usage ;;
+ esac
+done
+
+if [ -z "${VOLUME}" -o -z "${BRICKS}" ]; then
+ usage
+fi
+
+Exit () {
+ echo "$1: ${2:0}"
+ status=STATE_$1
+ exit ${!status}
+}
+
+# check for commands
+for cmd in basename bc awk sudo pidof gluster; do
+ if ! type -p "$cmd" >/dev/null; then
+ Exit UNKNOWN "$cmd not found"
+ fi
+done
+
+# check for glusterd (management daemon)
+if ! pidof glusterd &>/dev/null; then
+ Exit CRITICAL "glusterd management daemon not running"
+fi
+
+# check for glusterfsd (brick daemon)
+if ! pidof glusterfsd &>/dev/null; then
+ Exit CRITICAL "glusterfsd brick daemon not running"
+fi
+
+# get volume heal status
+heal=0
+for entries in $(sudo gluster volume heal ${VOLUME} info | awk '/^Number of entries: /{print $4}'); do
+ if [ "$entries" -gt 0 ]; then
+ let $((heal+=entries))
+ fi
+done
+if [ "$heal" -gt 0 ]; then
+ errors=("${errors[@]}" "$heal unsynched entries")
+fi
+
+# get volume status
+bricksfound=0
+freegb=9999999
+shopt -s nullglob
+while read -r line; do
+ field=($(echo $line))
+ case ${field[0]} in
+ Brick)
+ brick=${field[@]:2}
+ ;;
+ Disk)
+ key=${field[@]:0:3}
+ if [ "${key}" = "Disk Space Free" ]; then
+ freeunit=${field[@]:4}
+ free=${freeunit:0:-2}
+ unit=${freeunit#$free}
+ if [ "$unit" != "GB" ]; then
+ Exit UNKNOWN "unknown disk space size $freeunit"
+ fi
+ free=$(echo "${free} / 1" | bc -q)
+ if [ $free -lt $freegb ]; then
+ freegb=$free
+ fi
+ fi
+ ;;
+ Online)
+ online=${field[@]:2}
+ if [ "${online}" = "Y" ]; then
+ let $((bricksfound++))
+ else
+ errors=("${errors[@]}" "$brick offline")
+ fi
+ ;;
+ esac
+done < <(sudo gluster volume status ${VOLUME} detail)
+
+if [ $bricksfound -eq 0 ]; then
+ Exit CRITICAL "no bricks found"
+elif [ $bricksfound -lt $BRICKS ]; then
+ errors=("${errors[@]}" "found $bricksfound bricks, expected $BRICKS ")
+fi
+
+if [ -n "$CRIT" -a -n "$WARN" ]; then
+ if [ $CRIT -ge $WARN ]; then
+ Exit UNKNOWN "critical threshold below warning"
+ elif [ $freegb -lt $CRIT ]; then
+ Exit CRITICAL "free space ${freegb}GB"
+ elif [ $freegb -lt $WARN ]; then
+ errors=("${errors[@]}" "free space ${freegb}GB")
+ fi
+fi
+
+# exit with warning if errors
+if [ -n "$errors" ]; then
+ sep='; '
+ msg=$(printf "${sep}%s" "${errors[@]}")
+ msg=${msg:${#sep}}
+
+ Exit WARNING "${msg}"
+fi
+
+# exit with no errors
+Exit OK "${bricksfound} bricks; free space ${freegb}GB"
+
diff --git a/nagios-nrpe/files/plugins/check_haproxy_stats b/nagios-nrpe/files/plugins/check_haproxy_stats
new file mode 100755
index 00000000..e3e8ff4b
--- /dev/null
+++ b/nagios-nrpe/files/plugins/check_haproxy_stats
@@ -0,0 +1,225 @@
+#!/usr/bin/env perl
+# vim: se et ts=4:
+
+#
+# Copyright (C) 2012, Giacomo Montagner
+#
+# This program is free software; you can redistribute it and/or modify it
+# under the same terms as Perl 5.10.1.
+# For more details, see http://dev.perl.org/licenses/artistic.html
+#
+# 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.
+#
+
+our $VERSION = "1.0.1";
+
+# CHANGELOG:
+# 1.0.0 - first release
+# 1.0.1 - fixed empty message if all proxies are OK
+#
+
+use strict;
+use warnings;
+use 5.010.001;
+use File::Basename qw/basename/;
+use IO::Socket::UNIX;
+use Getopt::Long;
+
+sub usage {
+ my $me = basename $0;
+ print <.
+ $me is distributed under GPL and the Artistic License 2.0
+
+SEE ALSO
+ Check out online haproxy documentation at
+
+EOU
+}
+
+my %check_statuses = (
+ UNK => "unknown",
+ INI => "initializing",
+ SOCKERR => "socket error",
+ L4OK => "layer 4 check OK",
+ L4CON => "connection error",
+ L4TMOUT => "layer 1-4 timeout",
+ L6OK => "layer 6 check OK",
+ L6TOUT => "layer 6 (SSL) timeout",
+ L6RSP => "layer 6 protocol error",
+ L7OK => "layer 7 check OK",
+ L7OKC => "layer 7 conditionally OK",
+ L7TOUT => "layer 7 (HTTP/SMTP) timeout",
+ L7RSP => "layer 7 protocol error",
+ L7STS => "layer 7 status error",
+);
+
+my @status_names = (qw/OK WARNING CRITICAL UNKNOWN/);
+
+# Defaults
+my $swarn = 80.0;
+my $scrit = 90.0;
+my $sock = "/var/run/haproxy.sock";
+my $dump;
+my $proxy;
+my $help;
+
+# Read command line
+Getopt::Long::Configure ("bundling");
+GetOptions (
+ "c|critical=i" => \$scrit,
+ "d|dump" => \$dump,
+ "h|help" => \$help,
+ "p|proxy=s" => \$proxy,
+ "s|sock|socket=s" => \$sock,
+ "w|warning=i" => \$swarn,
+);
+
+# Want help?
+if ($help) {
+ usage;
+ exit 3;
+}
+
+# Connect to haproxy socket and get stats
+my $haproxy = new IO::Socket::UNIX (
+ Peer => $sock,
+ Type => SOCK_STREAM,
+);
+die "Unable to connect to haproxy socket: $@" unless $haproxy;
+print $haproxy "show stat\n" or die "Print to socket failed: $!";
+
+# Dump stats and exit if requested
+if ($dump) {
+ while (<$haproxy>) {
+ print;
+ }
+ exit 0;
+}
+
+# Get labels from first output line and map them to their position in the line
+my $labels = <$haproxy>;
+chomp($labels);
+$labels =~ s/^# // or die "Data format not supported.";
+my @labels = split /,/, $labels;
+{
+ no strict "refs";
+ my $idx = 0;
+ map { $$_ = $idx++ } @labels;
+}
+
+# Variables I will use from here on:
+our $pxname;
+our $svname;
+our $status;
+
+my @proxies = split ',', $proxy if $proxy;
+my $exitcode = 0;
+my $msg;
+my $checked = 0;
+while (<$haproxy>) {
+ chomp;
+ next if /^[[:space:]]*$/;
+ my @data = split /,/, $_;
+ if (@proxies) { next unless grep {$data[$pxname] eq $_} @proxies; };
+
+ # Is session limit enforced?
+ our $slim;
+ if ($data[$slim]) {
+ # Check current session # against limit
+ our $scur;
+ my $sratio = $data[$scur]/$data[$slim];
+ if ($sratio >= $scrit || $sratio >= $swarn) {
+ $exitcode = $sratio >= $scrit ? 2 :
+ $exitcode < 2 ? 1 : $exitcode;
+ $msg .= sprintf "%s:%s sessions: %.2f%%; ", $data[$pxname], $data[$svname], $sratio;
+ }
+ }
+
+ # Check of BACKENDS
+ if ($data[$svname] eq 'BACKEND') {
+ if ($data[$status] !~ '(UP|MAINT)') {
+ $msg .= sprintf "BACKEND: %s is %s; ", $data[$pxname], $data[$status];
+ $exitcode = 2;
+ }
+ # Check of FRONTENDS
+ } elsif ($data[$svname] eq 'FRONTEND') {
+ if ($data[$status] ne 'OPEN') {
+ $msg .= sprintf "FRONTEND: %s is %s; ", $data[$pxname], $data[$status];
+ $exitcode = 2;
+ }
+ # Check of servers
+ } else {
+ if ($data[$status] !~ '(UP|MAINT)') {
+ next if $data[$status] eq 'no check'; # Ignore server if no check is configured to be run
+ $exitcode = 2;
+ our $check_status;
+ $msg .= sprintf "server: %s:%s is %s", $data[$pxname], $data[$svname], $data[$status];
+ $msg .= sprintf " (check status: %s)", $check_statuses{$data[$check_status]} if $check_statuses{$data[$check_status]};
+ $msg .= "; ";
+ }
+ }
+ ++$checked;
+}
+
+unless ($msg) {
+ $msg = @proxies ? sprintf("checked proxies: %s", join ', ', sort @proxies) : "checked $checked proxies.";
+}
+say "Check haproxy $status_names[$exitcode] - $msg";
+exit $exitcode;
+
diff --git a/nagios-nrpe/files/plugins/check_http_many b/nagios-nrpe/files/plugins/check_http_many
new file mode 100644
index 00000000..90d8d9e2
--- /dev/null
+++ b/nagios-nrpe/files/plugins/check_http_many
@@ -0,0 +1,84 @@
+#!/bin/bash
+
+result=/tmp/nagios.check_http_many.result
+trap "rm ${result}*" EXIT
+warning=false
+critical=false
+
+check_state() {
+
+ if [[ $1 -eq 0 ]]; then
+ cat $result >> ${result}.ok
+ :> $result
+ fi
+ if [[ $1 -eq 1 ]]; then
+ warning=true
+ cat $result >> ${result}.err
+ :> $result
+ fi
+ if [[ $1 -eq 2 ]]; then
+ critical=true
+ cat $result >> ${result}.err
+ :> $result
+ fi
+
+}
+
+## Return OK between 02am and 05am.
+#date=$(date +%H)
+#if [[ $date > 01 && $date < 05 ]]; then
+# echo "Maintenance time, no check! All green!"
+# exit 0
+#fi
+
+# Check HTTP
+sites=""
+for site in $sites; do
+ echo -n "Site ${site}: " >> $result
+ /usr/lib/nagios/plugins/check_http -f critical -I 127.0.0.1 -H ${site%%/*} -u /${site#*/} >> $result
+ check_state $?
+done
+
+## Check HTTPs
+sites=""
+for site in $sites; do
+ echo -n "Site ${site}: " >> $result
+ /usr/lib/nagios/plugins/check_http -w4 -c6 -f critical -p 443 -S -I 127.0.0.1 -H ${site%%/*} -u /${site#*/} >> $result
+ check_state $?
+done
+
+# Check HTTPs certs
+sites=""
+for site in $sites; do
+ echo -n "Certificate ${site}: " >> $result
+ /usr/lib/nagios/plugins/check_http -p 443 -S --sni -H $site -C14,7 >> $result
+ check_state $?
+done
+
+# Check Sockets
+sockets=""
+for socket in $sockets; do
+ echo -n "Socket ${socket}: " >> $result
+ /usr/lib/nagios/plugins/check_tcp -H $socket >> $result
+ check_state $?0
+done
+
+# Check Ports
+ports=""
+for port in $ports; do
+ echo -n "Port ${port}: " >> $result
+ /usr/lib/nagios/plugins/check_tcp -p $port >> $result
+ check_state $?
+done
+
+if ($critical); then
+ cat ${result}.err
+ exit 2
+fi
+if ($warning); then
+ cat ${result}.err
+ exit 1
+else
+ cat ${result}.ok
+ exit 0
+fi
diff --git a/nagios-nrpe/files/plugins/check_iptables b/nagios-nrpe/files/plugins/check_iptables
new file mode 100755
index 00000000..1272936f
--- /dev/null
+++ b/nagios-nrpe/files/plugins/check_iptables
@@ -0,0 +1,29 @@
+#!/bin/sh
+
+usage() {
+
+ cat <&2
+Usage: $0 -w -c
+EOT
+}
+
+while getopts ':w:c:' o; do
+ case $o in
+ w)
+ warn=$OPTARG
+ ;;
+ c)
+ crit=$OPTARG
+ ;;
+ *)
+ usage
+ exit 2
+ ;;
+ esac
+done
+
+if [ -z $warn ] || [ -z $crit ]; then
+ usage
+ exit 2
+fi
+
+
+POSTCONFSPOOL="$(postconf -h queue_directory || echo /var/spool/postfix)"
+
+# If find fail (eg. Permission denied), script continues and exits normally,
+# even with set -e.
+# So check here if we are sufficient permission to list a Postfix directory
+if ! find $POSTCONFSPOOL/corrupt >/dev/null; then
+ echo "Script does not seem to have permission to list spool directories."
+ exit 2
+fi
+
+deferred=$(find $POSTCONFSPOOL/deferred -type f |wc -l)
+active=$(find $POSTCONFSPOOL/active -type f | wc -l)
+maildrop=$(find $POSTCONFSPOOL/maildrop -type f | wc -l)
+incoming=$(find $POSTCONFSPOOL/incoming -type f | wc -l)
+corrupt=$(find $POSTCONFSPOOL/corrupt -type f | wc -l)
+hold=$(find $POSTCONFSPOOL/hold -type f | wc -l)
+total=$(($deferred + $active + $maildrop + $incoming + $corrupt + $hold))
+
+echo "total: $total (deferred: $deferred, active: $active, maildrop: \
+$maildrop, incoming: $incoming, corrupt: $corrupt, hold: $hold)"
+
+if [ $total -ge $crit ]; then
+ exit 2
+elif [ $total -ge $warn ]; then
+ exit 1
+fi
diff --git a/nagios-nrpe/files/plugins/check_mem b/nagios-nrpe/files/plugins/check_mem
new file mode 100755
index 00000000..8487255c
--- /dev/null
+++ b/nagios-nrpe/files/plugins/check_mem
@@ -0,0 +1,266 @@
+#!/usr/bin/perl -w
+
+# Heavily based on the script from:
+# check_mem.pl Copyright (C) 2000 Dan Larsson
+# heavily modified by
+# Justin Ellison
+#
+# The MIT License (MIT)
+# Copyright (c) 2011 justin@techadvise.com
+
+# Permission is hereby granted, free of charge, to any person obtaining a copy of this
+# software and associated documentation files (the "Software"), to deal in the Software
+# without restriction, including without limitation the rights to use, copy, modify,
+# merge, publish, distribute, sublicense, and/or sell copies of the Software, and to
+# permit persons to whom the Software is furnished to do so, subject to the following conditions:
+
+# The above copyright notice and this permission notice shall be included in all copies
+# or substantial portions of the Software.
+
+# THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED,
+# INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR
+# PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE
+# FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT
+# OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR
+# OTHER DEALINGS IN THE SOFTWARE.
+
+# Tell Perl what we need to use
+use strict;
+use Getopt::Std;
+
+#TODO - Convert to Nagios::Plugin
+#TODO - Use an alarm
+
+# Predefined exit codes for Nagios
+use vars qw($opt_c $opt_f $opt_u $opt_w $opt_C $opt_v %exit_codes);
+%exit_codes = ('UNKNOWN' ,-1,
+ 'OK' , 0,
+ 'WARNING' , 1,
+ 'CRITICAL', 2,
+ );
+
+# Get our variables, do our checking:
+init();
+
+# Get the numbers:
+my ($free_memory_kb,$used_memory_kb,$caches_kb) = get_memory_info();
+print "$free_memory_kb Free\n$used_memory_kb Used\n$caches_kb Cache\n" if ($opt_v);
+
+if ($opt_C) { #Do we count caches as free?
+ $used_memory_kb -= $caches_kb;
+ $free_memory_kb += $caches_kb;
+}
+
+# Round to the nearest KB
+$free_memory_kb = sprintf('%d',$free_memory_kb);
+$used_memory_kb = sprintf('%d',$used_memory_kb);
+$caches_kb = sprintf('%d',$caches_kb);
+
+# Tell Nagios what we came up with
+tell_nagios($used_memory_kb,$free_memory_kb,$caches_kb);
+
+
+sub tell_nagios {
+ my ($used,$free,$caches) = @_;
+
+ # Calculate Total Memory
+ my $total = $free + $used;
+ print "$total Total\n" if ($opt_v);
+
+ my $perfdata = "|TOTAL=${total}KB;;;; USED=${used}KB;;;; FREE=${free}KB;;;; CACHES=${caches}KB;;;;";
+
+ if ($opt_f) {
+ my $percent = sprintf "%.1f", ($free / $total * 100);
+ if ($percent <= $opt_c) {
+ finish("CRITICAL - $percent% ($free kB) free!$perfdata",$exit_codes{'CRITICAL'});
+ }
+ elsif ($percent <= $opt_w) {
+ finish("WARNING - $percent% ($free kB) free!$perfdata",$exit_codes{'WARNING'});
+ }
+ else {
+ finish("OK - $percent% ($free kB) free.$perfdata",$exit_codes{'OK'});
+ }
+ }
+ elsif ($opt_u) {
+ my $percent = sprintf "%.1f", ($used / $total * 100);
+ if ($percent >= $opt_c) {
+ finish("CRITICAL - $percent% ($used kB) used!$perfdata",$exit_codes{'CRITICAL'});
+ }
+ elsif ($percent >= $opt_w) {
+ finish("WARNING - $percent% ($used kB) used!$perfdata",$exit_codes{'WARNING'});
+ }
+ else {
+ finish("OK - $percent% ($used kB) used.$perfdata",$exit_codes{'OK'});
+ }
+ }
+}
+
+# Show usage
+sub usage() {
+ print "\ncheck_mem.pl v1.0 - Nagios Plugin\n\n";
+ print "usage:\n";
+ print " check_mem.pl - -w -c \n\n";
+ print "options:\n";
+ print " -f Check FREE memory\n";
+ print " -u Check USED memory\n";
+ print " -C Count OS caches as FREE memory\n";
+ print " -w PERCENT Percent free/used when to warn\n";
+ print " -c PERCENT Percent free/used when critical\n";
+ print "\nCopyright (C) 2000 Dan Larsson
\n";
+ print "check_mem.pl comes with absolutely NO WARRANTY either implied or explicit\n";
+ print "This program is licensed under the terms of the\n";
+ print "MIT License (check source code for details)\n";
+ exit $exit_codes{'UNKNOWN'};
+}
+
+sub get_memory_info {
+ my $used_memory_kb = 0;
+ my $free_memory_kb = 0;
+ my $total_memory_kb = 0;
+ my $caches_kb = 0;
+
+ my $uname;
+ if ( -e '/usr/bin/uname') {
+ $uname = `/usr/bin/uname -a`;
+ }
+ elsif ( -e '/bin/uname') {
+ $uname = `/bin/uname -a`;
+ }
+ else {
+ die "Unable to find uname in /usr/bin or /bin!\n";
+ }
+ print "uname returns $uname" if ($opt_v);
+ if ( $uname =~ /Linux/ ) {
+ my @meminfo = `/bin/cat /proc/meminfo`;
+ foreach (@meminfo) {
+ chomp;
+ if (/^Mem(Total|Free):\s+(\d+) kB/) {
+ my $counter_name = $1;
+ if ($counter_name eq 'Free') {
+ $free_memory_kb = $2;
+ }
+ elsif ($counter_name eq 'Total') {
+ $total_memory_kb = $2;
+ }
+ }
+ elsif (/^(Buffers|Cached):\s+(\d+) kB/) {
+ $caches_kb += $2;
+ }
+ }
+ $used_memory_kb = $total_memory_kb - $free_memory_kb;
+ }
+ elsif ( $uname =~ /SunOS/ ) {
+ eval "use Sun::Solaris::Kstat";
+ if ($@) { #Kstat not available
+ if ($opt_C) {
+ print "You can't report on Solaris caches without Sun::Solaris::Kstat available!\n";
+ exit $exit_codes{UNKNOWN};
+ }
+ my @vmstat = `/usr/bin/vmstat 1 2`;
+ my $line;
+ foreach (@vmstat) {
+ chomp;
+ $line = $_;
+ }
+ $free_memory_kb = (split(/ /,$line))[5] / 1024;
+ my @prtconf = `/usr/sbin/prtconf`;
+ foreach (@prtconf) {
+ if (/^Memory size: (\d+) Megabytes/) {
+ $total_memory_kb = $1 * 1024;
+ }
+ }
+ $used_memory_kb = $total_memory_kb - $free_memory_kb;
+
+ }
+ else { # We have kstat
+ my $kstat = Sun::Solaris::Kstat->new();
+ my $phys_pages = ${kstat}->{unix}->{0}->{system_pages}->{physmem};
+ my $free_pages = ${kstat}->{unix}->{0}->{system_pages}->{freemem};
+ # We probably should account for UFS caching here, but it's unclear
+ # to me how to determine UFS's cache size. There's inode_cache,
+ # and maybe the physmem variable in the system_pages module??
+ # In the real world, it looks to be so small as not to really matter,
+ # so we don't grab it. If someone can give me code that does this,
+ # I'd be glad to put it in.
+ my $arc_size = (exists ${kstat}->{zfs} && ${kstat}->{zfs}->{0}->{arcstats}->{size}) ?
+ ${kstat}->{zfs}->{0}->{arcstats}->{size} / 1024
+ : 0;
+ $caches_kb += $arc_size;
+ my $pagesize = `pagesize`;
+
+ $total_memory_kb = $phys_pages * $pagesize / 1024;
+ $free_memory_kb = $free_pages * $pagesize / 1024;
+ $used_memory_kb = $total_memory_kb - $free_memory_kb;
+ }
+ }
+ elsif ( $uname =~ /AIX/ ) {
+ my @meminfo = `/usr/bin/vmstat -v`;
+ foreach (@meminfo) {
+ chomp;
+ if (/^\s*([0-9.]+)\s+(.*)/) {
+ my $counter_name = $2;
+ if ($counter_name eq 'memory pages') {
+ $total_memory_kb = $1*4;
+ }
+ if ($counter_name eq 'free pages') {
+ $free_memory_kb = $1*4;
+ }
+ if ($counter_name eq 'file pages') {
+ $caches_kb = $1*4;
+ }
+ }
+ }
+ $used_memory_kb = $total_memory_kb - $free_memory_kb;
+ }
+ else {
+ if ($opt_C) {
+ print "You can't report on $uname caches!\n";
+ exit $exit_codes{UNKNOWN};
+ }
+ my $command_line = `vmstat | tail -1 | awk '{print \$4,\$5}'`;
+ chomp $command_line;
+ my @memlist = split(/ /, $command_line);
+
+ # Define the calculating scalars
+ $used_memory_kb = $memlist[0]/1024;
+ $free_memory_kb = $memlist[1]/1024;
+ $total_memory_kb = $used_memory_kb + $free_memory_kb;
+ }
+ return ($free_memory_kb,$used_memory_kb,$caches_kb);
+}
+
+sub init {
+ # Get the options
+ if ($#ARGV le 0) {
+ &usage;
+ }
+ else {
+ getopts('c:fuCvw:');
+ }
+
+ # Shortcircuit the switches
+ if (!$opt_w or $opt_w == 0 or !$opt_c or $opt_c == 0) {
+ print "*** You must define WARN and CRITICAL levels!\n";
+ &usage;
+ }
+ elsif (!$opt_f and !$opt_u) {
+ print "*** You must select to monitor either USED or FREE memory!\n";
+ &usage;
+ }
+
+ # Check if levels are sane
+ if ($opt_w <= $opt_c and $opt_f) {
+ print "*** WARN level must not be less than CRITICAL when checking FREE memory!\n";
+ &usage;
+ }
+ elsif ($opt_w >= $opt_c and $opt_u) {
+ print "*** WARN level must not be greater than CRITICAL when checking USED memory!\n";
+ &usage;
+ }
+}
+
+sub finish {
+ my ($msg,$state) = @_;
+ print "$msg\n";
+ exit $state;
+}
diff --git a/nagios-nrpe/files/plugins/check_memcached_instances b/nagios-nrpe/files/plugins/check_memcached_instances
new file mode 100755
index 00000000..0a04b867
--- /dev/null
+++ b/nagios-nrpe/files/plugins/check_memcached_instances
@@ -0,0 +1,10 @@
+#!/bin/bash
+
+returnCode=0
+
+for port in $(grep "^-p " /etc/memcached*.conf |cut -d ' ' -f 2); do
+ /usr/lib/nagios/plugins/check_tcp -p $port
+ returnCode=$(($returnCode|$?))
+done
+
+exit $returnCode
diff --git a/nagios-nrpe/files/plugins/check_mongodb b/nagios-nrpe/files/plugins/check_mongodb
new file mode 100755
index 00000000..bc6278ac
--- /dev/null
+++ b/nagios-nrpe/files/plugins/check_mongodb
@@ -0,0 +1,1456 @@
+#!/usr/bin/env python
+
+#
+# A MongoDB Nagios check script
+#
+
+# Script idea taken from a Tag1 script I found and I modified it a lot
+#
+# Main Author
+# - Mike Zupan
+# Contributers
+# - Frank Brandewiede
+# - Sam Perman
+# - Shlomo Priymak
+# - @jhoff909 on github
+# - @jbraeuer on github
+# - Dag Stockstad
+# - @Andor on github
+# - Steven Richards - Captainkrtek on github
+# - Max Vernimmen
+#
+# USAGE
+#
+# See the README.md
+#
+
+import sys
+import time
+import optparse
+import textwrap
+import re
+import os
+
+try:
+ import pymongo
+except ImportError, e:
+ print e
+ sys.exit(2)
+
+# As of pymongo v 1.9 the SON API is part of the BSON package, therefore attempt
+# to import from there and fall back to pymongo in cases of older pymongo
+if pymongo.version >= "1.9":
+ import bson.son as son
+else:
+ import pymongo.son as son
+
+
+#
+# thanks to http://stackoverflow.com/a/1229667/72987
+#
+def optional_arg(arg_default):
+ def func(option, opt_str, value, parser):
+ if parser.rargs and not parser.rargs[0].startswith('-'):
+ val = parser.rargs[0]
+ parser.rargs.pop(0)
+ else:
+ val = arg_default
+ setattr(parser.values, option.dest, val)
+ return func
+
+
+def performance_data(perf_data, params):
+ data = ''
+ if perf_data:
+ data = " |"
+ for p in params:
+ p += (None, None, None, None)
+ param, param_name, warning, critical = p[0:4]
+ data += "%s=%s" % (param_name, str(param))
+ if warning or critical:
+ warning = warning or 0
+ critical = critical or 0
+ data += ";%s;%s" % (warning, critical)
+
+ data += " "
+
+ return data
+
+
+def numeric_type(param):
+ if ((type(param) == float or type(param) == int or param == None)):
+ return True
+ return False
+
+
+def check_levels(param, warning, critical, message, ok=[]):
+ if (numeric_type(critical) and numeric_type(warning)):
+ if param >= critical:
+ print "CRITICAL - " + message
+ sys.exit(2)
+ elif param >= warning:
+ print "WARNING - " + message
+ sys.exit(1)
+ else:
+ print "OK - " + message
+ sys.exit(0)
+ else:
+ if param in critical:
+ print "CRITICAL - " + message
+ sys.exit(2)
+
+ if param in warning:
+ print "WARNING - " + message
+ sys.exit(1)
+
+ if param in ok:
+ print "OK - " + message
+ sys.exit(0)
+
+ # unexpected param value
+ print "CRITICAL - Unexpected value : %d" % param + "; " + message
+ return 2
+
+
+def get_server_status(con):
+ try:
+ set_read_preference(con.admin)
+ data = con.admin.command(pymongo.son_manipulator.SON([('serverStatus', 1)]))
+ except:
+ data = con.admin.command(son.SON([('serverStatus', 1)]))
+ return data
+
+
+def main(argv):
+ p = optparse.OptionParser(conflict_handler="resolve", description="This Nagios plugin checks the health of mongodb.")
+
+ p.add_option('-H', '--host', action='store', type='string', dest='host', default='127.0.0.1', help='The hostname you want to connect to')
+ p.add_option('-P', '--port', action='store', type='int', dest='port', default=27017, help='The port mongodb is runnung on')
+ p.add_option('-u', '--user', action='store', type='string', dest='user', default=None, help='The username you want to login as')
+ p.add_option('-p', '--pass', action='store', type='string', dest='passwd', default=None, help='The password you want to use for that user')
+ p.add_option('-W', '--warning', action='store', dest='warning', default=None, help='The warning threshold we want to set')
+ p.add_option('-C', '--critical', action='store', dest='critical', default=None, help='The critical threshold we want to set')
+ p.add_option('-A', '--action', action='store', type='choice', dest='action', default='connect', help='The action you want to take',
+ choices=['connect', 'connections', 'replication_lag', 'replication_lag_percent', 'replset_state', 'memory', 'memory_mapped', 'lock',
+ 'flushing', 'last_flush_time', 'index_miss_ratio', 'databases', 'collections', 'database_size', 'database_indexes', 'collection_indexes', 'collection_size',
+ 'queues', 'oplog', 'journal_commits_in_wl', 'write_data_files', 'journaled', 'opcounters', 'current_lock', 'replica_primary', 'page_faults',
+ 'asserts', 'queries_per_second', 'page_faults', 'chunks_balance', 'connect_primary', 'collection_state', 'row_count', 'replset_quorum'])
+ p.add_option('--max-lag', action='store_true', dest='max_lag', default=False, help='Get max replication lag (for replication_lag action only)')
+ p.add_option('--mapped-memory', action='store_true', dest='mapped_memory', default=False, help='Get mapped memory instead of resident (if resident memory can not be read)')
+ p.add_option('-D', '--perf-data', action='store_true', dest='perf_data', default=False, help='Enable output of Nagios performance data')
+ p.add_option('-d', '--database', action='store', dest='database', default='admin', help='Specify the database to check')
+ p.add_option('--all-databases', action='store_true', dest='all_databases', default=False, help='Check all databases (action database_size)')
+ p.add_option('-s', '--ssl', dest='ssl', default=False, action='callback', callback=optional_arg(True), help='Connect using SSL')
+ p.add_option('-r', '--replicaset', dest='replicaset', default=None, action='callback', callback=optional_arg(True), help='Connect to replicaset')
+ p.add_option('-q', '--querytype', action='store', dest='query_type', default='query', help='The query type to check [query|insert|update|delete|getmore|command] from queries_per_second')
+ p.add_option('-c', '--collection', action='store', dest='collection', default='admin', help='Specify the collection to check')
+ p.add_option('-T', '--time', action='store', type='int', dest='sample_time', default=1, help='Time used to sample number of pages faults')
+
+ options, arguments = p.parse_args()
+ host = options.host
+ port = options.port
+ user = options.user
+ passwd = options.passwd
+ query_type = options.query_type
+ collection = options.collection
+ sample_time = options.sample_time
+ if (options.action == 'replset_state'):
+ warning = str(options.warning or "")
+ critical = str(options.critical or "")
+ else:
+ warning = float(options.warning or 0)
+ critical = float(options.critical or 0)
+
+ action = options.action
+ perf_data = options.perf_data
+ max_lag = options.max_lag
+ database = options.database
+ ssl = options.ssl
+ replicaset = options.replicaset
+
+ if action == 'replica_primary' and replicaset is None:
+ return "replicaset must be passed in when using replica_primary check"
+ elif not action == 'replica_primary' and replicaset:
+ return "passing a replicaset while not checking replica_primary does not work"
+
+ #
+ # moving the login up here and passing in the connection
+ #
+ start = time.time()
+ err, con = mongo_connect(host, port, ssl, user, passwd, replicaset)
+ if err != 0:
+ return err
+
+ conn_time = time.time() - start
+ conn_time = round(conn_time, 0)
+
+ if action == "connections":
+ return check_connections(con, warning, critical, perf_data)
+ elif action == "replication_lag":
+ return check_rep_lag(con, host, port, warning, critical, False, perf_data, max_lag, user, passwd)
+ elif action == "replication_lag_percent":
+ return check_rep_lag(con, host, port, warning, critical, True, perf_data, max_lag, user, passwd)
+ elif action == "replset_state":
+ return check_replset_state(con, perf_data, warning, critical)
+ elif action == "memory":
+ return check_memory(con, warning, critical, perf_data, options.mapped_memory)
+ elif action == "memory_mapped":
+ return check_memory_mapped(con, warning, critical, perf_data)
+ elif action == "queues":
+ return check_queues(con, warning, critical, perf_data)
+ elif action == "lock":
+ return check_lock(con, warning, critical, perf_data)
+ elif action == "current_lock":
+ return check_current_lock(con, host, warning, critical, perf_data)
+ elif action == "flushing":
+ return check_flushing(con, warning, critical, True, perf_data)
+ elif action == "last_flush_time":
+ return check_flushing(con, warning, critical, False, perf_data)
+ elif action == "index_miss_ratio":
+ index_miss_ratio(con, warning, critical, perf_data)
+ elif action == "databases":
+ return check_databases(con, warning, critical, perf_data)
+ elif action == "collections":
+ return check_collections(con, warning, critical, perf_data)
+ elif action == "oplog":
+ return check_oplog(con, warning, critical, perf_data)
+ elif action == "journal_commits_in_wl":
+ return check_journal_commits_in_wl(con, warning, critical, perf_data)
+ elif action == "database_size":
+ if options.all_databases:
+ return check_all_databases_size(con, warning, critical, perf_data)
+ else:
+ return check_database_size(con, database, warning, critical, perf_data)
+ elif action == "database_indexes":
+ return check_database_indexes(con, database, warning, critical, perf_data)
+ elif action == "collection_indexes":
+ return check_collection_indexes(con, database, collection, warning, critical, perf_data)
+ elif action == "collection_size":
+ return check_collection_size(con, database, collection, warning, critical, perf_data)
+ elif action == "journaled":
+ return check_journaled(con, warning, critical, perf_data)
+ elif action == "write_data_files":
+ return check_write_to_datafiles(con, warning, critical, perf_data)
+ elif action == "opcounters":
+ return check_opcounters(con, host, warning, critical, perf_data)
+ elif action == "asserts":
+ return check_asserts(con, host, warning, critical, perf_data)
+ elif action == "replica_primary":
+ return check_replica_primary(con, host, warning, critical, perf_data, replicaset)
+ elif action == "queries_per_second":
+ return check_queries_per_second(con, query_type, warning, critical, perf_data)
+ elif action == "page_faults":
+ check_page_faults(con, sample_time, warning, critical, perf_data)
+ elif action == "chunks_balance":
+ chunks_balance(con, database, collection, warning, critical)
+ elif action == "connect_primary":
+ return check_connect_primary(con, warning, critical, perf_data)
+ elif action == "collection_state":
+ return check_collection_state(con, database, collection)
+ elif action == "row_count":
+ return check_row_count(con, database, collection, warning, critical, perf_data)
+ elif action == "replset_quorum":
+ return check_replset_quorum(con, perf_data)
+ else:
+ return check_connect(host, port, warning, critical, perf_data, user, passwd, conn_time)
+
+
+def mongo_connect(host=None, port=None, ssl=False, user=None, passwd=None, replica=None):
+ try:
+ # ssl connection for pymongo > 2.3
+ if pymongo.version >= "2.3":
+ if replica is None:
+ con = pymongo.MongoClient(host, port)
+ else:
+ con = pymongo.Connection(host, port, read_preference=pymongo.ReadPreference.SECONDARY, ssl=ssl, replicaSet=replica, network_timeout=10)
+ else:
+ if replica is None:
+ con = pymongo.Connection(host, port, slave_okay=True, network_timeout=10)
+ else:
+ con = pymongo.Connection(host, port, slave_okay=True, network_timeout=10)
+ #con = pymongo.Connection(host, port, slave_okay=True, replicaSet=replica, network_timeout=10)
+
+ if user and passwd:
+ db = con["admin"]
+ if not db.authenticate(user, passwd):
+ sys.exit("Username/Password incorrect")
+ except Exception, e:
+ if isinstance(e, pymongo.errors.AutoReconnect) and str(e).find(" is an arbiter") != -1:
+ # We got a pymongo AutoReconnect exception that tells us we connected to an Arbiter Server
+ # This means: Arbiter is reachable and can answer requests/votes - this is all we need to know from an arbiter
+ print "OK - State: 7 (Arbiter)"
+ sys.exit(0)
+ return exit_with_general_critical(e), None
+ return 0, con
+
+
+def exit_with_general_warning(e):
+ if isinstance(e, SystemExit):
+ return e
+ else:
+ print "WARNING - General MongoDB warning:", e
+ return 1
+
+
+def exit_with_general_critical(e):
+ if isinstance(e, SystemExit):
+ return e
+ else:
+ print "CRITICAL - General MongoDB Error:", e
+ return 2
+
+
+def set_read_preference(db):
+ if pymongo.version >= "2.1":
+ db.read_preference = pymongo.ReadPreference.SECONDARY
+
+
+def check_connect(host, port, warning, critical, perf_data, user, passwd, conn_time):
+ warning = warning or 3
+ critical = critical or 6
+ message = "Connection took %i seconds" % conn_time
+ message += performance_data(perf_data, [(conn_time, "connection_time", warning, critical)])
+
+ return check_levels(conn_time, warning, critical, message)
+
+
+def check_connections(con, warning, critical, perf_data):
+ warning = warning or 80
+ critical = critical or 95
+ try:
+ data = get_server_status(con)
+
+ current = float(data['connections']['current'])
+ available = float(data['connections']['available'])
+
+ used_percent = int(float(current / (available + current)) * 100)
+ message = "%i percent (%i of %i connections) used" % (used_percent, current, current + available)
+ message += performance_data(perf_data, [(used_percent, "used_percent", warning, critical),
+ (current, "current_connections"),
+ (available, "available_connections")])
+ return check_levels(used_percent, warning, critical, message)
+
+ except Exception, e:
+ return exit_with_general_critical(e)
+
+
+def check_rep_lag(con, host, port, warning, critical, percent, perf_data, max_lag, user, passwd):
+ # Get mongo to tell us replica set member name when connecting locally
+ if "127.0.0.1" == host:
+ host = con.admin.command("ismaster","1")["me"].split(':')[0]
+
+ if percent:
+ warning = warning or 50
+ critical = critical or 75
+ else:
+ warning = warning or 600
+ critical = critical or 3600
+ rs_status = {}
+ slaveDelays = {}
+ try:
+ set_read_preference(con.admin)
+
+ # Get replica set status
+ try:
+ rs_status = con.admin.command("replSetGetStatus")
+ except pymongo.errors.OperationFailure, e:
+ if e.code == None and str(e).find('failed: not running with --replSet"'):
+ print "OK - Not running with replSet"
+ return 0
+
+ serverVersion = tuple(con.server_info()['version'].split('.'))
+ if serverVersion >= tuple("2.0.0".split(".")):
+ #
+ # check for version greater then 2.0
+ #
+ rs_conf = con.local.system.replset.find_one()
+ for member in rs_conf['members']:
+ if member.get('slaveDelay') is not None:
+ slaveDelays[member['host']] = member.get('slaveDelay')
+ else:
+ slaveDelays[member['host']] = 0
+
+ # Find the primary and/or the current node
+ primary_node = None
+ host_node = None
+
+ for member in rs_status["members"]:
+ if member["stateStr"] == "PRIMARY":
+ primary_node = member
+ if member["name"].split(':')[0] == host and int(member["name"].split(':')[1]) == port:
+ host_node = member
+
+ # Check if we're in the middle of an election and don't have a primary
+ if primary_node is None:
+ print "WARNING - No primary defined. In an election?"
+ return 1
+
+ # Check if we failed to find the current host
+ # below should never happen
+ if host_node is None:
+ print "CRITICAL - Unable to find host '" + host + "' in replica set."
+ return 2
+
+ # Is the specified host the primary?
+ if host_node["stateStr"] == "PRIMARY":
+ if max_lag == False:
+ print "OK - This is the primary."
+ return 0
+ else:
+ #get the maximal replication lag
+ data = ""
+ maximal_lag = 0
+ for member in rs_status['members']:
+ if not member['stateStr'] == "ARBITER":
+ lastSlaveOpTime = member['optimeDate']
+ replicationLag = abs(primary_node["optimeDate"] - lastSlaveOpTime).seconds - slaveDelays[member['name']]
+ data = data + member['name'] + " lag=%d;" % replicationLag
+ maximal_lag = max(maximal_lag, replicationLag)
+ if percent:
+ err, con = mongo_connect(primary_node['name'].split(':')[0], int(primary_node['name'].split(':')[1]), False, user, passwd)
+ if err != 0:
+ return err
+ primary_timediff = replication_get_time_diff(con)
+ maximal_lag = int(float(maximal_lag) / float(primary_timediff) * 100)
+ message = "Maximal lag is " + str(maximal_lag) + " percents"
+ message += performance_data(perf_data, [(maximal_lag, "replication_lag_percent", warning, critical)])
+ else:
+ message = "Maximal lag is " + str(maximal_lag) + " seconds"
+ message += performance_data(perf_data, [(maximal_lag, "replication_lag", warning, critical)])
+ return check_levels(maximal_lag, warning, critical, message)
+ elif host_node["stateStr"] == "ARBITER":
+ print "OK - This is an arbiter"
+ return 0
+
+ # Find the difference in optime between current node and PRIMARY
+
+ optime_lag = abs(primary_node["optimeDate"] - host_node["optimeDate"])
+
+ if host_node['name'] in slaveDelays:
+ slave_delay = slaveDelays[host_node['name']]
+ elif host_node['name'].endswith(':27017') and host_node['name'][:-len(":27017")] in slaveDelays:
+ slave_delay = slaveDelays[host_node['name'][:-len(":27017")]]
+ else:
+ raise Exception("Unable to determine slave delay for {0}".format(host_node['name']))
+
+ try: # work starting from python2.7
+ lag = optime_lag.total_seconds()
+ except:
+ lag = float(optime_lag.seconds + optime_lag.days * 24 * 3600)
+
+ if percent:
+ err, con = mongo_connect(primary_node['name'].split(':')[0], int(primary_node['name'].split(':')[1]), False, user, passwd)
+ if err != 0:
+ return err
+ primary_timediff = replication_get_time_diff(con)
+ if primary_timediff != 0:
+ lag = int(float(lag) / float(primary_timediff) * 100)
+ else:
+ lag = 0
+ message = "Lag is " + str(lag) + " percents"
+ message += performance_data(perf_data, [(lag, "replication_lag_percent", warning, critical)])
+ else:
+ message = "Lag is " + str(lag) + " seconds"
+ message += performance_data(perf_data, [(lag, "replication_lag", warning, critical)])
+ return check_levels(lag, warning + slaveDelays[host_node['name']], critical + slaveDelays[host_node['name']], message)
+ else:
+ #
+ # less than 2.0 check
+ #
+ # Get replica set status
+ rs_status = con.admin.command("replSetGetStatus")
+
+ # Find the primary and/or the current node
+ primary_node = None
+ host_node = None
+ for member in rs_status["members"]:
+ if member["stateStr"] == "PRIMARY":
+ primary_node = (member["name"], member["optimeDate"])
+ if member["name"].split(":")[0].startswith(host):
+ host_node = member
+
+ # Check if we're in the middle of an election and don't have a primary
+ if primary_node is None:
+ print "WARNING - No primary defined. In an election?"
+ sys.exit(1)
+
+ # Is the specified host the primary?
+ if host_node["stateStr"] == "PRIMARY":
+ print "OK - This is the primary."
+ sys.exit(0)
+
+ # Find the difference in optime between current node and PRIMARY
+ optime_lag = abs(primary_node[1] - host_node["optimeDate"])
+ lag = optime_lag.seconds
+ if percent:
+ err, con = mongo_connect(primary_node['name'].split(':')[0], int(primary_node['name'].split(':')[1]))
+ if err != 0:
+ return err
+ primary_timediff = replication_get_time_diff(con)
+ lag = int(float(lag) / float(primary_timediff) * 100)
+ message = "Lag is " + str(lag) + " percents"
+ message += performance_data(perf_data, [(lag, "replication_lag_percent", warning, critical)])
+ else:
+ message = "Lag is " + str(lag) + " seconds"
+ message += performance_data(perf_data, [(lag, "replication_lag", warning, critical)])
+ return check_levels(lag, warning, critical, message)
+
+ except Exception, e:
+ return exit_with_general_critical(e)
+
+
+def check_memory(con, warning, critical, perf_data, mapped_memory):
+ #
+ # These thresholds are basically meaningless, and must be customized to your system's ram
+ #
+
+ # Get the total system merory and calculate based on that how much memory used by Mongodb is ok or not.
+ meminfo = open('/proc/meminfo').read()
+ matched = re.search(r'^MemTotal:\s+(\d+)', meminfo)
+ if matched:
+ mem_total_kB = int(matched.groups()[0])
+
+ # Old way
+ #critical = critical or 16
+ # The new way. if using >80% then warn, if >90% then critical level
+ warning = warning or (mem_total_kB * 0.8) / 1024.0 / 1024.0
+ critical = critical or (mem_total_kB * 0.9) / 1024.0 / 1024.0
+
+ # debugging
+ #print "mem total: {0}kb, warn: {1}GB, crit: {2}GB".format(mem_total_kB,warning, critical)
+
+ try:
+ data = get_server_status(con)
+ if not data['mem']['supported'] and not mapped_memory:
+ print "OK - Platform not supported for memory info"
+ return 0
+ #
+ # convert to gigs
+ #
+ message = "Memory Usage:"
+ try:
+ mem_resident = float(data['mem']['resident']) / 1024.0
+ message += " %.2fGB resident," % (mem_resident)
+ except:
+ mem_resident = 0
+ message += " resident unsupported,"
+ try:
+ mem_virtual = float(data['mem']['virtual']) / 1024.0
+ message += " %.2fGB virtual," % mem_virtual
+ except:
+ mem_virtual = 0
+ message += " virtual unsupported,"
+ try:
+ mem_mapped = float(data['mem']['mapped']) / 1024.0
+ message += " %.2fGB mapped," % mem_mapped
+ except:
+ mem_mapped = 0
+ message += " mapped unsupported,"
+ try:
+ mem_mapped_journal = float(data['mem']['mappedWithJournal']) / 1024.0
+ message += " %.2fGB mappedWithJournal" % mem_mapped_journal
+ except:
+ mem_mapped_journal = 0
+ message += performance_data(perf_data, [("%.2f" % mem_resident, "memory_usage", warning, critical),
+ ("%.2f" % mem_mapped, "memory_mapped"), ("%.2f" % mem_virtual, "memory_virtual"), ("%.2f" % mem_mapped_journal, "mappedWithJournal")])
+ #added for unsupported systems like Solaris
+ if mapped_memory and mem_resident == 0:
+ return check_levels(mem_mapped, warning, critical, message)
+ else:
+ return check_levels(mem_resident, warning, critical, message)
+
+ except Exception, e:
+ return exit_with_general_critical(e)
+
+
+def check_memory_mapped(con, warning, critical, perf_data):
+ #
+ # These thresholds are basically meaningless, and must be customized to your application
+ #
+ warning = warning or 8
+ critical = critical or 16
+ try:
+ data = get_server_status(con)
+ if not data['mem']['supported']:
+ print "OK - Platform not supported for memory info"
+ return 0
+ #
+ # convert to gigs
+ #
+ message = "Memory Usage:"
+ try:
+ mem_mapped = float(data['mem']['mapped']) / 1024.0
+ message += " %.2fGB mapped," % mem_mapped
+ except:
+ mem_mapped = -1
+ message += " mapped unsupported,"
+ try:
+ mem_mapped_journal = float(data['mem']['mappedWithJournal']) / 1024.0
+ message += " %.2fGB mappedWithJournal" % mem_mapped_journal
+ except:
+ mem_mapped_journal = 0
+ message += performance_data(perf_data, [("%.2f" % mem_mapped, "memory_mapped"), ("%.2f" % mem_mapped_journal, "mappedWithJournal")])
+
+ if not mem_mapped == -1:
+ return check_levels(mem_mapped, warning, critical, message)
+ else:
+ print "OK - Server does not provide mem.mapped info"
+ return 0
+
+ except Exception, e:
+ return exit_with_general_critical(e)
+
+
+def check_lock(con, warning, critical, perf_data):
+ warning = warning or 10
+ critical = critical or 30
+ try:
+ data = get_server_status(con)
+ #
+ # calculate percentage
+ #
+ lockTime = data['globalLock']['lockTime']
+ totalTime = data['globalLock']['totalTime']
+ if lockTime > totalTime:
+ lock_percentage = 0.00
+ else:
+ lock_percentage = float(lockTime) / float(totalTime) * 100
+ message = "Lock Percentage: %.2f%%" % lock_percentage
+ message += performance_data(perf_data, [("%.2f" % lock_percentage, "lock_percentage", warning, critical)])
+ return check_levels(lock_percentage, warning, critical, message)
+
+ except Exception, e:
+ return exit_with_general_critical(e)
+
+
+def check_flushing(con, warning, critical, avg, perf_data):
+ #
+ # These thresholds mean it's taking 5 seconds to perform a background flush to issue a warning
+ # and 10 seconds to issue a critical.
+ #
+ warning = warning or 5000
+ critical = critical or 15000
+ try:
+ data = get_server_status(con)
+ if avg:
+ flush_time = float(data['backgroundFlushing']['average_ms'])
+ stat_type = "Average"
+ else:
+ flush_time = float(data['backgroundFlushing']['last_ms'])
+ stat_type = "Last"
+
+ message = "%s Flush Time: %.2fms" % (stat_type, flush_time)
+ message += performance_data(perf_data, [("%.2fms" % flush_time, "%s_flush_time" % stat_type.lower(), warning, critical)])
+
+ return check_levels(flush_time, warning, critical, message)
+
+ except Exception, e:
+ return exit_with_general_critical(e)
+
+
+def index_miss_ratio(con, warning, critical, perf_data):
+ warning = warning or 10
+ critical = critical or 30
+ try:
+ data = get_server_status(con)
+
+ try:
+ serverVersion = tuple(con.server_info()['version'].split('.'))
+ if serverVersion >= tuple("2.4.0".split(".")):
+ miss_ratio = float(data['indexCounters']['missRatio'])
+ else:
+ miss_ratio = float(data['indexCounters']['btree']['missRatio'])
+ except KeyError:
+ not_supported_msg = "not supported on this platform"
+ if data['indexCounters'].has_key('note'):
+ print "OK - MongoDB says: " + not_supported_msg
+ return 0
+ else:
+ print "WARNING - Can't get counter from MongoDB"
+ return 1
+
+ message = "Miss Ratio: %.2f" % miss_ratio
+ message += performance_data(perf_data, [("%.2f" % miss_ratio, "index_miss_ratio", warning, critical)])
+
+ return check_levels(miss_ratio, warning, critical, message)
+
+ except Exception, e:
+ return exit_with_general_critical(e)
+
+def check_replset_quorum(con, perf_data):
+ db = con['admin']
+ warning = 1
+ critical = 2
+ primary = 0
+
+ try:
+ rs_members = db.command("replSetGetStatus")['members']
+
+ for member in rs_members:
+ if member['state'] == 1:
+ primary += 1
+
+ if primary == 1:
+ state = 0
+ message = "Cluster is quorate"
+ else:
+ state = 2
+ message = "Cluster is not quorate and cannot operate"
+
+ return check_levels(state, warning, critical, message)
+ except Exception, e:
+ return exit_with_general_critical(e)
+
+
+
+def check_replset_state(con, perf_data, warning="", critical=""):
+ try:
+ warning = [int(x) for x in warning.split(",")]
+ except:
+ warning = [0, 3, 5]
+ try:
+ critical = [int(x) for x in critical.split(",")]
+ except:
+ critical = [8, 4, -1]
+
+ ok = range(-1, 8) # should include the range of all posiible values
+ try:
+ try:
+ try:
+ set_read_preference(con.admin)
+ data = con.admin.command(pymongo.son_manipulator.SON([('replSetGetStatus', 1)]))
+ except:
+ data = con.admin.command(son.SON([('replSetGetStatus', 1)]))
+ state = int(data['myState'])
+ except pymongo.errors.OperationFailure, e:
+ if e.code == None and str(e).find('failed: not running with --replSet"'):
+ state = -1
+
+ if state == 8:
+ message = "State: %i (Down)" % state
+ elif state == 4:
+ message = "State: %i (Fatal error)" % state
+ elif state == 0:
+ message = "State: %i (Starting up, phase1)" % state
+ elif state == 3:
+ message = "State: %i (Recovering)" % state
+ elif state == 5:
+ message = "State: %i (Starting up, phase2)" % state
+ elif state == 1:
+ message = "State: %i (Primary)" % state
+ elif state == 2:
+ message = "State: %i (Secondary)" % state
+ elif state == 7:
+ message = "State: %i (Arbiter)" % state
+ elif state == -1:
+ message = "Not running with replSet"
+ else:
+ message = "State: %i (Unknown state)" % state
+ message += performance_data(perf_data, [(state, "state")])
+ return check_levels(state, warning, critical, message, ok)
+ except Exception, e:
+ return exit_with_general_critical(e)
+
+
+def check_databases(con, warning, critical, perf_data=None):
+ try:
+ try:
+ set_read_preference(con.admin)
+ data = con.admin.command(pymongo.son_manipulator.SON([('listDatabases', 1)]))
+ except:
+ data = con.admin.command(son.SON([('listDatabases', 1)]))
+
+ count = len(data['databases'])
+ message = "Number of DBs: %.0f" % count
+ message += performance_data(perf_data, [(count, "databases", warning, critical, message)])
+ return check_levels(count, warning, critical, message)
+ except Exception, e:
+ return exit_with_general_critical(e)
+
+
+def check_collections(con, warning, critical, perf_data=None):
+ try:
+ try:
+ set_read_preference(con.admin)
+ data = con.admin.command(pymongo.son_manipulator.SON([('listDatabases', 1)]))
+ except:
+ data = con.admin.command(son.SON([('listDatabases', 1)]))
+
+ count = 0
+ for db in data['databases']:
+ dbase = con[db['name']]
+ set_read_preference(dbase)
+ count += len(dbase.collection_names())
+
+ message = "Number of collections: %.0f" % count
+ message += performance_data(perf_data, [(count, "collections", warning, critical, message)])
+ return check_levels(count, warning, critical, message)
+
+ except Exception, e:
+ return exit_with_general_critical(e)
+
+
+def check_all_databases_size(con, warning, critical, perf_data):
+ warning = warning or 100
+ critical = critical or 1000
+ try:
+ set_read_preference(con.admin)
+ all_dbs_data = con.admin.command(pymongo.son_manipulator.SON([('listDatabases', 1)]))
+ except:
+ all_dbs_data = con.admin.command(son.SON([('listDatabases', 1)]))
+
+ total_storage_size = 0
+ message = ""
+ perf_data_param = [()]
+ for db in all_dbs_data['databases']:
+ database = db['name']
+ data = con[database].command('dbstats')
+ storage_size = round(data['storageSize'] / 1024 / 1024, 1)
+ message += "; Database %s size: %.0f MB" % (database, storage_size)
+ perf_data_param.append((storage_size, database + "_database_size"))
+ total_storage_size += storage_size
+
+ perf_data_param[0] = (total_storage_size, "total_size", warning, critical)
+ message += performance_data(perf_data, perf_data_param)
+ message = "Total size: %.0f MB" % total_storage_size + message
+ return check_levels(total_storage_size, warning, critical, message)
+
+
+def check_database_size(con, database, warning, critical, perf_data):
+ warning = warning or 100
+ critical = critical or 1000
+ perfdata = ""
+ try:
+ set_read_preference(con.admin)
+ data = con[database].command('dbstats')
+ storage_size = data['storageSize'] / 1024 / 1024
+ if perf_data:
+ perfdata += " | database_size=%i;%i;%i" % (storage_size, warning, critical)
+ #perfdata += " database=%s" %(database)
+
+ if storage_size >= critical:
+ print "CRITICAL - Database size: %.0f MB, Database: %s%s" % (storage_size, database, perfdata)
+ return 2
+ elif storage_size >= warning:
+ print "WARNING - Database size: %.0f MB, Database: %s%s" % (storage_size, database, perfdata)
+ return 1
+ else:
+ print "OK - Database size: %.0f MB, Database: %s%s" % (storage_size, database, perfdata)
+ return 0
+ except Exception, e:
+ return exit_with_general_critical(e)
+
+
+def check_database_indexes(con, database, warning, critical, perf_data):
+ #
+ # These thresholds are basically meaningless, and must be customized to your application
+ #
+ warning = warning or 100
+ critical = critical or 1000
+ perfdata = ""
+ try:
+ set_read_preference(con.admin)
+ data = con[database].command('dbstats')
+ index_size = data['indexSize'] / 1024 / 1024
+ if perf_data:
+ perfdata += " | database_indexes=%i;%i;%i" % (index_size, warning, critical)
+
+ if index_size >= critical:
+ print "CRITICAL - %s indexSize: %.0f MB %s" % (database, index_size, perfdata)
+ return 2
+ elif index_size >= warning:
+ print "WARNING - %s indexSize: %.0f MB %s" % (database, index_size, perfdata)
+ return 1
+ else:
+ print "OK - %s indexSize: %.0f MB %s" % (database, index_size, perfdata)
+ return 0
+ except Exception, e:
+ return exit_with_general_critical(e)
+
+
+def check_collection_indexes(con, database, collection, warning, critical, perf_data):
+ #
+ # These thresholds are basically meaningless, and must be customized to your application
+ #
+ warning = warning or 100
+ critical = critical or 1000
+ perfdata = ""
+ try:
+ set_read_preference(con.admin)
+ data = con[database].command('collstats', collection)
+ total_index_size = data['totalIndexSize'] / 1024 / 1024
+ if perf_data:
+ perfdata += " | collection_indexes=%i;%i;%i" % (total_index_size, warning, critical)
+
+ if total_index_size >= critical:
+ print "CRITICAL - %s.%s totalIndexSize: %.0f MB %s" % (database, collection, total_index_size, perfdata)
+ return 2
+ elif total_index_size >= warning:
+ print "WARNING - %s.%s totalIndexSize: %.0f MB %s" % (database, collection, total_index_size, perfdata)
+ return 1
+ else:
+ print "OK - %s.%s totalIndexSize: %.0f MB %s" % (database, collection, total_index_size, perfdata)
+ return 0
+ except Exception, e:
+ return exit_with_general_critical(e)
+
+
+def check_queues(con, warning, critical, perf_data):
+ warning = warning or 10
+ critical = critical or 30
+ try:
+ data = get_server_status(con)
+
+ total_queues = float(data['globalLock']['currentQueue']['total'])
+ readers_queues = float(data['globalLock']['currentQueue']['readers'])
+ writers_queues = float(data['globalLock']['currentQueue']['writers'])
+ message = "Current queue is : total = %d, readers = %d, writers = %d" % (total_queues, readers_queues, writers_queues)
+ message += performance_data(perf_data, [(total_queues, "total_queues", warning, critical), (readers_queues, "readers_queues"), (writers_queues, "writers_queues")])
+ return check_levels(total_queues, warning, critical, message)
+
+ except Exception, e:
+ return exit_with_general_critical(e)
+
+def check_collection_size(con, database, collection, warning, critical, perf_data):
+ warning = warning or 100
+ critical = critical or 1000
+ perfdata = ""
+ try:
+ set_read_preference(con.admin)
+ data = con[database].command('collstats', collection)
+ size = data['size'] / 1024 / 1024
+ if perf_data:
+ perfdata += " | collection_size=%i;%i;%i" % (size, warning, critical)
+
+ if size >= critical:
+ print "CRITICAL - %s.%s size: %.0f MB %s" % (database, collection, size, perfdata)
+ return 2
+ elif size >= warning:
+ print "WARNING - %s.%s size: %.0f MB %s" % (database, collection, size, perfdata)
+ return 1
+ else:
+ print "OK - %s.%s size: %.0f MB %s" % (database, collection, size, perfdata)
+ return 0
+ except Exception, e:
+ return exit_with_general_critical(e)
+
+def check_queries_per_second(con, query_type, warning, critical, perf_data):
+ warning = warning or 250
+ critical = critical or 500
+
+ if query_type not in ['insert', 'query', 'update', 'delete', 'getmore', 'command']:
+ return exit_with_general_critical("The query type of '%s' is not valid" % query_type)
+
+ try:
+ db = con.local
+ data = get_server_status(con)
+
+ # grab the count
+ num = int(data['opcounters'][query_type])
+
+ # do the math
+ last_count = db.nagios_check.find_one({'check': 'query_counts'})
+ try:
+ ts = int(time.time())
+ diff_query = num - last_count['data'][query_type]['count']
+ diff_ts = ts - last_count['data'][query_type]['ts']
+
+ query_per_sec = float(diff_query) / float(diff_ts)
+
+ # update the count now
+ db.nagios_check.update({u'_id': last_count['_id']}, {'$set': {"data.%s" % query_type: {'count': num, 'ts': int(time.time())}}})
+
+ message = "Queries / Sec: %f" % query_per_sec
+ message += performance_data(perf_data, [(query_per_sec, "%s_per_sec" % query_type, warning, critical, message)])
+ except KeyError:
+ #
+ # since it is the first run insert it
+ query_per_sec = 0
+ message = "First run of check.. no data"
+ db.nagios_check.update({u'_id': last_count['_id']}, {'$set': {"data.%s" % query_type: {'count': num, 'ts': int(time.time())}}})
+ except TypeError:
+ #
+ # since it is the first run insert it
+ query_per_sec = 0
+ message = "First run of check.. no data"
+ db.nagios_check.insert({'check': 'query_counts', 'data': {query_type: {'count': num, 'ts': int(time.time())}}})
+
+ return check_levels(query_per_sec, warning, critical, message)
+
+ except Exception, e:
+ return exit_with_general_critical(e)
+
+
+def check_oplog(con, warning, critical, perf_data):
+ """ Checking the oplog time - the time of the log currntly saved in the oplog collection
+ defaults:
+ critical 4 hours
+ warning 24 hours
+ those can be changed as usual with -C and -W parameters"""
+ warning = warning or 24
+ critical = critical or 4
+ try:
+ db = con.local
+ ol = db.system.namespaces.find_one({"name": "local.oplog.rs"})
+ if (db.system.namespaces.find_one({"name": "local.oplog.rs"}) != None):
+ oplog = "oplog.rs"
+ else:
+ ol = db.system.namespaces.find_one({"name": "local.oplog.$main"})
+ if (db.system.namespaces.find_one({"name": "local.oplog.$main"}) != None):
+ oplog = "oplog.$main"
+ else:
+ message = "neither master/slave nor replica set replication detected"
+ return check_levels(None, warning, critical, message)
+
+ try:
+ set_read_preference(con.admin)
+ data = con.local.command(pymongo.son_manipulator.SON([('collstats', oplog)]))
+ except:
+ data = con.admin.command(son.SON([('collstats', oplog)]))
+
+ ol_size = data['size']
+ ol_storage_size = data['storageSize']
+ ol_used_storage = int(float(ol_size) / ol_storage_size * 100 + 1)
+ ol = con.local[oplog]
+ firstc = ol.find().sort("$natural", pymongo.ASCENDING).limit(1)[0]['ts']
+ lastc = ol.find().sort("$natural", pymongo.DESCENDING).limit(1)[0]['ts']
+ time_in_oplog = (lastc.as_datetime() - firstc.as_datetime())
+ message = "Oplog saves " + str(time_in_oplog) + " %d%% used" % ol_used_storage
+ try: # work starting from python2.7
+ hours_in_oplog = time_in_oplog.total_seconds() / 60 / 60
+ except:
+ hours_in_oplog = float(time_in_oplog.seconds + time_in_oplog.days * 24 * 3600) / 60 / 60
+ approx_level = hours_in_oplog * 100 / ol_used_storage
+ message += performance_data(perf_data, [("%.2f" % hours_in_oplog, 'oplog_time', warning, critical), ("%.2f " % approx_level, 'oplog_time_100_percent_used')])
+ return check_levels(-approx_level, -warning, -critical, message)
+
+ except Exception, e:
+ return exit_with_general_critical(e)
+
+
+def check_journal_commits_in_wl(con, warning, critical, perf_data):
+ """ Checking the number of commits which occurred in the db's write lock.
+Most commits are performed outside of this lock; committed while in the write lock is undesirable.
+Under very high write situations it is normal for this value to be nonzero. """
+
+ warning = warning or 10
+ critical = critical or 40
+ try:
+ data = get_server_status(con)
+ j_commits_in_wl = data['dur']['commitsInWriteLock']
+ message = "Journal commits in DB write lock : %d" % j_commits_in_wl
+ message += performance_data(perf_data, [(j_commits_in_wl, "j_commits_in_wl", warning, critical)])
+ return check_levels(j_commits_in_wl, warning, critical, message)
+
+ except Exception, e:
+ return exit_with_general_critical(e)
+
+
+def check_journaled(con, warning, critical, perf_data):
+ """ Checking the average amount of data in megabytes written to the recovery log in the last four seconds"""
+
+ warning = warning or 20
+ critical = critical or 40
+ try:
+ data = get_server_status(con)
+ journaled = data['dur']['journaledMB']
+ message = "Journaled : %.2f MB" % journaled
+ message += performance_data(perf_data, [("%.2f" % journaled, "journaled", warning, critical)])
+ return check_levels(journaled, warning, critical, message)
+
+ except Exception, e:
+ return exit_with_general_critical(e)
+
+
+def check_write_to_datafiles(con, warning, critical, perf_data):
+ """ Checking the average amount of data in megabytes written to the databases datafiles in the last four seconds.
+As these writes are already journaled, they can occur lazily, and thus the number indicated here may be lower
+than the amount physically written to disk."""
+ warning = warning or 20
+ critical = critical or 40
+ try:
+ data = get_server_status(con)
+ writes = data['dur']['writeToDataFilesMB']
+ message = "Write to data files : %.2f MB" % writes
+ message += performance_data(perf_data, [("%.2f" % writes, "write_to_data_files", warning, critical)])
+ return check_levels(writes, warning, critical, message)
+
+ except Exception, e:
+ return exit_with_general_critical(e)
+
+
+def get_opcounters(data, opcounters_name, host):
+ try:
+ insert = data[opcounters_name]['insert']
+ query = data[opcounters_name]['query']
+ update = data[opcounters_name]['update']
+ delete = data[opcounters_name]['delete']
+ getmore = data[opcounters_name]['getmore']
+ command = data[opcounters_name]['command']
+ except KeyError, e:
+ return 0, [0] * 100
+ total_commands = insert + query + update + delete + getmore + command
+ new_vals = [total_commands, insert, query, update, delete, getmore, command]
+ return maintain_delta(new_vals, host, opcounters_name)
+
+
+def check_opcounters(con, host, warning, critical, perf_data):
+ """ A function to get all opcounters delta per minute. In case of a replication - gets the opcounters+opcountersRepl"""
+ warning = warning or 10000
+ critical = critical or 15000
+
+ data = get_server_status(con)
+ err1, delta_opcounters = get_opcounters(data, 'opcounters', host)
+ err2, delta_opcounters_repl = get_opcounters(data, 'opcountersRepl', host)
+ if err1 == 0 and err2 == 0:
+ delta = [(x + y) for x, y in zip(delta_opcounters, delta_opcounters_repl)]
+ delta[0] = delta_opcounters[0] # only the time delta shouldn't be summarized
+ per_minute_delta = [int(x / delta[0] * 60) for x in delta[1:]]
+ message = "Test succeeded , old values missing"
+ message = "Opcounters: total=%d,insert=%d,query=%d,update=%d,delete=%d,getmore=%d,command=%d" % tuple(per_minute_delta)
+ message += performance_data(perf_data, ([(per_minute_delta[0], "total", warning, critical), (per_minute_delta[1], "insert"),
+ (per_minute_delta[2], "query"), (per_minute_delta[3], "update"), (per_minute_delta[5], "delete"),
+ (per_minute_delta[5], "getmore"), (per_minute_delta[6], "command")]))
+ return check_levels(per_minute_delta[0], warning, critical, message)
+ else:
+ return exit_with_general_critical("problem reading data from temp file")
+
+
+def check_current_lock(con, host, warning, critical, perf_data):
+ """ A function to get current lock percentage and not a global one, as check_lock function does"""
+ warning = warning or 10
+ critical = critical or 30
+ data = get_server_status(con)
+
+ lockTime = float(data['globalLock']['lockTime'])
+ totalTime = float(data['globalLock']['totalTime'])
+
+ err, delta = maintain_delta([totalTime, lockTime], host, "locktime")
+ if err == 0:
+ lock_percentage = delta[2] / delta[1] * 100 # lockTime/totalTime*100
+ message = "Current Lock Percentage: %.2f%%" % lock_percentage
+ message += performance_data(perf_data, [("%.2f" % lock_percentage, "current_lock_percentage", warning, critical)])
+ return check_levels(lock_percentage, warning, critical, message)
+ else:
+ return exit_with_general_warning("problem reading data from temp file")
+
+
+def check_page_faults(con, host, warning, critical, perf_data):
+ """ A function to get page_faults per second from the system"""
+ warning = warning or 10
+ critical = critical or 30
+ data = get_server_status(con)
+
+ try:
+ page_faults = float(data['extra_info']['page_faults'])
+ except:
+ # page_faults unsupported on the underlaying system
+ return exit_with_general_critical("page_faults unsupported on the underlaying system")
+
+ err, delta = maintain_delta([page_faults], host, "page_faults")
+ if err == 0:
+ page_faults_ps = delta[1] / delta[0]
+ message = "Page faults : %.2f ps" % page_faults_ps
+ message += performance_data(perf_data, [("%.2f" % page_faults_ps, "page_faults_ps", warning, critical)])
+ return check_levels(page_faults_ps, warning, critical, message)
+ else:
+ return exit_with_general_warning("problem reading data from temp file")
+
+
+def check_asserts(con, host, warning, critical, perf_data):
+ """ A function to get asserts from the system"""
+ warning = warning or 1
+ critical = critical or 10
+ data = get_server_status(con)
+
+ asserts = data['asserts']
+
+ #{ "regular" : 0, "warning" : 6, "msg" : 0, "user" : 12, "rollovers" : 0 }
+ regular = asserts['regular']
+ warning_asserts = asserts['warning']
+ msg = asserts['msg']
+ user = asserts['user']
+ rollovers = asserts['rollovers']
+
+ err, delta = maintain_delta([regular, warning_asserts, msg, user, rollovers], host, "asserts")
+
+ if err == 0:
+ if delta[5] != 0:
+ #the number of rollovers were increased
+ warning = -1 # no matter the metrics this situation should raise a warning
+ # if this is normal rollover - the warning will not appear again, but if there will be a lot of asserts
+ # the warning will stay for a long period of time
+ # although this is not a usual situation
+
+ regular_ps = delta[1] / delta[0]
+ warning_ps = delta[2] / delta[0]
+ msg_ps = delta[3] / delta[0]
+ user_ps = delta[4] / delta[0]
+ rollovers_ps = delta[5] / delta[0]
+ total_ps = regular_ps + warning_ps + msg_ps + user_ps
+ message = "Total asserts : %.2f ps" % total_ps
+ message += performance_data(perf_data, [(total_ps, "asserts_ps", warning, critical), (regular_ps, "regular"),
+ (warning_ps, "warning"), (msg_ps, "msg"), (user_ps, "user")])
+ return check_levels(total_ps, warning, critical, message)
+ else:
+ return exit_with_general_warning("problem reading data from temp file")
+
+
+def get_stored_primary_server_name(db):
+ """ get the stored primary server name from db. """
+ if "last_primary_server" in db.collection_names():
+ stored_primary_server = db.last_primary_server.find_one()["server"]
+ else:
+ stored_primary_server = None
+
+ return stored_primary_server
+
+
+def check_replica_primary(con, host, warning, critical, perf_data, replicaset):
+ """ A function to check if the primary server of a replica set has changed """
+ if warning is None and critical is None:
+ warning = 1
+ warning = warning or 2
+ critical = critical or 2
+
+ primary_status = 0
+ message = "Primary server has not changed"
+ db = con["nagios"]
+ data = get_server_status(con)
+ if replicaset != data['repl'].get('setName'):
+ message = "Replica set requested: %s differs from the one found: %s" % (replicaset, data['repl'].get('setName'))
+ primary_status = 2
+ return check_levels(primary_status, warning, critical, message)
+ current_primary = data['repl'].get('primary')
+ saved_primary = get_stored_primary_server_name(db)
+ if current_primary is None:
+ current_primary = "None"
+ if saved_primary is None:
+ saved_primary = "None"
+ if current_primary != saved_primary:
+ last_primary_server_record = {"server": current_primary}
+ db.last_primary_server.update({"_id": "last_primary"}, {"$set": last_primary_server_record}, upsert=True, safe=True)
+ message = "Primary server has changed from %s to %s" % (saved_primary, current_primary)
+ primary_status = 1
+ return check_levels(primary_status, warning, critical, message)
+
+
+def check_page_faults(con, sample_time, warning, critical, perf_data):
+ warning = warning or 10
+ critical = critical or 20
+ try:
+ try:
+ set_read_preference(con.admin)
+ data1 = con.admin.command(pymongo.son_manipulator.SON([('serverStatus', 1)]))
+ time.sleep(sample_time)
+ data2 = con.admin.command(pymongo.son_manipulator.SON([('serverStatus', 1)]))
+ except:
+ data1 = con.admin.command(son.SON([('serverStatus', 1)]))
+ time.sleep(sample_time)
+ data2 = con.admin.command(son.SON([('serverStatus', 1)]))
+
+ try:
+ #on linux servers only
+ page_faults = (int(data2['extra_info']['page_faults']) - int(data1['extra_info']['page_faults'])) / sample_time
+ except KeyError:
+ print "WARNING - Can't get extra_info.page_faults counter from MongoDB"
+ sys.exit(1)
+
+ message = "Page Faults: %i" % (page_faults)
+
+ message += performance_data(perf_data, [(page_faults, "page_faults", warning, critical)])
+ check_levels(page_faults, warning, critical, message)
+
+ except Exception, e:
+ exit_with_general_critical(e)
+
+
+def chunks_balance(con, database, collection, warning, critical):
+ warning = warning or 10
+ critical = critical or 20
+ nsfilter = database + "." + collection
+ try:
+ try:
+ set_read_preference(con.admin)
+ col = con.config.chunks
+ nscount = col.find({"ns": nsfilter}).count()
+ shards = col.distinct("shard")
+
+ except:
+ print "WARNING - Can't get chunks infos from MongoDB"
+ sys.exit(1)
+
+ if nscount == 0:
+ print "WARNING - Namespace %s is not sharded" % (nsfilter)
+ sys.exit(1)
+
+ avgchunksnb = nscount / len(shards)
+ warningnb = avgchunksnb * warning / 100
+ criticalnb = avgchunksnb * critical / 100
+
+ for shard in shards:
+ delta = abs(avgchunksnb - col.find({"ns": nsfilter, "shard": shard}).count())
+ message = "Namespace: %s, Shard name: %s, Chunk delta: %i" % (nsfilter, shard, delta)
+
+ if delta >= criticalnb and delta > 0:
+ print "CRITICAL - Chunks not well balanced " + message
+ sys.exit(2)
+ elif delta >= warningnb and delta > 0:
+ print "WARNING - Chunks not well balanced " + message
+ sys.exit(1)
+
+ print "OK - Chunks well balanced across shards"
+ sys.exit(0)
+
+ except Exception, e:
+ exit_with_general_critical(e)
+
+ print "OK - Chunks well balanced across shards"
+ sys.exit(0)
+
+
+def check_connect_primary(con, warning, critical, perf_data):
+ warning = warning or 3
+ critical = critical or 6
+
+ try:
+ try:
+ set_read_preference(con.admin)
+ data = con.admin.command(pymongo.son_manipulator.SON([('isMaster', 1)]))
+ except:
+ data = con.admin.command(son.SON([('isMaster', 1)]))
+
+ if data['ismaster'] == True:
+ print "OK - This server is primary"
+ return 0
+
+ phost = data['primary'].split(':')[0]
+ pport = int(data['primary'].split(':')[1])
+ start = time.time()
+
+ err, con = mongo_connect(phost, pport)
+ if err != 0:
+ return err
+
+ pconn_time = time.time() - start
+ pconn_time = round(pconn_time, 0)
+ message = "Connection to primary server " + data['primary'] + " took %i seconds" % pconn_time
+ message += performance_data(perf_data, [(pconn_time, "connection_time", warning, critical)])
+
+ return check_levels(pconn_time, warning, critical, message)
+
+ except Exception, e:
+ return exit_with_general_critical(e)
+
+
+def check_collection_state(con, database, collection):
+ try:
+ con[database][collection].find_one()
+ print "OK - Collection %s.%s is reachable " % (database, collection)
+ return 0
+
+ except Exception, e:
+ return exit_with_general_critical(e)
+
+
+def check_row_count(con, database, collection, warning, critical, perf_data):
+ try:
+ count = con[database][collection].count()
+ message = "Row count: %i" % (count)
+ message += performance_data(perf_data, [(count, "row_count", warning, critical)])
+
+ return check_levels(count, warning, critical, message)
+
+ except Exception, e:
+ return exit_with_general_critical(e)
+
+
+def build_file_name(host, action):
+ #done this way so it will work when run independently and from shell
+ module_name = re.match('(.*//*)*(.*)\..*', __file__).group(2)
+ return "/tmp/" + module_name + "_data/" + host + "-" + action + ".data"
+
+
+def ensure_dir(f):
+ d = os.path.dirname(f)
+ if not os.path.exists(d):
+ os.makedirs(d)
+
+
+def write_values(file_name, string):
+ f = None
+ try:
+ f = open(file_name, 'w')
+ except IOError, e:
+ #try creating
+ if (e.errno == 2):
+ ensure_dir(file_name)
+ f = open(file_name, 'w')
+ else:
+ raise IOError(e)
+ f.write(string)
+ f.close()
+ return 0
+
+
+def read_values(file_name):
+ data = None
+ try:
+ f = open(file_name, 'r')
+ data = f.read()
+ f.close()
+ return 0, data
+ except IOError, e:
+ if (e.errno == 2):
+ #no previous data
+ return 1, ''
+ except Exception, e:
+ return 2, None
+
+
+def calc_delta(old, new):
+ delta = []
+ if (len(old) != len(new)):
+ raise Exception("unequal number of parameters")
+ for i in range(0, len(old)):
+ val = float(new[i]) - float(old[i])
+ if val < 0:
+ val = new[i]
+ delta.append(val)
+ return 0, delta
+
+
+def maintain_delta(new_vals, host, action):
+ file_name = build_file_name(host, action)
+ err, data = read_values(file_name)
+ old_vals = data.split(';')
+ new_vals = [str(int(time.time()))] + new_vals
+ delta = None
+ try:
+ err, delta = calc_delta(old_vals, new_vals)
+ except:
+ err = 2
+ write_res = write_values(file_name, ";" . join(str(x) for x in new_vals))
+ return err + write_res, delta
+
+
+def replication_get_time_diff(con):
+ col = 'oplog.rs'
+ local = con.local
+ ol = local.system.namespaces.find_one({"name": "local.oplog.$main"})
+ if ol:
+ col = 'oplog.$main'
+ firstc = local[col].find().sort("$natural", 1).limit(1)
+ lastc = local[col].find().sort("$natural", -1).limit(1)
+ first = firstc.next()
+ last = lastc.next()
+ tfirst = first["ts"]
+ tlast = last["ts"]
+ delta = tlast.time - tfirst.time
+ return delta
+
+#
+# main app
+#
+if __name__ == "__main__":
+ sys.exit(main(sys.argv[1:]))
diff --git a/nagios-nrpe/files/plugins/check_mysql_instances b/nagios-nrpe/files/plugins/check_mysql_instances
new file mode 100755
index 00000000..479b56c0
--- /dev/null
+++ b/nagios-nrpe/files/plugins/check_mysql_instances
@@ -0,0 +1,11 @@
+#!/bin/sh
+
+for port in 3308 3309; do
+ /usr/lib/nagios/plugins/check_mysql -H 127.0.0.1 -P $port -u nrpe -p MYSQL_PASSWD
+ ret=$?
+
+ [ $ret -ne 0 ] && exit $ret
+done
+
+exit 0
+
diff --git a/nagios-nrpe/files/plugins/check_mysql_queries b/nagios-nrpe/files/plugins/check_mysql_queries
new file mode 100755
index 00000000..2c37c1eb
--- /dev/null
+++ b/nagios-nrpe/files/plugins/check_mysql_queries
@@ -0,0 +1,63 @@
+#!/bin/sh
+
+# Avant d'exécuter le check :
+# mysql> CREATE DATABASE nrpe;
+# mysql> CREATE TABLE nrpe (test TINYINT);
+# mysql> GRANT ALL ON nrpe.nrpe TO nrpe@localhost;
+
+usage() {
+ cat <&2
+Usage : $0 -H host -P port -u user -p password -b base
+All these options are required
+EOT
+}
+
+while getopts ':H:P:u:p:b:' o
+do
+ case $o in
+ H)
+ host=$OPTARG
+ ;;
+ P)
+ port=$OPTARG
+ ;;
+ u)
+ user=$OPTARG
+ ;;
+ p)
+ passwd=$OPTARG
+ ;;
+ b)
+ base=$OPTARG
+ ;;
+ ?)
+ usage
+ exit 2
+ ;;
+ esac
+done
+
+if [ -z $host ] || [ -z $port ] || [ -z $user ] || [ -z $passwd ] || [ -z $base ]; then
+ usage
+ exit 2
+fi
+
+MYSQLCMD="mysql -h $host -P $port -u $user -p$passwd $base"
+
+$MYSQLCMD -e "INSERT INTO nrpe (test) VALUES('4')"
+if [ $? -ne 0 ]; then
+ echo "INSERT query failed"
+ exit 2
+fi
+
+$MYSQLCMD -e "SELECT test FROM nrpe"
+if [ $? -ne 0 ]; then
+ echo "SELECT query failed"
+ exit 2
+fi
+
+$MYSQLCMD -e "DELETE FROM nrpe"
+if [ $? -ne 0 ]; then
+ echo "DELETE query failed"
+ exit 2
+fi
diff --git a/nagios-nrpe/files/plugins/check_nfsclient b/nagios-nrpe/files/plugins/check_nfsclient
new file mode 100755
index 00000000..a5565985
--- /dev/null
+++ b/nagios-nrpe/files/plugins/check_nfsclient
@@ -0,0 +1,23 @@
+#!/bin/sh
+
+HOSTNAME=$(hostname)
+nfsmount=/srv/data
+
+mkdir $nfsmount/.nrpe
+
+touch $nfsmount/.nrpe/.nfstest.$HOSTNAME
+if [ ! "$?" -eq "0" ]; then
+ echo "CRITICAL - error in check"
+ exit 2
+fi
+
+rm $nfsmount/.nrpe/.nfstest.$HOSTNAME
+if [ ! "$?" -eq "0" ]; then
+ echo "CRITICAL - error in check"
+ exit 2
+fi
+
+rmdir $nfsmount/.nrpe
+
+echo "OK - All fine"
+exit 0
diff --git a/nagios-nrpe/files/plugins/check_nfsserver b/nagios-nrpe/files/plugins/check_nfsserver
new file mode 100755
index 00000000..80752bfd
--- /dev/null
+++ b/nagios-nrpe/files/plugins/check_nfsserver
@@ -0,0 +1,14 @@
+#!/bin/sh
+# Check if nfs server is running using rpcinfo
+
+rpcinfo -u localhost nfs
+if [ $? -ne 0 ]; then
+ exit 2
+fi
+
+rpcinfo -t localhost nfs
+if [ $? -ne 0 ]; then
+ exit 2
+fi
+
+# vim: set ft=shell
diff --git a/nagios-nrpe/files/plugins/check_openvpn b/nagios-nrpe/files/plugins/check_openvpn
new file mode 100755
index 00000000..b62ea6bc
--- /dev/null
+++ b/nagios-nrpe/files/plugins/check_openvpn
@@ -0,0 +1,215 @@
+#!/usr/bin/perl -w
+
+#######################################################################
+#
+# Copyright (c) 2007 Jaime Gascon Romero
+#
+# License Information:
+# 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 .
+#
+# $Id: check_openvpn.pl,v 1.1 2014-09-29 08:39:24 rdessort Exp $
+# $Revision: 1.1 $
+# Home Site: http://emergeworld.blogspot.com/
+# #####################################################################
+
+use diagnostics;
+use strict;
+use Net::Telnet ();
+use Getopt::Long qw(:config no_ignore_case);
+use vars qw($PROGNAME $VERSION);
+use lib "/usr/lib/nagios/plugins/";
+use utils qw(%ERRORS);
+
+$PROGNAME = "check_openvpn";
+$VERSION = '$Revision: 1.1 $';
+
+$ENV{'PATH'}='';
+$ENV{'BASH_ENV'}='';
+$ENV{'ENV'}='';
+
+my ($opt_h, $opt_H, $opt_p, $opt_P, $opt_t, $opt_i, $opt_n, $opt_c, $opt_w, $opt_C, $opt_r);
+
+sub print_help ();
+sub print_usage ();
+
+GetOptions
+ ("h" => \$opt_h, "help" => \$opt_h,
+ "H=s" => \$opt_H, "host=s" => \$opt_H,
+ "p=i" => \$opt_p, "port=i" => \$opt_p,
+ "P=s" => \$opt_P, "password=s" => \$opt_P,
+ "t=i" => \$opt_t, "timeout=i" => \$opt_t,
+ "i" => \$opt_i, "ip" => \$opt_i,
+ "n" => \$opt_n, "numeric" => \$opt_n,
+ "c" => \$opt_c, "critical" => \$opt_c,
+ "w" => \$opt_w, "warning" => \$opt_w,
+ "C=s" => \$opt_C, "common_name=s" => \$opt_C,
+ "r=s" => \$opt_r, "remote_ip=s" => \$opt_r,
+ ) or exit $ERRORS{'UNKNOWN'};
+
+# default values
+unless ( defined $opt_t ) {
+ $opt_t = 10;
+}
+
+if ($opt_h) {print_help(); exit $ERRORS{'OK'};}
+
+if ( ! defined($opt_H) || ! defined($opt_p) ) {
+ print_usage();
+ exit $ERRORS{'UNKNOWN'}
+}
+
+my @lines;
+my @clients;
+my @clients_ip;
+my $t;
+
+eval {
+$t = new Net::Telnet (Timeout => $opt_t,
+ Port => $opt_p,
+ Prompt => '/END$/'
+ );
+$t->open($opt_H);
+if ( defined $opt_P ) {
+ $t->waitfor('/ENTER PASSWORD:$/');
+ $t->print($opt_P);
+}
+$t->waitfor('/^$/');
+@lines = $t->cmd("status 2");
+$t->close;
+};
+
+if ($@) {
+ print "OpenVPN Critical: Can't connect to server\n";
+ exit $ERRORS{'CRITICAL'};
+}
+
+
+if (defined $opt_i || defined $opt_r) {
+ foreach (@lines) {
+ if ($_ =~ /CLIENT_LIST,.*,(\d+\.\d+\.\d+\.\d+):\d+,/) {
+ push @clients_ip, $1;
+ }
+}
+ if (defined $opt_i) {
+ print "OpenVPN OK: "."@clients_ip ";
+ exit $ERRORS{'OK'};
+ } elsif (defined $opt_r) {
+ if ( ! grep /\b$opt_r\b/, @clients_ip) {
+ if (defined $opt_c) {
+ print "OpenVPN CRITICAL: $opt_r don't found";
+ exit $ERRORS{'CRITICAL'};
+ } else {
+ print "OpenVPN WARNING: $opt_r don't found";
+ exit $ERRORS{'WARNING'};
+ }
+ }
+ print "OpenVPN OK: "."@clients_ip ";
+ exit $ERRORS{'OK'};
+ }
+}
+
+foreach (@lines) {
+ if ($_ =~ /CLIENT_LIST,(.*),\d+\.\d+\.\d+\.\d+:\d+,/) {
+ push @clients, $1;
+ }
+}
+
+if (defined $opt_C) {
+ if ( ! grep /\b$opt_C\b/, @clients) {
+ if (defined $opt_c) {
+ print "OpenVPN CRITICAL: $opt_C don't found";
+ exit $ERRORS{'CRITICAL'};
+ } else {
+ print "OpenVPN WARNING: $opt_C don't found";
+ exit $ERRORS{'WARNING'};
+ }
+ }
+}
+
+
+if (defined $opt_n) {
+print "OpenVPN OK: ".@clients." connected clients.";
+exit $ERRORS{'OK'};
+}
+
+print "OpenVPN OK: "."@clients ";
+exit $ERRORS{'OK'};
+
+#######################################################################
+###### Subroutines ####################################################
+
+sub print_usage() {
+ print "Usage: $PROGNAME -H | --host -p | --port [-P | --password] [-t | --timeout]
+ [-i | --ip] [-n | --numeric] [-C | --common_name] [-r | --remote_ip] [-c | --critical] [-w | --warning]\n\n";
+ print " $PROGNAME [-h | --help]\n";
+}
+
+sub print_help() {
+ print "$PROGNAME $VERSION\n\n";
+ print "Copyright (c) 2007 Jaime Gascon Romero
+
+Nagios plugin to check the clients connected to a openvpn server.
+
+";
+ print_usage();
+ print "
+-H | --host
+ IP address or hostname of the openvpn server.
+
+-p | --port
+ Management port interface of the openvpn server.
+
+-P | --password
+ Password for the management interface of the openvpn server.
+
+-t | --timeout
+ Timeout for the connection attempt. Optional, default 10 seconds.
+
+
+ Optional parameters
+ ===================
+
+-i | --ip
+ Prints the IP address of the remote client instead of the common name.
+
+-n | --numeric
+ Prints the number of clients connected to the openvpn server.
+
+
+ Matching Parameters
+ ===================
+
+-C | --common_name
+ The common name, as it is specified in the client certificate, who is wanted to check.
+
+-r | --remote_ip
+ The client remote ip address who is wanted to check.
+
+-c | --critical
+ Exits with CRITICAL status if the client specified by the common name or the remote ip address is not connected.
+
+-w | --warning
+ Exits with WARNING status if the client specified by the common name or the remote ip address is not connected.
+
+
+ Other Parameters
+ ================
+
+-h | --help
+ Show this help.
+";
+
+}
+
+# vim:sts=2:sw=2:ts=2:et
diff --git a/nagios-nrpe/files/plugins/check_process b/nagios-nrpe/files/plugins/check_process
new file mode 100755
index 00000000..780ef233
--- /dev/null
+++ b/nagios-nrpe/files/plugins/check_process
@@ -0,0 +1,7 @@
+#!/bin/bash
+
+rc=0
+for proc in cron rsyslogd ntpd munin-node; do
+ sudo /usr/lib/nagios//plugins/check_procs -C $proc -c 1:
+ rc=$(($rc|$?))
+done
diff --git a/nagios-nrpe/files/plugins/check_spamd b/nagios-nrpe/files/plugins/check_spamd
new file mode 100755
index 00000000..df8477da
--- /dev/null
+++ b/nagios-nrpe/files/plugins/check_spamd
@@ -0,0 +1,197 @@
+#!/usr/bin/perl -w
+
+# $Id: check_spamd.pl,v 1.1 2009-08-11 09:47:11 tmartin Exp $
+#
+# check SPAMD connections
+#
+# Copyright (c) 2005, 2006 Holger Weiss
+#
+# 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 2
+# 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, write to the Free Software
+# Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
+#
+# ---------------------------------------------------------------
+#
+# New in 1.4:
+# - Checking SPAMD using a UNIX domain socket specified via the new
+# -U/--socket option is now supported (thanks to Zeus Panchenko).
+#
+# New in 1.3:
+# - The "-v" option now works again.
+#
+# New in 1.2:
+# - A proper error message is reported if spamd(1) closes the connection
+# unexpectedly. This happens, for example, if spamd(1)s "-A" option is
+# used, but the client hasn't been added to the list of authorized hosts.
+# - Minor code cleanup.
+
+use strict;
+use Socket;
+use Getopt::Long;
+use lib "/usr/lib/nagios/plugins";
+use utils qw(%ERRORS $TIMEOUT &print_revision &support);
+use vars qw($opt_H $opt_U $opt_V $opt_c $opt_h $opt_p $opt_t $opt_v $opt_w);
+
+sub talk_spamd ($$);
+sub die_crit ($);
+sub die_warn ($);
+sub die_unknown ($);
+sub print_usage ();
+sub print_help ();
+
+my $PROGNAME = "check_spamd";
+my $PORT = 783;
+my $CRIT = $TIMEOUT;
+my ($spamd_target, $spamd_port, $warning, $critical, $timeout, $response,
+ $start, $duration);
+
+$SIG{'ALRM'} = sub { die_unknown("Timeout"); };
+$ENV{'PATH'}='';
+$ENV{'ENV'}='';
+
+Getopt::Long::Configure("bundling");
+if (!GetOptions("V" => \$opt_V, "version" => \$opt_V,
+ "h" => \$opt_h, "help" => \$opt_h,
+ "v+" => \$opt_v, "verbose+" => \$opt_v,
+ "H=s" => \$opt_H, "hostname=s" => \$opt_H,
+ "U=s" => \$opt_U, "socket=s" => \$opt_U,
+ "c=i" => \$opt_c, "critical=i" => \$opt_c,
+ "p=i" => \$opt_p, "port=i" => \$opt_p,
+ "t=i" => \$opt_t, "timeout=i" => \$opt_t,
+ "w=i" => \$opt_w, "warning=i" => \$opt_w)) {
+ print "SPAMD UNKNOWN - Error processing command line options\n";
+ print_usage();
+ exit $ERRORS{'UNKNOWN'};
+}
+if ($opt_V) {
+ print_revision($PROGNAME,'$Revision: 1.1 $ ');
+ exit $ERRORS{'OK'};
+}
+if ($opt_h) {
+ print_help();
+ exit $ERRORS{'OK'};
+}
+if (not $opt_H and not $opt_U) {
+ print "SPAMD UNKNOWN - No target host or socket specified\n";
+ print_usage();
+ exit $ERRORS{'UNKNOWN'};
+}
+if ($opt_U and ($opt_H or $opt_p)) {
+ print "SPAMD UNKNOWN - UNIX domain socket AND host/port specified\n";
+ print_usage();
+ exit $ERRORS{'UNKNOWN'};
+}
+alarm($opt_t ? $opt_t : $TIMEOUT);
+$critical = $opt_c ? $opt_c : $CRIT;
+$warning = $opt_w ? $opt_w : $critical;
+if ($warning > $critical) {
+ print "SPAMD UNKNOWN - Warning larger than critical threshold\n";
+ print_usage();
+ exit $ERRORS{'UNKNOWN'};
+}
+if ($opt_U) {
+ $spamd_target = $opt_U;
+ $spamd_port = undef;
+} else {
+ $spamd_target = $opt_H;
+ $spamd_port = $opt_p ? $opt_p : getservbyname("spamd", "tcp");
+ $spamd_port = $PORT unless defined $spamd_port;
+}
+$start = time;
+$response = talk_spamd($spamd_target, $spamd_port);
+$duration = time - $start;
+die_crit("$response - $duration sec. response time") if $duration >= $critical;
+die_warn("$response - $duration sec. response time") if $duration >= $warning;
+$response .= " - $duration sec. response time" if $opt_v;
+print "SPAMD OK - Server response: $response\n";
+exit $ERRORS{'OK'};
+
+sub talk_spamd ($$) {
+ my ($host, $port) = @_;
+ my ($buffer, $iaddr, $message, $n, $paddr, $proto, $status, $str);
+
+ if ($port) { # check host name or IP address
+ $iaddr = inet_aton($host)
+ || die_unknown("Invalid hostname/address: $host");
+ $paddr = sockaddr_in($port, $iaddr);
+ socket(SOCK, PF_INET, SOCK_STREAM, getprotobyname('tcp'))
+ || die_unknown("Socket error: $!");
+ } else { # check UNIX domain socket
+ $paddr = sockaddr_un($host);
+ socket(SOCK, PF_UNIX, SOCK_STREAM, 0)
+ || die_unknown("Socket error: $!");
+ }
+ connect(SOCK, $paddr) || die_crit("Error connecting to $host: $!");
+ defined(send(SOCK, "PING SPAMC/1.2\r\n", 0))
+ || die_unknown("Error sending request to $host: $!");
+ $buffer = ;
+ die_unknown("Connection reset by peer") unless $buffer;
+ close SOCK || die_unknown("Cannot close connection: $!");
+ $n = ($proto, $status, $message)
+ = ($buffer =~ /^(\S+) +(\S+) +([^\r\n]+)/);
+ if ($n != 3) {
+ my $error = "Protocol error";
+
+ $error .= " - Server said: $buffer" if $buffer;
+ die_crit($error);
+ }
+ $str = "$proto $status $message";
+ die_crit($str) unless $status == 0;
+ $str;
+}
+
+sub die_unknown ($) {
+ printf "SPAMD UNKNOWN - %s\n", shift;
+ exit $ERRORS{'UNKNOWN'};
+}
+
+sub die_warn ($) {
+ printf "SPAMD WARNING - %s\n", shift;
+ exit $ERRORS{'WARNING'};
+}
+
+sub die_crit ($) {
+ printf "SPAMD CRITICAL - %s\n", shift;
+ exit $ERRORS{'CRITICAL'};
+}
+
+sub print_usage () {
+ print "Usage: $PROGNAME { -H host | -U socket } [-p port] [-w warn]\n" .
+ " [-c crit] [-t timeout] [-v]\n";
+}
+
+sub print_help () {
+ print_revision($PROGNAME, '$Revision: 1.1 $');
+ print "Copyright (c) 2005, 2006 Holger Weiss\n\n";
+ print "Check SPAMD connections with the specified host.\n\n";
+ print_usage();
+ print </dev/null
-
-- name: Adjust rights on private key
- file:
- path: /etc/ssl/private/{{ ansible_fqdn }}.key
- owner: root
- group: ssl-cert
- mode: 0640
-
-- name: Create certificate for default site
- shell: openssl x509 -req -days 3650 -sha256 -in /etc/ssl/{{ ansible_fqdn }}.csr -signkey /etc/ssl/private/{{ ansible_fqdn }}.key -out /etc/ssl/certs/{{ ansible_fqdn }}.crt 2>/dev/null
diff --git a/nginx/tasks/main.yml b/nginx/tasks/main.yml
index fe1c4758..5cc397c4 100644
--- a/nginx/tasks/main.yml
+++ b/nginx/tasks/main.yml
@@ -7,17 +7,34 @@
tags:
- nginx
-- name: Install Nginx configuration
- template:
- src: nginx.conf.j2
+# TODO: find a way to override the main configuration
+# without touching the main file
+
+- name: customize worker_connections
+ lineinfile:
dest: /etc/nginx/nginx.conf
+ regexp: '^(\s*worker_connections)\s+.+;'
+ line: ' worker_connections 1024;'
+ insertafter: 'events \{'
+
+- name: use epoll
+ lineinfile:
+ dest: /etc/nginx/nginx.conf
+ regexp: '^(\s*use)\s+.+;'
+ line: ' use epoll;'
+ insertafter: 'events \{'
+
+- name: Install Nginx http configuration
+ copy:
+ src: nginx/evolinux-defaults.conf
+ dest: /etc/nginx/conf.d/z-evolinux-defaults.conf
mode: 0640
# force: yes
notify: reload nginx
tags:
- nginx
-# TODO: verify that those permisisons are correct :
+# TODO: verify that those permissions are correct :
# not too strict for private_ipaddr_whitelist
# and not too loose for private_htpasswd
@@ -79,37 +96,6 @@
with_items: "{{ nginx_private_htpasswd_absent }}"
notify: reload nginx
-- name: Check if a certificate is present for default site
- stat:
- path: /etc/ssl/certs/{{ ansible_fqdn }}.crt
- register: stat_crt
- tags:
- - nginx
-
-- include: create_default_cert.yml
- when: not stat_crt.stat.exists
- tags:
- - nginx
-
-- name: Install Nginx default site
- template:
- src: default_site.j2
- dest: /etc/nginx/sites-available/default
- mode: 0640
- # force: yes
- notify: reload nginx
- tags:
- - nginx
-
-- name: Enable Nginx default site
- file:
- src: /etc/nginx/sites-available/default
- dest: /etc/nginx/sites-enabled/default
- state: link
- notify: reload nginx
- tags:
- - nginx
-
- name: Verify that the service is enabled and started
service:
name: nginx
@@ -125,7 +111,12 @@
tags:
- munin
-- include: configure_munin.yml
+- include: munin_vhost.yml
+ when: stat_munin_node.stat.exists
+ tags:
+ - munin
+
+- include: munin_graphs.yml
when: stat_munin_node.stat.exists
tags:
- munin
diff --git a/nginx/tasks/munin_graphs.yml b/nginx/tasks/munin_graphs.yml
new file mode 100644
index 00000000..1133f525
--- /dev/null
+++ b/nginx/tasks/munin_graphs.yml
@@ -0,0 +1,18 @@
+---
+
+- name: Copy Munin config for Nginx
+ copy:
+ src: munin/evolinux.nginx
+ dest: /etc/munin/plugin-conf.d/
+ mode: 0644
+ notify: restart munin
+
+- name: Enable Munin plugins for Nginx
+ file:
+ src: '/usr/share/munin/plugins/{{ item }}'
+ dest: '/etc/munin/plugins/{{ item }}'
+ state: link
+ with_items:
+ - nginx_request
+ - nginx_status
+ notify: restart munin
diff --git a/nginx/tasks/configure_munin.yml b/nginx/tasks/munin_vhost.yml
similarity index 63%
rename from nginx/tasks/configure_munin.yml
rename to nginx/tasks/munin_vhost.yml
index 0b75af18..c97da1a2 100644
--- a/nginx/tasks/configure_munin.yml
+++ b/nginx/tasks/munin_vhost.yml
@@ -3,24 +3,8 @@
lineinfile:
dest: /etc/hosts
regexp: 'munin$'
- line: '127.0.0.1 munin'
-
-- name: Copy Munin config for Nginx
- copy:
- src: munin/plugin-conf.d/evolinux.nginx
- dest: /etc/munin/plugin-conf.d/
- mode: 0644
- notify: restart munin
-
-- name: Enable Munin plugins for Nginx
- file:
- src: '/usr/share/munin/plugins/{{ item }}'
- dest: '/etc/munin/plugins/{{ item }}'
- state: link
- with_items:
- - nginx_request
- - nginx_status
- notify: restart munin
+ line: '127.0.0.1 munin'
+ insertafter: EOF
- name: Ensure packages for Munin CGI are installed
apt:
diff --git a/nginx/templates/nginx.conf.j2 b/nginx/templates/nginx.conf.j2
deleted file mode 100644
index d58a230a..00000000
--- a/nginx/templates/nginx.conf.j2
+++ /dev/null
@@ -1,88 +0,0 @@
-user www-data;
-worker_processes {{ nginx_worker_processes }};
-pid /var/run/nginx.pid;
-
-events {
- worker_connections 1024;
- #multi_accept on;
- use epoll;
-}
-
-http {
- ##
- # Basic Settings
- ##
-
- sendfile on;
- tcp_nopush on;
- tcp_nodelay on;
- keepalive_timeout 65;
- types_hash_max_size 2048;
-
- ##
- # Tuning Evolix
- ##
- #connection_pool_size 256;
- #client_header_buffer_size 64k;
- #client_body_buffer_size 128k;
- #large_client_header_buffers 8 16k;
- #request_pool_size 4k;
- #client_header_timeout 10m;
- #client_body_timeout 10m;
- #send_timeout 10m;
- #client_max_body_size 50m;
- server_tokens off;
- server_names_hash_max_size 512;
- server_names_hash_bucket_size 128;
- server_name_in_redirect off;
-
- include /etc/nginx/mime.types;
- default_type application/octet-stream;
-
- ##
- # Gzip Settings
- ##
-
- gzip on;
- gzip_disable "msie6";
-
- # gzip_vary on;
- # gzip_proxied any;
- # gzip_comp_level 6;
- # gzip_buffers 16 8k;
- # gzip_http_version 1.1;
- # gzip_types text/plain text/css application/json application/x-javascript text/xml application/xml application/xml+rss text/javascript;
-
- index index.html;
-
- ##
- # Logging Settings
- ##
-
- access_log /var/log/nginx/access_log;
- error_log /var/log/nginx/error_log;
-
- ##
- # nginx-naxsi config
- ##
- # Uncomment it if you installed nginx-naxsi
- ##
-
- #include /etc/nginx/naxsi_core.rules;
-
- ##
- # nginx-passenger config
- ##
- # Uncomment it if you installed nginx-passenger
- ##
-
- #passenger_root /usr;
- #passenger_ruby /usr/bin/ruby;
-
- ##
- # Virtual Host Configs
- ##
-
- include /etc/nginx/conf.d/*.conf;
- include /etc/nginx/sites-enabled/*;
-}
diff --git a/nodejs/README.md b/nodejs/README.md
new file mode 100644
index 00000000..f93ccfbd
--- /dev/null
+++ b/nodejs/README.md
@@ -0,0 +1,11 @@
+# nodejs
+
+Install NodeJS from NPM repositories.
+
+## Tasks
+
+Everything is in the `tasks/main.yml` file.
+
+## Variables
+
+* `nodejs_apt_version`: verison for the repository (default: `node_6.x`).
diff --git a/nodejs/defaults/main.yml b/nodejs/defaults/main.yml
new file mode 100644
index 00000000..f51e88aa
--- /dev/null
+++ b/nodejs/defaults/main.yml
@@ -0,0 +1,2 @@
+---
+nodejs_apt_version: 'node_6.x'
diff --git a/nodejs/tasks/main.yml b/nodejs/tasks/main.yml
new file mode 100644
index 00000000..3aceb48b
--- /dev/null
+++ b/nodejs/tasks/main.yml
@@ -0,0 +1,37 @@
+---
+
+
+- name: APT https transport is enabled
+ apt:
+ name: apt-transport-https
+ state: installed
+ tags:
+ - system
+ - packages
+
+- name: Node GPG key is installed
+ apt_key:
+ url: https://deb.nodesource.com/gpgkey/nodesource.gpg.key
+ state: present
+ tags:
+ - system
+ - packages
+ - nodejs
+
+- name: Node sources list ({{ nodejs_apt_version }}) is available
+ apt_repository:
+ repo: "deb https://deb.nodesource.com/{{ nodejs_apt_version }} jessie main"
+ state: present
+ tags:
+ - system
+ - packages
+ - nodejs
+
+- name: Node is installed
+ apt:
+ name: nodejs
+ update_cache: yes
+ state: installed
+ tags:
+ - packages
+ - nodejs
diff --git a/postfix/README.md b/postfix/README.md
new file mode 100644
index 00000000..24621cfb
--- /dev/null
+++ b/postfix/README.md
@@ -0,0 +1,18 @@
+# postfix
+
+Install Postfix
+
+## Tasks
+
+Everything is in the `tasks/main.yml` file.
+
+## Available variables
+
+Main variables are :
+
+* `general_alert_email`: email address to send various alert messages (default: `root@localhost`).
+* `postfix_alias_email`: email address for messages sent to root (default: `general_alert_email`) ;
+* `postfix_slow_transports_enabled`: configure slow transports (default: `True`) ;
+* `postfix_remove_exim`: remove Exim4 packages (default: `True`) ;
+
+The full list of variables (with default values) can be found in `defaults/main.yml`.
diff --git a/postfix/defaults/main.yml b/postfix/defaults/main.yml
new file mode 100644
index 00000000..2e3bbb94
--- /dev/null
+++ b/postfix/defaults/main.yml
@@ -0,0 +1,6 @@
+---
+general_alert_email: "root@localhost"
+postfix_alias_email: Null
+
+postfix_slow_transports_enabled: True
+postfix_remove_exim: True
diff --git a/postfix/handlers/main.yml b/postfix/handlers/main.yml
new file mode 100644
index 00000000..7894a013
--- /dev/null
+++ b/postfix/handlers/main.yml
@@ -0,0 +1,17 @@
+---
+
+- name: newaliases
+ command: newaliases
+
+- name: restart postfix
+ service:
+ name: postfix
+ state: restarted
+
+- name: reload postfix
+ service:
+ name: postfix
+ state: reloaded
+
+- name: postmap transport
+ command: postmap /etc/postfix/transport
diff --git a/postfix/tasks/main.yml b/postfix/tasks/main.yml
new file mode 100644
index 00000000..4d7ec042
--- /dev/null
+++ b/postfix/tasks/main.yml
@@ -0,0 +1,83 @@
+---
+
+- name: packages are installed
+ apt:
+ name: "{{ item }}"
+ state: present
+ with_items:
+ - postfix
+ - mailgraph
+ tags:
+ - packages
+ - postfix
+
+- name: main.cf is configured
+ lineinfile:
+ dest: /etc/postfix/main.cf
+ regexp: "^#? *{{ item.key }} *="
+ line: "{{ item.key }} = {{ item.value }}"
+ with_items:
+ - { key: "myorigin", value: "/etc/mailname" }
+ - { key: "disable_vrfy_command", value: "yes" }
+ notify: reload postfix
+ tags:
+ - postfix
+
+- name: fetch users list
+ shell: getent passwd | cut -d":" -f 1 | grep -v root
+ register: non_root_users_list
+ changed_when: False
+ tags:
+ - postfix
+
+- name: each user is aliased to root
+ lineinfile:
+ dest: /etc/aliases
+ regexp: "^{{ item }}:.*"
+ line: "{{ item }}: root"
+ with_items: "{{ non_root_users_list.stdout_lines }}"
+ notify: newaliases
+ tags:
+ - postfix
+
+- name: additional users address aliased to root
+ lineinfile:
+ dest: /etc/aliases
+ regexp: "^{{ item }}:.*"
+ line: "{{ item }}: root"
+ with_items:
+ - postmaster
+ - abuse
+ - mailer-daemon
+ notify: newaliases
+ tags:
+ - postfix
+
+- name: root alias is configured
+ lineinfile:
+ dest: /etc/aliases
+ regexp: "^root:"
+ line: "root: {{ postfix_alias_email or general_alert_email | mandatory }}"
+ notify: newaliases
+ tags:
+ - postfix
+
+- name: exim4 is absent
+ apt:
+ name: "{{ item }}"
+ purge: yes
+ state: absent
+ with_items:
+ - exim4
+ - exim4-base
+ - exim4-config
+ - exim4-daemon-light
+ when: postfix_remove_exim
+ tags:
+ - packages
+ - postfix
+
+- include: slow_transports.yml
+ when: postfix_slow_transports_enabled
+ tags:
+ - postfix
diff --git a/postfix/tasks/slow_transports.yml b/postfix/tasks/slow_transports.yml
new file mode 100644
index 00000000..da32df89
--- /dev/null
+++ b/postfix/tasks/slow_transports.yml
@@ -0,0 +1,69 @@
+---
+
+- name: slow transport is defined in master.cf
+ lineinfile:
+ dest: /etc/postfix/master.cf
+ regexp: "^slow "
+ line: "slow unix - - n - - smtp"
+ notify: reload postfix
+ tags:
+ - postfix
+
+- name: list of providers for slow transport
+ lineinfile:
+ dest: /etc/postfix/transport
+ line: "{{ item }}"
+ create: yes
+ with_items:
+ - "orange.fr slow:"
+ - "wanadoo.fr slow:"
+ - "voila.fr slow:"
+ - "laposte slow:"
+ - "yahoo.fr slow:"
+ - "yahoo.com slow:"
+ - "hotmail.fr slow:"
+ - "hotmail.com slow:"
+ notify:
+ - postmap transport
+ - reload postfix
+ tags:
+ - postfix
+
+# - name: main.cf is configured for slow transports
+# lineinfile:
+# dest: /etc/postfix/main.cf
+# regexp: "^{{ item.key }} ="
+# line: "{{ item.key }} = {{ item.value }}"
+# with_items:
+# - { key: "minimal_backoff_time", value: "2h" }
+# - { key: "maximal_backoff_time", value: "6h" }
+# - { key: "maximal_queue_lifetime", value: "4d" }
+# - { key: "queue_run_delay", value: "100s" }
+# - { key: "bounce_queue_lifetime", value: "1d" }
+# - { key: "initial_destination_concurrency", value: "5" }
+# - { key: "default_destination_concurrency_limit", value: "20" }
+# - { key: "slow_destination_rate_delay", value: "0" }
+# - { key: "slow_destination_concurrency_limit", value: "1" }
+# - { key: "slow_destination_concurrency_failed_cohort_limit", value: "100" }
+# - { key: "slow_destination_recipient_limit", value: "25" }
+# - { key: "transport_maps", value: "hash:$config_directory/transport" }
+# notify: reload postfix
+
+- name: main.cf is configured for slow transports
+ blockinfile:
+ dest: /etc/postfix/main.cf
+ marker: "# {mark} Slow transports configuration (managed by Ansible)"
+ block: |
+ minimal_backoff_time = 2h
+ maximal_backoff_time = 6h
+ maximal_queue_lifetime = 4d
+ queue_run_delay = 100s
+ bounce_queue_lifetime = 1d
+ initial_destination_concurrency = 5
+ default_destination_concurrency_limit = 20
+ slow_destination_rate_delay = 0
+ slow_destination_concurrency_limit = 1
+ slow_destination_concurrency_failed_cohort_limit = 100
+ slow_destination_recipient_limit = 25
+ transport_maps = hash:$config_directory/transport
+ notify: reload postfix
diff --git a/proftpd/README.md b/proftpd/README.md
new file mode 100644
index 00000000..55168279
--- /dev/null
+++ b/proftpd/README.md
@@ -0,0 +1,16 @@
+# fail2ban
+
+Install Fail2ban.
+
+## Tasks
+
+Everything is in the `tasks/main.yml` file.
+
+## Available variables
+
+Main variables are :
+
+* `general_alert_email`: email address to send various alert messages (default: `root@localhost`).
+* `fail2ban_alert_email`: email address for messages sent to root (default: `general_alert_email`).
+
+The full list of variables (with default values) can be found in `defaults/main.yml`.
diff --git a/proftpd/defaults/main.yml b/proftpd/defaults/main.yml
new file mode 100644
index 00000000..33f9d284
--- /dev/null
+++ b/proftpd/defaults/main.yml
@@ -0,0 +1,6 @@
+---
+general_alert_email: "root@localhost"
+fail2ban_alert_email: Null
+
+proftpd_hostname: "{{ ansible_hostname }}"
+proftpd_fqdn: "{{ ansible_fqdn }}"
diff --git a/proftpd/handlers/main.yml b/proftpd/handlers/main.yml
new file mode 100644
index 00000000..0914d289
--- /dev/null
+++ b/proftpd/handlers/main.yml
@@ -0,0 +1,5 @@
+---
+- name: restart proftpd
+ service:
+ name: proftpd
+ state: restarted
diff --git a/proftpd/tasks/main.yml b/proftpd/tasks/main.yml
new file mode 100644
index 00000000..8acaa3fc
--- /dev/null
+++ b/proftpd/tasks/main.yml
@@ -0,0 +1,34 @@
+---
+- name: package is installed
+ apt:
+ name: proftpd-basic
+ state: installed
+ tags:
+ - proftpd
+ - packages
+
+- name: ftpusers groupe exists
+ group:
+ name: ftpusers
+ state: present
+ notify: restart proftpd
+ tags:
+ - proftpd
+
+- name: local jail is installed
+ template:
+ src: evolinux.conf.j2
+ dest: /etc/proftpd/conf.d/z-evolinux.conf
+ mode: 0644
+ notify: restart proftpd
+ tags:
+ - proftpd
+
+- name: mod_tls_memcache is disabled
+ replace:
+ dest: /etc/proftpd/modules.conf
+ regexp: '^LoadModule mod_tls_memcache.c'
+ replace: '#LoadModule mod_tls_memcache.c'
+ notify: restart proftpd
+ tags:
+ - proftpd
diff --git a/proftpd/templates/evolinux.conf.j2 b/proftpd/templates/evolinux.conf.j2
new file mode 100644
index 00000000..e02820d6
--- /dev/null
+++ b/proftpd/templates/evolinux.conf.j2
@@ -0,0 +1,29 @@
+# Evolix's specific configuration
+
+ServerName "{{ proftpd_hostname }} FTP Server"
+ServerIdent on "FTP Server Ready"
+AccessGrantMsg "Hey, bienvenue %u sur le serveur FTP {{ proftpd_fqdn }} !"
+
+# Connexion limits
+MaxInstances 50
+MaxClients 40
+MaxClientsPerHost 20
+
+# Network settings
+PassivePorts 60000 61000
+UseReverseDNS off
+IdentLookups off
+
+# Local permissions
+DefaultRoot ~
+Umask 137 027
+RequireValidShell off
+UseFtpUsers off
+
+# Allow RESUME (REST command)
+AllowStoreRestart on
+
+
+ AllowGroup ftpusers
+ DenyAll
+
diff --git a/squid/README.md b/squid/README.md
new file mode 100644
index 00000000..27b80d66
--- /dev/null
+++ b/squid/README.md
@@ -0,0 +1,15 @@
+# squid
+
+Install Squid.
+
+## Tasks
+
+Everything is in the `tasks/main.yml` file.
+
+## Available variables
+
+* `squid_address` : IP address for internal/outgoing traffic (default: Ansible detected IPv4 address) ;
+* `general_alert_email`: email address to send various alert messages (default: `root@localhost`).
+* `log2mail_alert_email`: email address to send Log2mail messages to (default: `general_alert_email`).
+
+The full list of variables (with default values) can be found in `defaults/main.yml`.
diff --git a/squid/defaults/main.yml b/squid/defaults/main.yml
new file mode 100644
index 00000000..35b4a91f
--- /dev/null
+++ b/squid/defaults/main.yml
@@ -0,0 +1,5 @@
+---
+general_alert_email: "root@localhost"
+log2mail_alert_email: Null
+
+squid_address: "{{ ansible_default_ipv4.address }}"
diff --git a/squid/files/whitelist-custom.conf b/squid/files/whitelist-custom.conf
new file mode 100644
index 00000000..5d930f2c
--- /dev/null
+++ b/squid/files/whitelist-custom.conf
@@ -0,0 +1,2 @@
+### Custom whitelist
+# http://example.com/.*
diff --git a/squid/files/whitelist-evolinux.conf b/squid/files/whitelist-evolinux.conf
new file mode 100644
index 00000000..30c5140e
--- /dev/null
+++ b/squid/files/whitelist-evolinux.conf
@@ -0,0 +1,116 @@
+### Evolix & System
+http://.*evolix.(net|org|com|fr)/.*
+http://.*debian.org/.*
+http://www.backports.org/.*
+http://backports.debian.org/.*
+http://www.kernel.org/.*
+http://hwraid.le-vert.net/.*
+http://.*clamav.net/.*
+http://spamassassin.apache.org/.*
+http://.*sa-update.*
+http://pear.php.net/.*
+
+### CMS / Wordpress / Drupal / ...
+# Wordpress
+http://.*akismet.com/.*
+http://.*wordpress.(org|com)/.*
+http://.*gravatar.com/.*
+http://www.wordpress-fr.net/.*
+http://pixel.wp.com/.*
+# Wordpress pingback
+http://rpc.pingomatic.com/.*
+http://blo.gs/ping.php
+http://ping.blo.gs/.*
+http://ping.baidu.com/ping/RPC2
+http://blogsearch.google.ru/ping/RPC2
+http://ping.pubsub.com/ping
+http://rpc.twingly.com/.*
+http://api.feedster.com/ping
+http://api.moreover.com/RPC2
+http://api.moreover.com/ping
+http://www.blogdigger.com/RPC2
+http://www.blogshares.com/rpc.php
+http://www.blogsnow.com/ping
+http://www.blogstreet.com/xrbin/xmlrpc.cgi
+http://bulkfeeds.net/rpc
+http://www.newsisfree.com/xmlrpctest.php
+http://ping.feedburner.com/.*
+http://ping.syndic8.com/xmlrpc.php
+http://ping.weblogalot.com/rpc.php
+http://rpc.blogrolling.com/pinger/.*
+http://rpc.technorati.com/rpc/ping
+http://rpc.weblogs.com/RPC2
+http://www.feedsubmitter.com/.*
+http://www.pingerati.net/.*
+http://www.pingmyblog.com/.*
+http://geourl.org/ping
+http://ipings.com/.*
+http://www.weblogalot.com/ping
+# Wordpress plugins
+http://.*wpml.org/.*
+http://www.wpcube.co.uk/.*
+http://.*wp-rocket.me/.*
+http://www.yithemes.com/.*
+http://.*yoast.com/.*
+http://yarpp.org/.*
+http://repository.kreaturamedia.com/.*
+http://api.wp-events-plugin.com/.*
+http://updates.themepunch.com/.*
+http://themeisle.com/.*
+http://download.advancedcustomfields.com/.*
+http://wpcdn.io/.*
+http://vimeo.com/channels/wpetourisme/videos/rss
+http://api.genesistheme.com/update-themes/
+http://www.bolderelements.net/updates/.*
+# Magento Plugins
+http://extensions.activo.com/.*
+http://amasty.com/.*
+# Joomla
+http://.*.joomla.org/.*
+http://getk2.org/.*
+http://miwisoft.com/.*
+http://mijosoft.com/.*
+http://www.joomlaworks.net/.*
+http://cdn.joomlaworks.org/.*
+http://download.regularlabs.com/.*
+# Prestashop
+http://.*.prestashop.com/.*
+http://www.presta-module.com/.*
+http://www.presteamshop.com/.*
+# Others
+http://.*.drupal.org/.*
+http://.*.dotclear.(net|org)/.*
+http://www.phpbb.com/.*
+http://www.typolight.org/.*
+http://www.spip.net/.*
+
+### Feeds / API / WS Tools / ...
+# Google
+http://.*.googleapis.com/.*
+http://.*.google-analytics.com/.*
+http://blogsearch.google.(com|fr)/.*
+http://csi.gstatic.com/.*
+http://maps.google.*/.*
+http://translate.google.com/.*
+http://www.google.com/webmasters/tools/.*
+# Facebook
+http://.*.facebook.com/.*
+http://.*.fbcdn.net/.*
+# Maxmind
+http://geolite.maxmind.com/.*
+# Others
+http://.*amazon.com/.*
+http://.*twitter.com/.*
+http://.*feedburner.com/.*
+http://.*openx.(org|com|net)/.*
+http://geoip-api.meteor.com/.*
+http://www.bing.com/.*
+http://www.telize.com/.*
+http://.*ident.me/.*
+http://.*icanhazip.com/.*
+http://www.express-mailing.com/.*
+http://bot.whatismyipaddress.com/.*
+http://ipecho.net/.*
+
+### Various / Manual entry
+http://.*.s3.amazonaws.com/.*
diff --git a/squid/handlers/main.yml b/squid/handlers/main.yml
new file mode 100644
index 00000000..c623bc19
--- /dev/null
+++ b/squid/handlers/main.yml
@@ -0,0 +1,15 @@
+---
+- name: restart munin-node
+ service:
+ name: munin-node
+ state: restarted
+
+- name: restart squid
+ service:
+ name: squid3
+ state: restarted
+
+- name: restart log2mail
+ service:
+ name: log2mail
+ state: restarted
diff --git a/squid/tasks/log2mail.yml b/squid/tasks/log2mail.yml
new file mode 100644
index 00000000..d525fbae
--- /dev/null
+++ b/squid/tasks/log2mail.yml
@@ -0,0 +1,26 @@
+---
+
+- name: is log2mail installed?
+ stat:
+ path: /etc/log2mail/config/
+ register: log2mail_config
+
+- block:
+ - name: log2mail proxy config is present
+ template:
+ src: log2mail.j2
+ dest: /etc/log2mail/config/squid.conf
+ mode: 0640
+ owner: log2mail
+ group: adm
+ notify: restart log2mail
+
+ - name: log2mail user is in proxy group
+ user:
+ name: log2mail
+ groups: proxy
+ append: yes
+ state: present
+ notify: restart log2mail
+
+ when: log2mail_config.stat.exists
diff --git a/squid/tasks/main.yml b/squid/tasks/main.yml
new file mode 100644
index 00000000..35be44cf
--- /dev/null
+++ b/squid/tasks/main.yml
@@ -0,0 +1,31 @@
+---
+
+- name: package is installed
+ apt:
+ name: squid3
+ state: present
+
+- name: squid.conf is present
+ template:
+ src: squid.j2
+ dest: /etc/squid3/squid.conf
+ notify: restart squid
+
+- name: evolix whitelist is present
+ copy:
+ src: whitelist-evolix.conf
+ dest: /etc/squid3/whitelist-evolix.conf
+ force: yes
+ backup: yes
+ notify: restart squid
+
+- name: custom whitelist is present
+ copy:
+ src: whitelist-custom.conf
+ dest: /etc/squid3/whitelist-custom.conf
+ force: no
+ notify: restart squid
+
+- include: minifirewall.yml
+
+- include: log2mail.yml
diff --git a/squid/tasks/minifirewall.yml b/squid/tasks/minifirewall.yml
new file mode 100644
index 00000000..8f47bdaa
--- /dev/null
+++ b/squid/tasks/minifirewall.yml
@@ -0,0 +1,39 @@
+---
+- name: verify that minifirewall is present
+ stat:
+ path: /etc/default/minifirewall
+ register: minifirewall_test
+
+- fail:
+ msg: "You must install and configure minifirewall to use Squid"
+ when: not minifirewall_test.stat.exists
+
+- name: HTTPSITES list is commented in minifirewall
+ replace:
+ dest: /etc/default/minifirewall
+ regexp: "^(HTTPSITES='[^0-9])"
+ replace: '#\1'
+
+- name: all HTTPSITES are authorized in minifirewall
+ lineinfile:
+ dest: /etc/default/minifirewall
+ line: "HTTPSITES='0.0.0.0/0'"
+ insertafter: "^#HTTPSITES="
+
+- name: add minifirewall rules for the proxy
+ lineinfile:
+ dest: /etc/default/minifirewall
+ regexp: "^#? *{{ item }}"
+ line: "{{ item }}"
+ insertafter: "^# Proxy"
+ with_items:
+ - "/sbin/iptables -t nat -A OUTPUT -p tcp --dport 80 -m owner --uid-owner proxy -j ACCEPT"
+ - "/sbin/iptables -t nat -A OUTPUT -p tcp --dport 80 -d {{ squid_address }} -j ACCEPT"
+ - "/sbin/iptables -t nat -A OUTPUT -p tcp --dport 80 -d 127.0.0.0/8 -j ACCEPT"
+ - "/sbin/iptables -t nat -A OUTPUT -p tcp --dport 80 -j REDIRECT --to-port 8888"
+
+- name: remove minifirewall example rule for the proxy
+ lineinfile:
+ dest: /etc/default/minifirewall
+ regexp: '^#.*(-t nat).*(-d X\.X\.X\.X)'
+ state: absent
diff --git a/squid/templates/log2mail.j2 b/squid/templates/log2mail.j2
new file mode 100644
index 00000000..223c8e27
--- /dev/null
+++ b/squid/templates/log2mail.j2
@@ -0,0 +1,4 @@
+file = /var/log/squid3/access.log
+pattern = "TCP_DENIED"
+mailto = {{ log2mail_alert_email or general_alert_email | mandatory }}
+template = /etc/log2mail/mail
diff --git a/squid/templates/squid.j2 b/squid/templates/squid.j2
new file mode 100644
index 00000000..7fe7f36b
--- /dev/null
+++ b/squid/templates/squid.j2
@@ -0,0 +1,20 @@
+# Ports
+http_port 8888 transparent
+icp_port 0
+
+# ACL
+#acl all src 0.0.0.0/0.0.0.0
+acl localhost src 127.0.0.0/32
+acl INTERNE src {{ squid_address }}/32 127.0.0.0/8
+acl Safe_ports port 80 # http
+acl SSL_ports port 443 563
+acl WHITELIST url_regex "/etc/squid3/whitelist-evolinux.conf"
+acl WHITELIST url_regex "/etc/squid3/whitelist-custom.conf"
+http_access deny !WHITELIST
+http_access allow INTERNE
+http_access deny all
+tcp_outgoing_address {{ squid_address }}
+
+# Logs
+logformat combined %>a %[ui %[un [%tl] "%rm %ru HTTP/%rv" %>Hs %h" "%{User-Agent}>h" %Ss:%Sh
+access_log /var/log/squid3/access.log combined
diff --git a/vagrant.yml b/vagrant.yml
index e4510f41..cd0ad811 100644
--- a/vagrant.yml
+++ b/vagrant.yml
@@ -2,10 +2,20 @@
- hosts: all
gather_facts: yes
become: yes
+ vars_files:
+ - 'vars/main.yml'
roles:
+ # - apt-upgrade
# - { role: apt-upgrade, apt_upgrade_mode: safe }
- - apt-upgrade
+ # - evolinux-base
+ # - listupgrade
+ # - etc-git
+ - evolinux
+ # - postfix
+ # - minifirewall
+ # - squid
+ # - evomaintenance
# - munin
# - monit
# - redis
@@ -20,8 +30,8 @@
# nginx_private_htpasswd_absent: ["toto:dsfgdfsdf"]
# }
# - apache
- - { role: elastic-stack,
- elasticsearch_jvm_xms: "256m",
- elasticsearch_jvm_xmx: "256m"
- }
- - filebeat
+ # - { role: elastic-stack,
+ # elasticsearch_jvm_xms: "256m",
+ # elasticsearch_jvm_xmx: "256m"
+ # }
+ # - filebeat