diff --git a/checkmk/checkmk-files/apache_status b/checkmk/checkmk-files/apache_status
new file mode 100644
index 0000000000000000000000000000000000000000..ad11fc97f85ea5fba06ce278d1d55ea846820262
--- /dev/null
+++ b/checkmk/checkmk-files/apache_status
@@ -0,0 +1,182 @@
+#!/usr/bin/python
+# -*- encoding: utf-8; py-indent-offset: 4 -*-
+# +------------------------------------------------------------------+
+# | ____ _ _ __ __ _ __ |
+# | / ___| |__ ___ ___| | __ | \/ | |/ / |
+# | | | | '_ \ / _ \/ __| |/ / | |\/| | ' / |
+# | | |___| | | | __/ (__| < | | | | . \ |
+# | \____|_| |_|\___|\___|_|\_\___|_| |_|_|\_\ |
+# | |
+# | Copyright Mathias Kettner 2014 mk@mathias-kettner.de |
+# +------------------------------------------------------------------+
+#
+# This file is part of Check_MK.
+# The official homepage is at http://mathias-kettner.de/check_mk.
+#
+# check_mk 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 in version 2. check_mk is distributed
+# in the hope that it will be useful, but WITHOUT ANY WARRANTY; with-
+# out even the implied warranty of MERCHANTABILITY or FITNESS FOR A
+# PARTICULAR PURPOSE. See the GNU General Public License for more de-
+# tails. You should have received a copy of the GNU General Public
+# License along with GNU Make; see the file COPYING. If not, write
+# to the Free Software Foundation, Inc., 51 Franklin St, Fifth Floor,
+# Boston, MA 02110-1301 USA.
+
+# Check_MK-Agent-Plugin - Apache Server Status
+#
+# Fetches the server-status page from detected or configured apache
+# processes to gather status information about this apache process.
+#
+# To make this agent plugin work you have to load the status_module
+# into your apache process. It is also needed to enable the "server-status"
+# handler below the URL "/server-status".
+#
+# By default this plugin tries to detect all locally running apache processes
+# and to monitor them. If this is not good for your environment you might
+# create an apache_status.cfg file in MK_CONFDIR and populate the servers
+# list to prevent executing the detection mechanism.
+#
+# It is also possible to override or extend the ssl_ports variable to make the
+# check contact other ports than 443 with HTTPS requests.
+import os
+import re
+import socket
+import sys
+import urllib2
+
+
+config_dir = os.getenv("MK_CONFDIR", "/etc/check_mk")
+config_file = config_dir + "/apache_status.conf"
+
+if not os.path.exists(config_file):
+ config_file = config_dir + "/apache_status.cfg"
+
+# We have to deal with socket timeouts. Python > 2.6
+# supports timeout parameter for the urllib2.urlopen method
+# but we are on a python 2.5 system here which seem to use the
+# default socket timeout. We are local here so set it to 1 second.
+socket.setdefaulttimeout(5.0)
+
+# None or list of (proto, ipaddress, port) tuples.
+# proto is 'http' or 'https'
+servers = None
+ssl_ports = [443]
+
+
+if os.path.exists(config_file):
+ execfile(config_file)
+
+
+def try_detect_servers():
+ results = []
+
+ for line in os.popen('netstat -tlnp 2>/dev/null').readlines():
+ parts = line.split()
+ # Skip lines with wrong format
+ if len(parts) < 7 or '/' not in parts[6]:
+ continue
+
+ pid, proc = parts[6].split('/', 1)
+ to_replace = re.compile('^.*/')
+ proc = to_replace.sub('', proc)
+
+ procs = [
+ 'apache2',
+ 'httpd',
+ 'httpd-prefork',
+ 'httpd2-prefork',
+ 'httpd2-worker',
+ 'httpd.worker',
+ 'fcgi-pm',
+ ]
+ # the pid/proc field length is limited to 19 chars. Thus in case of
+ # long PIDs, the process names are stripped of by that length.
+ # Workaround this problem here
+ procs = [ p[:19 - len(pid) - 1] for p in procs ]
+
+ # Skip unwanted processes
+ if proc not in procs:
+ continue
+
+ address, port = parts[3].rsplit(':', 1)
+ port = int(port)
+
+ # Use localhost when listening globally
+ if address == '0.0.0.0':
+ address = '127.0.0.1'
+ elif address == '::':
+ address = '[::1]'
+ elif ':' in address:
+ address = '[%s]' % address
+
+ # Switch protocol if port is SSL port. In case you use SSL on another
+ # port you would have to change/extend the ssl_port list
+ if port in ssl_ports:
+ proto = 'https'
+ else:
+ proto = 'http'
+
+ results.append((proto, address, port))
+
+ return results
+
+
+if servers is None:
+ servers = try_detect_servers()
+
+
+if not servers:
+ sys.exit(0)
+
+
+sys.stdout.write('<<<apache_status>>>\n')
+for server in servers:
+ if isinstance(server, tuple):
+ proto, address, port = server
+ page = 'server-status'
+ else:
+ proto = server['protocol']
+ address = server['address']
+ port = server['port']
+ page = server.get('page', 'server-status')
+
+ portspec = port and ":%d" % port or ""
+
+ try:
+ url = '%s://%s%s/%s?auto' % (proto, address, portspec, page)
+ is_local = address in ("127.0.0.1", "[::1]", "localhost")
+ # Try to fetch the status page for each server
+ try:
+ request = urllib2.Request(url, headers={"Accept" : "text/plain"})
+ if is_local and proto == 'https':
+ import ssl
+ no_cert_context = ssl.create_default_context()
+ no_cert_context.check_hostname = False
+ no_cert_context.verify_mode = ssl.CERT_NONE
+ fd = urllib2.urlopen(url, context=no_cert_context)
+ else:
+ fd = urllib2.urlopen(request)
+ except urllib2.URLError, e:
+ if 'unknown protocol' in str(e):
+ # HACK: workaround misconfigurations where port 443 is used for
+ # serving non ssl secured http
+ url = 'http://%s%s/server-status?auto' % (address, portspec)
+ fd = urllib2.urlopen(url)
+ else:
+ raise
+
+ for line in fd.read().split('\n'):
+ if not line.strip():
+ continue
+ if line.lstrip()[0] == '<':
+ # Seems to be html output. Skip this server.
+ break
+
+ sys.stdout.write("%s %s %s\n" % (address, port, line))
+ except urllib2.HTTPError, e:
+ sys.stderr.write('HTTP-Error (%s%s): %s %s\n' % (address, portspec, e.code, e))
+
+ except Exception, e:
+ sys.stderr.write('Exception (%s%s): %s\n' % (address, portspec, e))
diff --git a/checkmk/checkmk-files/check_mk_agent.freebsd b/checkmk/checkmk-files/check_mk_agent.freebsd
index f75ed902e07b69d16516e0a90bcf04859b3ccf22..c1b3601d13d084e06a1e4736fb2489b22d18b9b6 100644
--- a/checkmk/checkmk-files/check_mk_agent.freebsd
+++ b/checkmk/checkmk-files/check_mk_agent.freebsd
@@ -442,3 +442,4 @@ then
echo
done
fi
+
diff --git a/checkmk/checkmk-files/mk_apt b/checkmk/checkmk-files/mk_apt
new file mode 100644
index 0000000000000000000000000000000000000000..31f930ba3ddc3110a1ff28af2bbb707ccdc552d9
--- /dev/null
+++ b/checkmk/checkmk-files/mk_apt
@@ -0,0 +1,65 @@
+#!/bin/bash
+# Check for APT updates (Debian, Ubuntu)
+# +------------------------------------------------------------------+
+# | ____ _ _ __ __ _ __ |
+# | / ___| |__ ___ ___| | __ | \/ | |/ / |
+# | | | | '_ \ / _ \/ __| |/ / | |\/| | ' / |
+# | | |___| | | | __/ (__| < | | | | . \ |
+# | \____|_| |_|\___|\___|_|\_\___|_| |_|_|\_\ |
+# | |
+# | Copyright Mathias Kettner 2014 mk@mathias-kettner.de |
+# +------------------------------------------------------------------+
+#
+# This file is part of Check_MK.
+# The official homepage is at http://mathias-kettner.de/check_mk.
+#
+# check_mk 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 in version 2. check_mk is distributed
+# in the hope that it will be useful, but WITHOUT ANY WARRANTY; with-
+# out even the implied warranty of MERCHANTABILITY or FITNESS FOR A
+# PARTICULAR PURPOSE. See the GNU General Public License for more de-
+# tails. You should have received a copy of the GNU General Public
+# License along with GNU Make; see the file COPYING. If not, write
+# to the Free Software Foundation, Inc., 51 Franklin St, Fifth Floor,
+# Boston, MA 02110-1301 USA.
+
+# TODO:
+# Einstellungen:
+# - upgrade oder dist-upgrade
+# - vorher ein update machen
+# Bakery:
+# - Bakelet anlegen
+# - Async-Zeit einstellbar machen und das Ding immer async laufen lassen
+# Check programmieren:
+# * Schwellwerte auf Anzahlen
+# * Regexen auf Pakete, die zu CRIT/WARN führen
+# - Graph malen mit zwei Kurven
+
+# This variable can either be "upgrade" or "dist-upgrade"
+UPGRADE=upgrade
+DO_UPDATE=yes
+
+
+function check_apt_update {
+ if [ "$DO_UPDATE" = yes ] ; then
+ # NOTE: Even with -qq, apt-get update can output several lines to
+ # stderr, e.g.:
+ #
+ # W: There is no public key available for the following key IDs:
+ # 1397BC53640DB551
+ apt-get update -qq 2> /dev/null
+ fi
+ apt-get -o 'Debug::NoLocking=true' -o 'APT::Get::Show-User-Simulation-Note=false' -s -qq "$UPGRADE" | grep -v '^Conf'
+}
+
+
+if type apt-get > /dev/null ; then
+ echo '<<<apt:sep(0)>>>'
+ out=$(check_apt_update)
+ if [ -z "$out" ]; then
+ echo "No updates pending for installation"
+ else
+ echo "$out"
+ fi
+fi
diff --git a/checkmk/checkmk-files/mk_haproxy.freebsd b/checkmk/checkmk-files/mk_haproxy.freebsd
index dd8f6c6899e094b5d2ce4fe19b8f1551d02001c0..7c7a0fe77577746a0f8bd887c5396579d593acbd 100644
--- a/checkmk/checkmk-files/mk_haproxy.freebsd
+++ b/checkmk/checkmk-files/mk_haproxy.freebsd
@@ -1,4 +1,4 @@
-if [ -r /var/run/haproxy.sock ]; then
+if [ -r /var/run/haproxy.stat ]; then
echo "<<<haproxy:sep(44)>>>"
echo "show stat" | socat - UNIX-CONNECT:/var/run/haproxy.sock
fi
diff --git a/checkmk/checkmk-files/mk_logins b/checkmk/checkmk-files/mk_logins
new file mode 100644
index 0000000000000000000000000000000000000000..b4b8b64618af8f6f373389d9dc191727fc7995fc
--- /dev/null
+++ b/checkmk/checkmk-files/mk_logins
@@ -0,0 +1,29 @@
+#!/bin/bash
+# +------------------------------------------------------------------+
+# | ____ _ _ __ __ _ __ |
+# | / ___| |__ ___ ___| | __ | \/ | |/ / |
+# | | | | '_ \ / _ \/ __| |/ / | |\/| | ' / |
+# | | |___| | | | __/ (__| < | | | | . \ |
+# | \____|_| |_|\___|\___|_|\_\___|_| |_|_|\_\ |
+# | |
+# | Copyright Mathias Kettner 2014 mk@mathias-kettner.de |
+# +------------------------------------------------------------------+
+#
+# This file is part of Check_MK.
+# The official homepage is at http://mathias-kettner.de/check_mk.
+#
+# check_mk 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 in version 2. check_mk is distributed
+# in the hope that it will be useful, but WITHOUT ANY WARRANTY; with-
+# out even the implied warranty of MERCHANTABILITY or FITNESS FOR A
+# PARTICULAR PURPOSE. See the GNU General Public License for more de-
+# tails. You should have received a copy of the GNU General Public
+# License along with GNU Make; see the file COPYING. If not, write
+# to the Free Software Foundation, Inc., 51 Franklin St, Fifth Floor,
+# Boston, MA 02110-1301 USA.
+
+if type who >/dev/null; then
+ echo "<<<logins>>>"
+ who | wc -l
+fi
diff --git a/checkmk/checkmk-files/mk_postgres b/checkmk/checkmk-files/mk_postgres
new file mode 100644
index 0000000000000000000000000000000000000000..47fef50d06e80945eda5a9436e08093581431def
--- /dev/null
+++ b/checkmk/checkmk-files/mk_postgres
@@ -0,0 +1,520 @@
+#!/bin/bash
+# +------------------------------------------------------------------+
+# | ____ _ _ __ __ _ __ |
+# | / ___| |__ ___ ___| | __ | \/ | |/ / |
+# | | | | '_ \ / _ \/ __| |/ / | |\/| | ' / |
+# | | |___| | | | __/ (__| < | | | | . \ |
+# | \____|_| |_|\___|\___|_|\_\___|_| |_|_|\_\ |
+# | |
+# | Copyright Mathias Kettner 2015 mk@mathias-kettner.de |
+# +------------------------------------------------------------------+
+#
+# This file is part of Check_MK.
+# The official homepage is at http://mathias-kettner.de/check_mk.
+#
+# check_mk 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 in version 2. check_mk is distributed
+# in the hope that it will be useful, but WITHOUT ANY WARRANTY; with-
+# out even the implied warranty of MERCHANTABILITY or FITNESS FOR A
+# PARTICULAR PURPOSE. See the GNU General Public License for more de-
+# tails. You should have received a copy of the GNU General Public
+# License along with GNU Make; see the file COPYING. If not, write
+# to the Free Software Foundation, Inc., 51 Franklin St, Fifth Floor,
+# Boston, MA 02110-1301 USA.
+
+
+# TODO postgres_connections output format
+
+
+# .--common funcs--------------------------------------------------------.
+# | __ |
+# | ___ ___ _ __ ___ _ __ ___ ___ _ __ / _|_ _ _ __ ___ ___ |
+# | / __/ _ \| '_ ` _ \| '_ ` _ \ / _ \| '_ \ | |_| | | | '_ \ / __/ __| |
+# || (_| (_) | | | | | | | | | | | (_) | | | || _| |_| | | | | (__\__ \ |
+# | \___\___/|_| |_| |_|_| |_| |_|\___/|_| |_||_| \__,_|_| |_|\___|___/ |
+# | |
+# '----------------------------------------------------------------------'
+
+
+function compare_version_greater_equal() {
+ local GREATER_ONE
+ GREATER_ONE=$(echo "$1 $2" | awk '{if ($1 >= $2) print $1; else print $2}')
+ if [ "$GREATER_ONE" == "$1" ] ; then
+ return 0
+ else
+ return 1
+ fi
+}
+
+
+#.
+# .--section funcs-------------------------------------------------------.
+# | _ _ __ |
+# | ___ ___ ___| |_(_) ___ _ __ / _|_ _ _ __ ___ ___ |
+# | / __|/ _ \/ __| __| |/ _ \| '_ \ | |_| | | | '_ \ / __/ __| |
+# | \__ \ __/ (__| |_| | (_) | | | | | _| |_| | | | | (__\__ \ |
+# | |___/\___|\___|\__|_|\___/|_| |_| |_| \__,_|_| |_|\___|___/ |
+# | |
+# '----------------------------------------------------------------------'
+
+
+function postgres_instances() {
+ echo '<<<postgres_instances>>>'
+ # If we have no instances we take db id (pqsql/postgres) because
+ # ps output may be unreadable
+ # In case of instances ps output shows them readable
+ if [ ! -z "${1}" ]; then
+ echo "[[[${1}]]]"
+ fi
+
+ # shellcheck disable=SC2009
+ # The pgrep command would be different for older distros. Newer distros
+ # need the -a option, but older ones need the -f option. The first idea
+ # was to use:
+ # pgrep -af bin/postgres 2>/dev/null || pgrep -lf bin/postgres
+ # but SLES 11 returns the exit code 0 for a wrong command line.
+ ps -eo pid,command | grep bin/postgres | grep -vE '^[ ]*[0-9]+ grep '
+}
+
+
+function postgres_sessions() {
+ local OUTPUT
+
+ # In postgresql 9.2 the column state was introduced, which has to be queried to
+ # find the state of the sessions. The column state can be NULL.
+ CONDITION="$ROW = $IDLE"
+ OUTPUT="$(echo "\echo '<<<postgres_sessions>>>${INSTANCE_SECTION}'
+ SELECT $CONDITION, count(*) FROM pg_stat_activity WHERE $ROW IS NOT NULL GROUP BY ($CONDITION);" |\
+ su - "$DBUSER" -c "$export_PGPASSFILE $psql -X --variable ON_ERROR_STOP=1 ${EXTRA_ARGS} -A -t -F' '" 2>/dev/null)"
+
+ echo "$OUTPUT"
+ # line with number of idle sessions is sometimes missing on Postgres 8.x. This can lead
+ # to an altogether empty section and thus the check disappearing.
+ echo "$OUTPUT" | grep -q '^t ' || echo "t 0"
+}
+
+
+function postgres_simple_queries() {
+ # Querytime
+ # Supports versions >= 8.3, > 9.1
+ local QUERYTIME_QUERY
+ if compare_version_greater_equal "$POSTGRES_VERSION" "9.2" ; then
+ QUERYTIME_QUERY="SELECT datname, datid, usename, client_addr, state AS state, COALESCE(ROUND(EXTRACT(epoch FROM now()-query_start)),0) AS seconds,
+ pid, regexp_replace(query, E'[\\n\\r\\u2028]+', ' ', 'g' ) AS current_query FROM pg_stat_activity WHERE (query_start IS NOT NULL AND (state NOT LIKE 'idle%' OR state IS NULL)) ORDER BY query_start, pid DESC;"
+ else
+ QUERYTIME_QUERY="SELECT datname, datid, usename, client_addr, '' AS state, COALESCE(ROUND(EXTRACT(epoch FROM now()-query_start)),0) AS seconds,
+ procpid as pid, regexp_replace(current_query, E'[\\n\\r\\u2028]+', ' ', 'g' ) AS current_query FROM pg_stat_activity WHERE (query_start IS NOT NULL AND current_query NOT LIKE '<IDLE>%') ORDER BY query_start, procpid DESC;"
+ fi
+
+ # Number of current connections per database
+ # We need to output the databases, too.
+ # This query does not report databases without an active query
+ local CONNECTIONS_QUERY
+
+ # Here the order of the columns did not match with what the server side expects,
+ # with the result, that there was never any active connection shown in the
+ # web-gui.
+ CONDITION="$ROW <> $IDLE"
+ CONNECTIONS_QUERY="SELECT d.datname, COUNT(datid) AS current,
+ (SELECT setting AS mc FROM pg_settings WHERE name = 'max_connections') AS mc
+ FROM pg_database d
+ LEFT JOIN pg_stat_activity s ON (s.datid = d.oid) WHERE $CONDITION
+ GROUP BY 1
+ ORDER BY datname;"
+
+ echo "\pset footer off
+ \echo '<<<postgres_stat_database:sep(59)>>>${INSTANCE_SECTION}'
+ SELECT datid, datname, numbackends, xact_commit, xact_rollback, blks_read, blks_hit, tup_returned, tup_fetched, tup_inserted, tup_updated, tup_deleted, pg_database_size(datname) AS datsize FROM pg_stat_database;
+
+ \echo '<<<postgres_locks:sep(59)>>>${INSTANCE_SECTION}'
+ \echo '[databases_start]'
+ $ECHO_DATABASES
+ \echo '[databases_end]'
+ SELECT datname, granted, mode FROM pg_locks l RIGHT JOIN pg_database d ON (d.oid=l.database) WHERE d.datallowconn;
+
+ \echo '<<<postgres_query_duration:sep(59)>>>${INSTANCE_SECTION}'
+ \echo '[databases_start]'
+ $ECHO_DATABASES
+ \echo '[databases_end]'
+ $QUERYTIME_QUERY
+
+ \echo '<<<postgres_connections:sep(59)>>>${INSTANCE_SECTION}'
+ \echo '[databases_start]'
+ $ECHO_DATABASES
+ \echo '[databases_end]'
+ $CONNECTIONS_QUERY" \
+ | su - "$DBUSER" -c "$export_PGPASSFILE $psql -X ${EXTRA_ARGS} -q -A -F';'"
+}
+
+
+function postgres_stats() {
+ # Contains last vacuum time and analyze time
+ local LASTVACUUM="SELECT current_database() AS datname, nspname AS sname, relname AS tname,
+ CASE WHEN v IS NULL THEN -1 ELSE round(extract(epoch FROM v)) END AS vtime,
+ CASE WHEN g IS NULL THEN -1 ELSE round(extract(epoch FROM v)) END AS atime
+ FROM (SELECT nspname, relname, GREATEST(pg_stat_get_last_vacuum_time(c.oid), pg_stat_get_last_autovacuum_time(c.oid)) AS v,
+ GREATEST(pg_stat_get_last_analyze_time(c.oid), pg_stat_get_last_autoanalyze_time(c.oid)) AS g
+ FROM pg_class c, pg_namespace n
+ WHERE relkind = 'r' AND n.oid = c.relnamespace AND n.nspname <> 'information_schema'
+ ORDER BY 3) AS foo;"
+
+ local FIRST=
+ local QUERY="\pset footer off
+ BEGIN;
+ SET statement_timeout=30000;
+ COMMIT;
+
+ \echo '<<<postgres_stats:sep(59)>>>${INSTANCE_SECTION}'
+ \echo '[databases_start]'
+ $ECHO_DATABASES
+ \echo '[databases_end]'"
+
+ for db in $DATABASES ; do
+ QUERY="$QUERY
+ \c $db
+ $LASTVACUUM
+ "
+ if [ -z $FIRST ] ; then
+ FIRST=false
+ QUERY="$QUERY
+ \pset tuples_only on
+ "
+ fi
+ done
+ echo "$QUERY" | su - "$DBUSER" -c "$export_PGPASSFILE $psql -X ${EXTRA_ARGS} -q -A -F';'" | grep -v -e 'COMMIT$' -e 'SET$' -e 'BEGIN$'
+}
+
+
+function postgres_version() {
+ # Postgres version an connection time
+ echo -e "<<<postgres_version:sep(1)>>>${INSTANCE_SECTION}"
+ (TIMEFORMAT='%3R'; time echo "SELECT version() AS v" |\
+ su - "$DBUSER" -c "$export_PGPASSFILE $psql -X ${EXTRA_ARGS} -t -A -F';'; echo -e '<<<postgres_conn_time>>>${INSTANCE_SECTION}'") 2>&1
+}
+
+
+function postgres_bloat() {
+ # Bloat index and tables
+ # Supports versions <9.0, >=9.0
+ # This huge query has been gratefully taken from Greg Sabino Mullane's check_postgres.pl
+ local BLOAT_QUERY
+ if compare_version_greater_equal "$POSTGRES_VERSION" "9.0" ; then
+ BLOAT_QUERY="SELECT
+ current_database() AS db, schemaname, tablename, reltuples::bigint AS tups, relpages::bigint AS pages, otta,
+ ROUND(CASE WHEN sml.relpages=0 OR sml.relpages=otta THEN 0.0 ELSE (sml.relpages-otta::numeric)/sml.relpages END,3) AS tbloat,
+ CASE WHEN relpages < otta THEN 0 ELSE relpages::bigint - otta END AS wastedpages,
+ CASE WHEN relpages < otta THEN 0 ELSE bs*(sml.relpages-otta)::bigint END AS wastedbytes,
+ CASE WHEN relpages < otta THEN 0 ELSE (bs*(relpages-otta))::bigint END AS wastedsize,
+ iname, ituples::bigint AS itups, ipages::bigint AS ipages, iotta,
+ ROUND(CASE WHEN ipages=0 OR ipages<=iotta THEN 0.0 ELSE (ipages-iotta::numeric)/ipages END,3) AS ibloat,
+ CASE WHEN ipages < iotta THEN 0 ELSE ipages::bigint - iotta END AS wastedipages,
+ CASE WHEN ipages < iotta THEN 0 ELSE bs*(ipages-iotta) END AS wastedibytes,
+ CASE WHEN ipages < iotta THEN 0 ELSE (bs*(ipages-iotta))::bigint END AS wastedisize,
+ CASE WHEN relpages < otta THEN
+ CASE WHEN ipages < iotta THEN 0 ELSE bs*(ipages-iotta::bigint) END
+ ELSE CASE WHEN ipages < iotta THEN bs*(relpages-otta::bigint)
+ ELSE bs*(relpages-otta::bigint + ipages-iotta::bigint) END
+ END AS totalwastedbytes
+ FROM (
+ SELECT
+ nn.nspname AS schemaname,
+ cc.relname AS tablename,
+ COALESCE(cc.reltuples,0) AS reltuples,
+ COALESCE(cc.relpages,0) AS relpages,
+ COALESCE(bs,0) AS bs,
+ COALESCE(CEIL((cc.reltuples*((datahdr+ma-
+ (CASE WHEN datahdr%ma=0 THEN ma ELSE datahdr%ma END))+nullhdr2+4))/(bs-20::float)),0) AS otta,
+ COALESCE(c2.relname,'?') AS iname, COALESCE(c2.reltuples,0) AS ituples, COALESCE(c2.relpages,0) AS ipages,
+ COALESCE(CEIL((c2.reltuples*(datahdr-12))/(bs-20::float)),0) AS iotta -- very rough approximation, assumes all cols
+ FROM
+ pg_class cc
+ JOIN pg_namespace nn ON cc.relnamespace = nn.oid AND nn.nspname <> 'information_schema'
+ LEFT JOIN
+ (
+ SELECT
+ ma,bs,foo.nspname,foo.relname,
+ (datawidth+(hdr+ma-(case when hdr%ma=0 THEN ma ELSE hdr%ma END)))::numeric AS datahdr,
+ (maxfracsum*(nullhdr+ma-(case when nullhdr%ma=0 THEN ma ELSE nullhdr%ma END))) AS nullhdr2
+ FROM (
+ SELECT
+ ns.nspname, tbl.relname, hdr, ma, bs,
+ SUM((1-coalesce(null_frac,0))*coalesce(avg_width, 2048)) AS datawidth,
+ MAX(coalesce(null_frac,0)) AS maxfracsum,
+ hdr+(
+ SELECT 1+count(*)/8
+ FROM pg_stats s2
+ WHERE null_frac<>0 AND s2.schemaname = ns.nspname AND s2.tablename = tbl.relname
+ ) AS nullhdr
+ FROM pg_attribute att
+ JOIN pg_class tbl ON att.attrelid = tbl.oid
+ JOIN pg_namespace ns ON ns.oid = tbl.relnamespace
+ LEFT JOIN pg_stats s ON s.schemaname=ns.nspname
+ AND s.tablename = tbl.relname
+ AND s.inherited=false
+ AND s.attname=att.attname,
+ (
+ SELECT
+ (SELECT current_setting('block_size')::numeric) AS bs,
+ CASE WHEN SUBSTRING(SPLIT_PART(v, ' ', 2) FROM '#\[0-9]+.[0-9]+#\%' for '#')
+ IN ('8.0','8.1','8.2') THEN 27 ELSE 23 END AS hdr,
+ CASE WHEN v ~ 'mingw32' OR v ~ '64-bit' THEN 8 ELSE 4 END AS ma
+ FROM (SELECT version() AS v) AS foo
+ ) AS constants
+ WHERE att.attnum > 0 AND tbl.relkind='r'
+ GROUP BY 1,2,3,4,5
+ ) AS foo
+ ) AS rs
+ ON cc.relname = rs.relname AND nn.nspname = rs.nspname
+ LEFT JOIN pg_index i ON indrelid = cc.oid
+ LEFT JOIN pg_class c2 ON c2.oid = i.indexrelid
+ ) AS sml
+ WHERE sml.relpages - otta > 0 OR ipages - iotta > 10 ORDER BY totalwastedbytes DESC LIMIT 10;"
+ else
+ BLOAT_QUERY="SELECT
+ current_database() AS db, schemaname, tablename, reltuples::bigint AS tups, relpages::bigint AS pages, otta,
+ ROUND(CASE WHEN sml.relpages=0 OR sml.relpages=otta THEN 0.0 ELSE (sml.relpages-otta::numeric)/sml.relpages END,3) AS tbloat,
+ CASE WHEN relpages < otta THEN 0 ELSE relpages::bigint - otta END AS wastedpages,
+ CASE WHEN relpages < otta THEN 0 ELSE bs*(sml.relpages-otta)::bigint END AS wastedbytes,
+ CASE WHEN relpages < otta THEN '0 bytes'::text ELSE (bs*(relpages-otta))::bigint || ' bytes' END AS wastedsize,
+ iname, ituples::bigint AS itups, ipages::bigint AS ipages, iotta,
+ ROUND(CASE WHEN ipages=0 OR ipages<=iotta THEN 0.0 ELSE (ipages-iotta::numeric)/ipages END,3) AS ibloat,
+ CASE WHEN ipages < iotta THEN 0 ELSE ipages::bigint - iotta END AS wastedipages,
+ CASE WHEN ipages < iotta THEN 0 ELSE bs*(ipages-iotta) END AS wastedibytes,
+ CASE WHEN ipages < iotta THEN '0 bytes' ELSE (bs*(ipages-iotta))::bigint || ' bytes' END AS wastedisize,
+ CASE WHEN relpages < otta THEN
+ CASE WHEN ipages < iotta THEN 0 ELSE bs*(ipages-iotta::bigint) END
+ ELSE CASE WHEN ipages < iotta THEN bs*(relpages-otta::bigint)
+ ELSE bs*(relpages-otta::bigint + ipages-iotta::bigint) END
+ END AS totalwastedbytes
+ FROM (
+ SELECT
+ nn.nspname AS schemaname,
+ cc.relname AS tablename,
+ COALESCE(cc.reltuples,0) AS reltuples,
+ COALESCE(cc.relpages,0) AS relpages,
+ COALESCE(bs,0) AS bs,
+ COALESCE(CEIL((cc.reltuples*((datahdr+ma-
+ (CASE WHEN datahdr%ma=0 THEN ma ELSE datahdr%ma END))+nullhdr2+4))/(bs-20::float)),0) AS otta,
+ COALESCE(c2.relname,'?') AS iname, COALESCE(c2.reltuples,0) AS ituples, COALESCE(c2.relpages,0) AS ipages,
+ COALESCE(CEIL((c2.reltuples*(datahdr-12))/(bs-20::float)),0) AS iotta -- very rough approximation, assumes all cols
+ FROM
+ pg_class cc
+ JOIN pg_namespace nn ON cc.relnamespace = nn.oid AND nn.nspname <> 'information_schema'
+ LEFT JOIN
+ (
+ SELECT
+ ma,bs,foo.nspname,foo.relname,
+ (datawidth+(hdr+ma-(case when hdr%ma=0 THEN ma ELSE hdr%ma END)))::numeric AS datahdr,
+ (maxfracsum*(nullhdr+ma-(case when nullhdr%ma=0 THEN ma ELSE nullhdr%ma END))) AS nullhdr2
+ FROM (
+ SELECT
+ ns.nspname, tbl.relname, hdr, ma, bs,
+ SUM((1-coalesce(null_frac,0))*coalesce(avg_width, 2048)) AS datawidth,
+ MAX(coalesce(null_frac,0)) AS maxfracsum,
+ hdr+(
+ SELECT 1+count(*)/8
+ FROM pg_stats s2
+ WHERE null_frac<>0 AND s2.schemaname = ns.nspname AND s2.tablename = tbl.relname
+ ) AS nullhdr
+ FROM pg_attribute att
+ JOIN pg_class tbl ON att.attrelid = tbl.oid
+ JOIN pg_namespace ns ON ns.oid = tbl.relnamespace
+ LEFT JOIN pg_stats s ON s.schemaname=ns.nspname
+ AND s.tablename = tbl.relname
+ AND s.attname=att.attname,
+ (
+ SELECT
+ (SELECT current_setting('block_size')::numeric) AS bs,
+ CASE WHEN SUBSTRING(SPLIT_PART(v, ' ', 2) FROM '#\"[0-9]+.[0-9]+#\"%' for '#')
+ IN ('8.0','8.1','8.2') THEN 27 ELSE 23 END AS hdr,
+ CASE WHEN v ~ 'mingw32' OR v ~ '64-bit' THEN 8 ELSE 4 END AS ma
+ FROM (SELECT version() AS v) AS foo
+ ) AS constants
+ WHERE att.attnum > 0 AND tbl.relkind='r'
+ GROUP BY 1,2,3,4,5
+ ) AS foo
+ ) AS rs
+ ON cc.relname = rs.relname AND nn.nspname = rs.nspname
+ LEFT JOIN pg_index i ON indrelid = cc.oid
+ LEFT JOIN pg_class c2 ON c2.oid = i.indexrelid
+ ) AS sml
+ WHERE sml.relpages - otta > 0 OR ipages - iotta > 10 ORDER BY totalwastedbytes DESC LIMIT 10;"
+ fi
+
+ local FIRST=
+ local QUERY="\pset footer off
+ \echo '<<<postgres_bloat:sep(59)>>>${INSTANCE_SECTION}'
+ \echo '[databases_start]'
+ $ECHO_DATABASES
+ \echo '[databases_end]'"
+
+ for db in $DATABASES ; do
+ QUERY="$QUERY
+ \c $db
+ $BLOAT_QUERY
+ "
+ if [ -z $FIRST ] ; then
+ FIRST=false
+ QUERY="$QUERY
+ \pset tuples_only on
+ "
+ fi
+ done
+ echo "$QUERY" | su - "$DBUSER" -c "$export_PGPASSFILE $psql -X ${EXTRA_ARGS} -q -A -F';'"
+}
+
+
+#.
+# .--main----------------------------------------------------------------.
+# | _ |
+# | _ __ ___ __ _(_)_ __ |
+# | | '_ ` _ \ / _` | | '_ \ |
+# | | | | | | | (_| | | | | | |
+# | |_| |_| |_|\__,_|_|_| |_| |
+# | |
+# '----------------------------------------------------------------------'
+
+
+### postgres.cfg ##
+# DBUSER=OS_USER_NAME
+# INSTANCE=/home/postgres/db1.env:USER_NAME:/PATH/TO/.pgpass
+# INSTANCE=/home/postgres/db2.env:USER_NAME:/PATH/TO/.pgpass
+
+# TODO @dba USERNAME in .pgpass ?
+# INSTANCE=/home/postgres/db2.env:/PATH/TO/.pgpass
+
+
+function postgres_main() {
+ if [ -z "$DBUSER" ] || [ -z "$PGDATABASE" ] ; then
+ exit 0
+ fi
+
+ EXTRA_ARGS=""
+ if [ ! -z "$PGUSER" ]; then
+ EXTRA_ARGS=$EXTRA_ARGS" -U $PGUSER"
+ fi
+ if [ ! -z "$PGDATABASE" ]; then
+ EXTRA_ARGS=$EXTRA_ARGS" -d $PGDATABASE"
+ fi
+ if [ ! -z "$PGPORT" ]; then
+ EXTRA_ARGS=$EXTRA_ARGS" -p $PGPORT"
+ fi
+
+ if [ ! -z "$PGPASSFILE" ]; then
+ export_PGPASSFILE="export PGPASSFILE=$PGPASSFILE; "
+ fi
+
+ DATABASES="$(echo "SELECT datname FROM pg_database WHERE datistemplate = false;" |\
+ su - "$DBUSER" -c "$export_PGPASSFILE $psql -X ${EXTRA_ARGS} -t -A -F';'")"
+ # shellcheck disable=SC2001
+ # DATABASES contains one database per line. To print each database in the psql terminal
+ # we have to prefix each line with '\echo '. ${varialbe//search/replace} is not
+ # sufficient in this case.
+ ECHO_DATABASES="$(echo "$DATABASES" | sed 's/^/\\echo /')"
+
+ postgres_check_server_version
+ postgres_sessions
+ postgres_simple_queries
+ postgres_stats
+ postgres_version
+ postgres_bloat
+}
+
+
+function postgres_check_server_version() {
+ # Query the server version from the server. Originally the version of the
+ # client tools was taken, but what really matters is the version of the server.
+ # Terminate the script if the server can not be queried.
+ # We want $(su ...) to be
+ # shellcheck disable=SC2046
+ set -- $(su - "$DBUSER" -c "$psql -A -t -X ${EXTRA_ARGS} -c 'SHOW server_version;'" | tr '.' ' ')
+ test $# -eq 0 && exit 0
+ POSTGRES_VERSION="$1.$2"
+ postgres_set_condition_vars
+}
+
+
+function postgres_set_condition_vars() {
+ if compare_version_greater_equal "$POSTGRES_VERSION" "9.2" ; then
+ ROW=state
+ IDLE="'idle'"
+ else
+ ROW=current_query
+ IDLE="'<IDLE>'"
+ fi
+}
+
+
+MK_CONFFILE=$MK_CONFDIR/postgres.cfg
+if [ -e "$MK_CONFFILE" ]; then
+
+ postgres_instances
+
+ DBUSER=$(grep DBUSER "$MK_CONFFILE" | sed 's/.*=//g')
+
+ # read -r: we do not want to interpret backslashes before spaces and line feeds
+ while read -r line; do
+ case $line in
+ INSTANCE*)
+ instance=$line
+ ;;
+ *)
+ instance=
+ ;;
+ esac
+
+ if [ ! -z "$instance" ]; then
+ # Too complicated for ${variable//search/replace}
+ # shellcheck disable=SC2001
+ instance_path=$(echo "$instance" | sed 's/.*=\(.*\):.*:.*$/\1/g')
+ instance_name=$(echo "$instance_path" | sed -e 's/.*\/\(.*\)/\1/g' -e 's/\.env$//g')
+ if [ ! -z "$instance_name" ]; then
+ INSTANCE_SECTION="\n[[[$instance_name]]]"
+ else
+ INSTANCE_SECTION=""
+ fi
+
+ psql="/$DBUSER/$(grep "^export PGVERSION=" "$instance_path" |
+ sed -e 's/.*=//g' -e 's/\s*#.*$//g')/bin/psql"
+
+ # Too complicated for ${variable//search/replace}
+ # shellcheck disable=SC2001
+ PGUSER=$(echo "$instance" | sed 's/.*=.*:\(.*\):.*$/\1/g')
+ # Too complicated for ${variable//search/replace}
+ # shellcheck disable=SC2001
+ PGPASSFILE="$(echo "$instance" | sed 's/.*=.*:.*:\(.*\)$/\1/g')"
+ PGDATABASE=$(grep "^export PGDATABASE=" "$instance_path" |
+ sed -e 's/.*=//g' -e 's/\s*#.*$//g')
+ PGPORT=$(grep "^export PGPORT=" "$instance_path" |
+ sed -e 's/.*=//g' -e 's/\s*#.*$//g')
+
+ # Fallback
+ if [ ! -f "$psql" ]; then
+ psql="$(grep "^export PGHOME=" "$instance_path" |
+ sed -e 's/.*=//g' -e 's/\s*#.*$//g')/psql"
+ fi
+
+ postgres_main
+
+ fi
+ done < "$MK_CONFFILE"
+
+else
+
+ if id pgsql >/dev/null 2>&1; then
+ DBUSER=pgsql
+ elif id postgres >/dev/null 2>&1; then
+ DBUSER=postgres
+ else
+ exit 0
+ fi
+
+ PGDATABASE=postgres
+ INSTANCE_SECTION=""
+ psql="psql"
+
+ postgres_instances "$DBUSER"
+ postgres_main
+
+fi
diff --git a/checkmk/checkmk-files/mk_zypper b/checkmk/checkmk-files/mk_zypper
new file mode 100644
index 0000000000000000000000000000000000000000..a12d09ba3c8f92acfb87bf6a9f167315dbaccdbf
--- /dev/null
+++ b/checkmk/checkmk-files/mk_zypper
@@ -0,0 +1,50 @@
+#!/bin/bash
+# +------------------------------------------------------------------+
+# | ____ _ _ __ __ _ __ |
+# | / ___| |__ ___ ___| | __ | \/ | |/ / |
+# | | | | '_ \ / _ \/ __| |/ / | |\/| | ' / |
+# | | |___| | | | __/ (__| < | | | | . \ |
+# | \____|_| |_|\___|\___|_|\_\___|_| |_|_|\_\ |
+# | |
+# | Copyright Mathias Kettner 2014 mk@mathias-kettner.de |
+# +------------------------------------------------------------------+
+#
+# This file is part of Check_MK.
+# The official homepage is at http://mathias-kettner.de/check_mk.
+#
+# check_mk 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 in version 2. check_mk is distributed
+# in the hope that it will be useful, but WITHOUT ANY WARRANTY; with-
+# out even the implied warranty of MERCHANTABILITY or FITNESS FOR A
+# PARTICULAR PURPOSE. See the GNU General Public License for more de-
+# tails. You should have received a copy of the GNU General Public
+# License along with GNU Make; see the file COPYING. If not, write
+# to the Free Software Foundation, Inc., 51 Franklin St, Fifth Floor,
+# Boston, MA 02110-1301 USA.
+
+if type zypper > /dev/null ; then
+ echo '<<<zypper:sep(124)>>>'
+ if grep -q '^VERSION = 10' < /etc/SuSE-release
+ then
+ ZYPPER='waitmax 10 zypper --no-gpg-checks --non-interactive --terse'
+ REFRESH=`$ZYPPER refresh 2>&1`
+ if [ "$REFRESH" ]
+ then
+ echo "ERROR: $REFRESH"
+ else
+ { $ZYPPER pchk || [ $? = 100 -o $? = 101 ] && $ZYPPER lu ; } \
+ | egrep '(patches needed|\|)' | egrep -v '^(#|Repository |Catalog )'
+ fi
+ else
+ ZYPPER='waitmax 10 zypper --no-gpg-checks --non-interactive --quiet'
+ REFRESH=`$ZYPPER refresh 2>&1`
+ if [ "$REFRESH" ]
+ then
+ echo "ERROR: $REFRESH"
+ else
+ { { $ZYPPER pchk || [ $? = 100 -o $? = 101 ] && $ZYPPER lp ; } ; $ZYPPER ll ; } \
+ | egrep '(patches needed|\|)' | egrep -v '^(#|Repository)'
+ fi
+ fi
+fi
diff --git a/checkmk/checkmk-files/netstat.linux b/checkmk/checkmk-files/netstat.linux
new file mode 100644
index 0000000000000000000000000000000000000000..55a27aeb8a1923c67d91b6e6ce64c3027149246d
--- /dev/null
+++ b/checkmk/checkmk-files/netstat.linux
@@ -0,0 +1,31 @@
+#!/bin/sh
+# +------------------------------------------------------------------+
+# | ____ _ _ __ __ _ __ |
+# | / ___| |__ ___ ___| | __ | \/ | |/ / |
+# | | | | '_ \ / _ \/ __| |/ / | |\/| | ' / |
+# | | |___| | | | __/ (__| < | | | | . \ |
+# | \____|_| |_|\___|\___|_|\_\___|_| |_|_|\_\ |
+# | |
+# | Copyright Mathias Kettner 2014 mk@mathias-kettner.de |
+# +------------------------------------------------------------------+
+#
+# This file is part of Check_MK.
+# The official homepage is at http://mathias-kettner.de/check_mk.
+#
+# check_mk 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 in version 2. check_mk is distributed
+# in the hope that it will be useful, but WITHOUT ANY WARRANTY; with-
+# out even the implied warranty of MERCHANTABILITY or FITNESS FOR A
+# PARTICULAR PURPOSE. See the GNU General Public License for more de-
+# tails. You should have received a copy of the GNU General Public
+# License along with GNU Make; see the file COPYING. If not, write
+# to the Free Software Foundation, Inc., 51 Franklin St, Fifth Floor,
+# Boston, MA 02110-1301 USA.
+
+# This is not part of the standard agent since it can take very
+# long to run if your TCP/UDP table is large. Netstat seems to
+# have an execution time complexity of at least O(n^2) on Linux.
+
+echo '<<<netstat>>>'
+netstat -ntua | egrep '^(tcp|udp)' | sed -e 's/LISTEN/LISTENING/g'
diff --git a/checkmk/checkmk-files/nginx_status b/checkmk/checkmk-files/nginx_status
new file mode 100644
index 0000000000000000000000000000000000000000..8eb52fcec708a66a768dbd64098215de641d5100
--- /dev/null
+++ b/checkmk/checkmk-files/nginx_status
@@ -0,0 +1,153 @@
+#!/usr/bin/python
+# -*- encoding: utf-8; py-indent-offset: 4 -*-
+# +------------------------------------------------------------------+
+# | ____ _ _ __ __ _ __ |
+# | / ___| |__ ___ ___| | __ | \/ | |/ / |
+# | | | | '_ \ / _ \/ __| |/ / | |\/| | ' / |
+# | | |___| | | | __/ (__| < | | | | . \ |
+# | \____|_| |_|\___|\___|_|\_\___|_| |_|_|\_\ |
+# | |
+# | Copyright Mathias Kettner 2014 mk@mathias-kettner.de |
+# +------------------------------------------------------------------+
+#
+# This file is part of Check_MK.
+# The official homepage is at http://mathias-kettner.de/check_mk.
+#
+# check_mk 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 in version 2. check_mk is distributed
+# in the hope that it will be useful, but WITHOUT ANY WARRANTY; with-
+# out even the implied warranty of MERCHANTABILITY or FITNESS FOR A
+# PARTICULAR PURPOSE. See the GNU General Public License for more de-
+# tails. You should have received a copy of the GNU General Public
+# License along with GNU Make; see the file COPYING. If not, write
+# to the Free Software Foundation, Inc., 51 Franklin St, Fifth Floor,
+# Boston, MA 02110-1301 USA.
+
+# Check_MK-Agent-Plugin - Nginx Server Status
+#
+# Fetches the stub nginx_status page from detected or configured nginx
+# processes to gather status information about this process.
+#
+# Take a look at the check man page for details on how to configure this
+# plugin and check.
+#
+# By default this plugin tries to detect all locally running processes
+# and to monitor them. If this is not good for your environment you might
+# create an nginx_status.cfg file in MK_CONFDIR and populate the servers
+# list to prevent executing the detection mechanism.
+
+import os
+import re
+import sys
+import urllib2
+
+# tell urllib2 not to honour "http(s)_proxy" env variables
+urllib2.getproxies = lambda: {}
+
+config_dir = os.getenv("MK_CONFDIR", "/etc/check_mk")
+config_file = config_dir + "/nginx_status.cfg"
+
+# None or list of (proto, ipaddress, port) tuples.
+# proto is 'http' or 'https'
+servers = None
+ssl_ports = [
+ 443,
+]
+
+if os.path.exists(config_file):
+ execfile(config_file)
+
+
+def try_detect_servers():
+ pids = []
+ results = []
+ for netstat_line in os.popen('netstat -tlnp 2>/dev/null').readlines():
+ parts = netstat_line.split()
+ # Skip lines with wrong format
+ if len(parts) < 7 or '/' not in parts[6]:
+ continue
+
+ pid, proc = parts[6].split('/', 1)
+ to_replace = re.compile('^.*/')
+ proc = to_replace.sub('', proc)
+
+ procs = ['nginx', 'nginx:', 'nginx.conf']
+ # the pid/proc field length is limited to 19 chars. Thus in case of
+ # long PIDs, the process names are stripped of by that length.
+ # Workaround this problem here
+ procs = [p[:19 - len(pid) - 1] for p in procs]
+
+ # Skip unwanted processes
+ if proc not in procs:
+ continue
+
+ # Add only the first found port of a single server process
+ if pid in pids:
+ continue
+ pids.append(pid)
+
+ server_proto = 'http'
+ server_address, server_port = parts[3].rsplit(':', 1)
+ server_port = int(server_port)
+
+ # Use localhost when listening globally
+ if server_address == '0.0.0.0':
+ server_address = '127.0.0.1'
+ elif server_address == '::':
+ server_address = '::1'
+
+ # Switch protocol if port is SSL port. In case you use SSL on another
+ # port you would have to change/extend the ssl_port list
+ if server_port in ssl_ports:
+ server_proto = 'https'
+
+ results.append((server_proto, server_address, server_port))
+
+ return results
+
+
+if servers is None:
+ servers = try_detect_servers()
+
+if not servers:
+ sys.exit(0)
+
+sys.stdout.write('<<<nginx_status>>>\n')
+for server in servers:
+ if isinstance(server, tuple):
+ proto, address, port = server
+ page = 'nginx_status'
+ else:
+ proto = server['protocol']
+ address = server['address']
+ port = server['port']
+ page = server.get('page', 'nginx_status')
+
+ try:
+ url = '%s://%s:%s/%s' % (proto, address, port, page)
+ # Try to fetch the status page for each server
+ try:
+ request = urllib2.Request(url, headers={"Accept": "text/plain"})
+ fd = urllib2.urlopen(request)
+ except urllib2.URLError, e:
+ if 'SSL23_GET_SERVER_HELLO:unknown protocol' in str(e):
+ # HACK: workaround misconfigurations where port 443 is used for
+ # serving non ssl secured http
+ url = 'http://%s:%s/%s' % (address, port, page)
+ fd = urllib2.urlopen(url)
+ else:
+ raise
+
+ for line in fd.read().split('\n'):
+ if not line.strip():
+ continue
+ if line.lstrip()[0] == '<':
+ # seems to be html output. Skip this server.
+ break
+ sys.stdout.write("%s %s %s\n" % (address, port, line))
+ except urllib2.HTTPError, e:
+ sys.stderr.write('HTTP-Error (%s:%d): %s %s\n' % (address, port, e.code, e))
+
+ except Exception, e:
+ sys.stderr.write('Exception (%s:%d): %s\n' % (address, port, e))
diff --git a/checkmk/checkmk-files/smart b/checkmk/checkmk-files/smart
new file mode 100644
index 0000000000000000000000000000000000000000..6e28c91faf990e511e00ab7b98081c9512719aa9
--- /dev/null
+++ b/checkmk/checkmk-files/smart
@@ -0,0 +1,179 @@
+#!/bin/bash
+# +------------------------------------------------------------------+
+# | ____ _ _ __ __ _ __ |
+# | / ___| |__ ___ ___| | __ | \/ | |/ / |
+# | | | | '_ \ / _ \/ __| |/ / | |\/| | ' / |
+# | | |___| | | | __/ (__| < | | | | . \ |
+# | \____|_| |_|\___|\___|_|\_\___|_| |_|_|\_\ |
+# | |
+# | Copyright Mathias Kettner 2014 mk@mathias-kettner.de |
+# +------------------------------------------------------------------+
+#
+# This file is part of Check_MK.
+# The official homepage is at http://mathias-kettner.de/check_mk.
+#
+# check_mk 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 in version 2. check_mk is distributed
+# in the hope that it will be useful, but WITHOUT ANY WARRANTY; with-
+# out even the implied warranty of MERCHANTABILITY or FITNESS FOR A
+# PARTICULAR PURPOSE. See the GNU General Public License for more de-
+# tails. You should have received a copy of the GNU General Public
+# License along with GNU Make; see the file COPYING. If not, write
+# to the Free Software Foundation, Inc., 51 Franklin St, Fifth Floor,
+# Boston, MA 02110-1301 USA.
+
+
+
+
+# This will be called on LSI based raidcontrollers and accesses
+# the SMART data of SATA disks attached to a SAS Raid HBA via
+# SCSI protocol interface.
+megaraid_info()
+{
+ #PDINFO=$(MegaCli -PDlist -a0)
+ if [ -z "$1" ]; then
+ PDINFO=$(megacli -PDlist -a0 -NoLog)
+ else
+ PDINFO=$($1 -PDlist -a0 -NoLog)
+ fi
+
+ echo "$PDINFO" | \
+ while read line ; do
+ case "$line" in
+ # FIRST LINE
+ "Enclosure Device ID"*) #Enclosure Device ID: 252
+ ENC=$( echo "$line" | awk '{print $4}')
+ unset SLOT LOG_DEV_ID VEND MODEL
+ ;;
+ "Slot Number"*) #Slot Number: 7
+ SLOT=$( echo "$line" | awk '{print $3}')
+ ;;
+ # Identify the logical device ID. smartctl needs it to access the disk.
+ "Device Id"*) #Device Id: 19
+ LOG_DEV_ID=$( echo "$line" | awk '{print $3}')
+ ;;
+ "PD Type"*) #PD Type: SATA
+ VEND=$( echo "$line" | awk '{print $3}')
+ ;;
+ # This is the last value, generate output here
+ "Inquiry Data"*)
+ #Inquiry Data: WD-WCC1T1035197WDC WD20EZRX-00DC0B0 80.00A80
+ # $4 seems to be better for some vendors... wont be possible to get this perfect.
+ MODEL=$( echo "$line" | awk '{print $3}')
+
+ # /dev/sdc ATA SAMSUNG_SSD_830 5 Reallocated_Sector_Ct 0x0033 100 100 010 Pre-fail Always -
+ smartctl -d megaraid,${LOG_DEV_ID} -v 9,raw48 -A /dev/sg0 | \
+ grep Always | egrep -v '^190(.*)Temperature(.*)' | \
+ sed "s|^|Enc${ENC}/Slot${SLOT} $VEND $MODEL |"
+ ;;
+ esac
+ done
+}
+
+
+# Only handle always updated values, add device path and vendor/model
+if which smartctl > /dev/null 2>&1 ; then
+ #
+ # if the 3ware-utility is found
+ # get the serials for all disks on the controller
+ #
+ if which tw_cli > /dev/null 2>&1 ; then
+ # support for only one controller at the moment
+ TWAC=$(tw_cli show | awk 'NR < 4 { next } { print $1 }' | head -n 1)
+
+ # - add a trailing zero to handle case of unused slot
+ # trailing zeros are part of the device links in /dev/disk/by-id/... anyway
+ # - only the last 9 chars seem to be relevant
+ # (hopefully all this doesn't change with new kernels...)
+ eval `tw_cli /$TWAC show drivestatus | grep -E '^p[0-9]' | awk '{print $1 " " $7 "0"}' | while read twaminor serial ; do
+ twaminor=${twaminor#p}
+ serial=${serial:(-9)}
+ serial=AMCC_${serial}00000000000
+ echo "$serial=$twaminor"
+ done`
+ else:
+ echo "tw_cli not found" >&2
+ fi
+
+ echo '<<<smart>>>'
+ SEEN=
+ for D in /dev/disk/by-id/{scsi,ata}-*; do
+ [ "$D" != "${D%scsi-\*}" ] && continue
+ [ "$D" != "${D%ata-\*}" ] && continue
+ [ "$D" != "${D%-part*}" ] && continue
+ N=$(readlink $D)
+ N=${N##*/}
+ if [ -r /sys/block/$N/device/vendor ]; then
+ VEND=$(tr -d ' ' < /sys/block/$N/device/vendor)
+ else
+ # 2012-01-25 Stefan Kaerst CDJ - in case $N does not exist
+ VEND=ATA
+ fi
+ if [ -r /sys/block/$N/device/model ]; then
+ MODEL=$(sed -e 's/ /_/g' -e 's/_*$//g' < /sys/block/$N/device/model)
+ else
+ MODEL=$(smartctl -a $D | grep -i "device model" | sed -e "s/.*:[ ]*//g" -e "s/\ /_/g")
+ fi
+ # Excluded disk models for SAN arrays or certain RAID luns that are also not usable..
+ if [ "$MODEL" = "iSCSI_Disk" -o "$MODEL" = "LOGICAL_VOLUME" ]; then
+ continue
+ fi
+
+ # Avoid duplicate entries for same device
+ if [ "${SEEN//.$N./}" != "$SEEN" ] ; then
+ continue
+ fi
+ SEEN="$SEEN.$N."
+
+ # strip device name for final output
+ DNAME=${D#/dev/disk/by-id/scsi-}
+ DNAME=${DNAME#/dev/disk/by-id/ata-}
+ # 2012-01-25 Stefan Kaerst CDJ - special option in case vendor is AMCC
+ CMD=
+ if [ "$VEND" == "AMCC" -a -n "$TWAC" ]; then
+ DNAME=${DNAME#1}
+ [ -z "${!DNAME}" ] && continue
+ CMD="smartctl -d 3ware,${!DNAME} -v 9,raw48 -A /dev/twa0"
+ # create nice device name including model
+ MODEL=$(tw_cli /$TWAC/p${!DNAME} show model | head -n 1 | awk -F= '{ print $2 }')
+ MODEL=${MODEL## }
+ MODEL=${MODEL// /-}
+ DNAME=${DNAME#AMCC_}
+ DNAME="AMCC_${MODEL}_${DNAME%000000000000}"
+ elif [ "$VEND" != "ATA" ] ; then
+ TEMP=
+ # create temperature output as expected by checks/smart
+ # this is a hack, TODO: change checks/smart to support SCSI-disks
+ eval `smartctl -d scsi -i -A $D | while read a b c d e ; do
+ [ "$a" == Serial ] && echo SN=$c
+ [ "$a" == Current -a "$b" == Drive -a "$c" == Temperature: ] && echo TEMP=$d
+ done`
+ [ -n "$TEMP" ] && CMD="echo 194 Temperature_Celsius 0x0000 000 000 000 Old_age Always - $TEMP (0 0 0 0)"
+ DNAME="${VEND}_${MODEL}_${SN}"
+ else
+ CMD="smartctl -d ata -v 9,raw48 -A $D"
+ fi
+
+ [ -n "$CMD" ] && $CMD | grep Always | egrep -v '^190(.*)Temperature(.*)' | sed "s|^|$DNAME $VEND $MODEL |"
+ done 2>/dev/null
+
+
+ # Call MegaRaid submodule if conditions are met
+ if type MegaCli >/dev/null 2>&1; then
+ MegaCli_bin="MegaCli"
+ elif type MegaCli64 >/dev/null 2>&1; then
+ MegaCli_bin="MegaCli64"
+ elif type megacli >/dev/null 2>&1; then
+ MegaCli_bin="megacli"
+ else
+ MegaCli_bin="unknown"
+ fi
+
+ if [ "$MegaCli_bin" != "unknown" ]; then
+ megaraid_info "$MegaCli_bin"
+ fi
+else
+ echo "ERROR: smartctl not found" >&2
+fi
+