diff --git a/plugins/ilias/example-graphs/ilias-day.png b/plugins/ilias/example-graphs/ilias-day.png
new file mode 100644
index 00000000..130604cf
Binary files /dev/null and b/plugins/ilias/example-graphs/ilias-day.png differ
diff --git a/plugins/ilias/example-graphs/ilias_sessions-day.png b/plugins/ilias/example-graphs/ilias_sessions-day.png
deleted file mode 100644
index f53b11df..00000000
Binary files a/plugins/ilias/example-graphs/ilias_sessions-day.png and /dev/null differ
diff --git a/plugins/ilias/ilias_ b/plugins/ilias/ilias_
deleted file mode 100755
index 39bf1367..00000000
--- a/plugins/ilias/ilias_
+++ /dev/null
@@ -1,254 +0,0 @@
-#!/usr/bin/env python3
-# -*- coding: utf-8 -*-
-
-"""
-: << =cut
-
-=head1 NAME
-
-ilias - Munin plugin to monitor L open source
-learning management system
-
-=head1 DESCRIPTION
-
-Reads session and user statistcs from any ILIAS MySQLdb database.
-
-https://ilias.de/ | http://gallery.munin-monitoring.org/contrib/cms-index.html
-
-This plugin requires python3 and python3-mysqldb.
-
-There is a check for the the filename suffix _ (from the symlink) in place
-to decide which value to output. Symlink the file for each value you want
-displayed
-example:
- ln -s /usr/local/munin_plugins/ilias_ /etc/munin/plugins/ilias_sessions
-
-In order to get precise results, please ensure your MySQL server has the same
-time as your ILIAS application server. Timezone does not matter.
-
-=head1 CONFIGURATION
-
-The plugin needs the following configuration settings e.g. in
-/etc/munin/plugin-conf.d/ilias.conf
-
- [ilias_*]
- env.ildbuser ilias
- env.ildbpassword youriliaspasword
- env.ildb ilias
- env.ildbhost localhost
- env.ildbport 3306
-
-
-=head1 AUTHOR
-
-Copyright 2016 Pascal Seeland
-
-Copyright 2018 L
- (L)
-
-=head1 LICENSE
-
-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, and/or sell copies of the
-Software, and to permit persons to whom the Software is furnished to do so,
-provided that the above copyright notice(s) and this permission notice
-appear in all copies of the Software and that both the above copyright
-notice(s) and this permission notice appear in supporting documentation.
-
-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 OF THIRD PARTY RIGHTS.
-IN NO EVENT SHALL THE COPYRIGHT HOLDER OR HOLDERS INCLUDED IN THIS NOTICE BE
-LIABLE FOR ANY CLAIM, OR ANY SPECIAL INDIRECT OR CONSEQUENTIAL DAMAGES, OR
-ANY DAMAGES WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER
-IN AN ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT
-OF OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
-
-Except as contained in this notice, the name of a copyright holder shall not
-be used in advertising or otherwise to promote the sale, use or other
-dealings in this Software without prior written authorization of the
-copyright holder.
-
-=head1 CONTRIBUTE
-
-Find this plugin on L
-
-=head1 MAGIC MARKERS
-
- #%# family=auto
- #%# capabilities=autoconf suggest
-
-=head1 VERSION
-
- 1.0
-
-=head1 CHANGELOG
-
-=head2 1.0 - 2018/03/19
-
- first release
-
-=cut
-"""
-
-import os
-import sys
-import pkgutil
-
-
-class ILIAS():
- pluginname = sys.argv[0].split('_')[1]
-
- def __init__(self):
- self.con = None
- self.user = os.environ.get('ildbuser', 'root')
- self.pw = os.environ.get('ildbpassword', '')
- self.ildb = os.environ.get('ildb', 'ilias')
- self.ildbhost = os.environ.get('ildbhost', 'localhost')
- self.ildbport = int(os.environ.get('ildbport', 3306))
-
- def db_modules_available(self):
- return pkgutil.find_loader("MySQLdb")
-
- def get_connection(self):
- import MySQLdb
- return MySQLdb.connect(host=self.ildbhost,
- port=self.ildbport,
- user=self.user,
- passwd=self.pw,
- db=self.ildb)
-
- def connectdb(self):
- self.con = self.get_connection()
-
- def config_sessions(self):
- print("graph_title ILIAS Session")
- print("graph_info Number of active ILIAS user sessions")
- print("graph_vlabel ilsessions")
- print("graph_category cms")
- print("ilsessions.label ilSessions")
- print("ilsessions.min 0")
- print("ilsessions.draw AREA")
-
- def execute_sessions(self):
- cursor = self.con.cursor()
- cursor.execute(
- "SELECT COUNT( user_id ) "
- "FROM usr_session "
- "WHERE `expires` > UNIX_TIMESTAMP( NOW( ) ) AND user_id != 0"
- )
- usrs = cursor.fetchone()[0]
- print("ilsessions.value %s" % (usrs))
-
- def config_5minavg(self):
- print("graph_title ILIAS 5 avg")
- print("graph_info ILIAS sessions created or "
- "updated during the last 5 minutes")
- print("graph_vlabel il5minavg")
- print("graph_category cms")
- print("il5minavg.label 5 min Count")
- print("il5minavg.min 0")
- print("il5minavg.draw AREA")
-
- def execute_5minavg(self):
- cursor = self.con.cursor()
- cursor.execute(
- "SELECT COUNT( user_id ) "
- "FROM usr_session "
- "WHERE 5 * 60 > UNIX_TIMESTAMP( NOW( ) ) - ctime AND user_id != 0"
- )
- usrs = cursor.fetchone()[0]
- print("il5minavg.value %s" % (usrs))
-
- def config_60minavg(self):
- print("graph_title ILIAS 60 avg")
- print("graph_info ILIAS sessions created or "
- "updated during the last 60 minutes")
- print("graph_vlabel il60minavg")
- print("graph_category cms")
- print("il60minavg.label 60 min Count")
- print("il60minavg.min 0")
- print("il60minavg.draw AREA")
-
- def execute_60minavg(self):
- cursor = self.con.cursor()
- cursor.execute(
- "SELECT COUNT( user_id ) "
- "FROM usr_session "
- "WHERE 60 * 60 > UNIX_TIMESTAMP( NOW( ) ) - ctime AND user_id != 0"
- )
- usrs = cursor.fetchone()[0]
- print("il60minavg.value %s" % (usrs))
-
- def config_total1day(self):
- print("graph_title Users in 24h")
- print("graph_info ILIAS users logging in during last 24h")
- print("graph_vlabel iltotal1day")
- print("graph_category cms")
- print("iltotal1day.label User/24h")
- print("iltotal1day.min 0")
- print("iltotal1day.draw AREA")
-
- def execute_total1day(self):
- cursor = self.con.cursor()
- cursor.execute(
- "SELECT COUNT( usr_id ) "
- "FROM `usr_data` "
- "WHERE last_login >= DATE_SUB( NOW( ) , INTERVAL 1 DAY )")
- usrs = cursor.fetchone()[0]
- print("iltotal1day.value %s" % (usrs))
-
- def run(self):
- cmd = ((len(sys.argv) > 1) and sys.argv[1]) or "execute"
- function = None
-
- if cmd == "config":
- function = "config"
- elif cmd == "suggest":
- print("sessions")
- print("5minavg")
- print("60minavg")
- print("total1day")
- elif cmd == "autoconf":
- if not self.db_modules_available():
- print("no (Please install the MySQLdb python3 module)")
- else:
- try:
- con = self.get_connection()
- cursor = con.cursor()
- cursor.execute("SELECT COUNT( component ) "
- "FROM il_pluginslot")
- con.close()
- except _mysql.Error as e:
- print("no (Error %d: %s - Database configuration missing?)"
- % (e.args[0], e.args[1]))
- else:
- print("yes")
- else:
- function = "execute"
-
- if function is not None:
- if not self.db_modules_available():
- print("U (Please install the MySQLdb python3 module)")
- else:
- self.connectdb()
- try:
- func = getattr(self, "%s_%s" % (function, self.pluginname))
- except AttributeError:
- print('function not found "%s" (%s)' %
- ("config_%s" % self.pluginname, "self"))
- else:
- func()
-
- if self.con:
- self.con.close()
-
- sys.exit(0)
-
-
-if __name__ == "__main__":
- ILIAS().run()
-
diff --git a/plugins/ilias/ilias_session b/plugins/ilias/ilias_session
new file mode 100755
index 00000000..5f85a7c4
--- /dev/null
+++ b/plugins/ilias/ilias_session
@@ -0,0 +1,236 @@
+#!/usr/bin/env bash
+# Munin plugin for ILIAS
+
+: << =cut
+
+=head1 NAME
+
+ilias_session - Munin plugin to monitor L open source
+learning management system's sessions
+
+=head1 DESCRIPTION
+
+Reads session and user statistcs from any ILIAS MySQL/MariaDB database.
+
+https://ilias.de/ | http://gallery.munin-monitoring.org/contrib/cms-index.html
+
+Requirements:
+
+bash version 4 is required for associative array support.
+This plugin requires mysql CLI or a compatible client being available.
+
+In order to get precise results, please ensure your MySQL server has the same
+time as your ILIAS application server. Timezone does not matter.
+
+=head1 CONFIGURATION
+
+The plugin needs the following configuration settings e.g. in
+/etc/munin/plugin-conf.d/ilias.conf
+
+ [ilias_session]
+ env.ildbuser ilias
+ env.ildbpassword youriliaspasword
+ env.ildb ilias
+ env.ildbhost localhost
+ env.ildbport 3306
+
+WARNING: Setting env.ildbpassword will possibly expose the database password
+to other processes and might be insecure.
+
+=head1 AUTHOR
+
+Copyright 2018 L
+ (L)
+
+=head1 LICENSE
+
+Licensed under the MIT license:
+https://opensource.org/licenses/MIT
+
+=head1 CONTRIBUTE
+
+Find this plugin on L
+
+=head1 MAGIC MARKERS
+
+ #%# family=auto
+ #%# capabilities=autoconf
+
+=head1 VERSION
+
+ 2.0
+
+=head1 CHANGELOG
+
+=head2 2.0 - 2018/04/20
+
+ first sh release
+
+=head2 1.0 - 2018/03/19
+
+ first release
+
+=cut
+
+# Include plugin.sh
+# shellcheck source=/dev/null
+. "${MUNIN_LIBDIR:-}/plugins/plugin.sh"
+
+# Shell options
+set -o nounset # Like perl use strict;
+
+# Graph settings
+global_attr="
+ graph_title ILIAS session and logins
+ graph_category cms
+ graph_args --lower-limit 0
+ graph_vlabel occurences
+ graph_info Number of active ILIAS user sessions and logins
+"
+
+declare -A d_attr=( \
+ [0,field]=iltotal1day \
+ [0,type]=GAUGE \
+ [0,draw]=LINE \
+ [0,label]='users logged in within day' \
+ [0,sql]="SELECT COUNT( usr_id ) AS C
+ FROM \`usr_data\`
+ WHERE last_login >= DATE_SUB( NOW( ) , INTERVAL 1 DAY )
+ " \
+ [1,field]=ilsessions \
+ [1,type]=GAUGE \
+ [1,draw]=LINE \
+ [1,label]='active sessions' \
+ [1,sql]="SELECT COUNT( user_id ) AS C
+ FROM usr_session
+ WHERE \`expires\` > UNIX_TIMESTAMP( NOW( ) ) AND user_id != 0
+ " \
+ [2,field]=il60minavg \
+ [2,type]=GAUGE \
+ [2,draw]=LINE \
+ [2,label]='sessions created/updated within 1h' \
+ [2,sql]="SELECT COUNT( user_id ) AS C
+ FROM usr_session
+ WHERE 60 * 60 > UNIX_TIMESTAMP( NOW( ) ) - ctime AND user_id != 0
+ " \
+ [3,field]=il5minavg \
+ [3,type]=GAUGE \
+ [3,draw]=LINE \
+ [3,label]='sessions created/updated within 5min' \
+ [3,sql]="SELECT COUNT( user_id ) AS C
+ FROM usr_session
+ WHERE 5 * 60 > UNIX_TIMESTAMP( NOW( ) ) - ctime AND user_id != 0
+ " \
+)
+
+# Read the environment and apply defaults
+DB_CLI_TOOL="${ildbcli:-mysql}"
+DB_CLI_CMD="$(command -v "${DB_CLI_TOOL}")"
+DB_HOST="${ildbhost:-localhost}"
+DB_PORT="${ildbport:-3306}"
+DB="${ildb:-ilias}"
+DB_USER="${ildbuser:-root}"
+DB_PASSWORD="${ildbpassword:-}"
+
+# Functions
+
+autoconf() {
+ if command -v "${DB_CLI_TOOL}" >/dev/null ; then
+ echo yes
+ else
+ echo "no (failed to find executable '${DB_CLI_TOOL}')"
+ fi
+}
+
+config() {
+ local label_max_length=45
+ local i=0
+
+ # print global attributes
+ echo "$global_attr" | sed -e 's/^ *//' -e '/^$/d'
+
+ i=0
+ # -v varname
+ # True if the shell variable varname is set (has been assigned a value).
+ # https://stackoverflow.com/a/45385463/2683737
+ while [[ -v d_attr[$i,field] ]]; do
+ field=${d_attr[$i,field]}
+ echo "$field.type ${d_attr[$i,type]}"
+ echo "$field.draw ${d_attr[$i,draw]}"
+ echo "$field.label ${d_attr[$i,label]:0:${label_max_length}}"
+ echo "$field.min 0"
+ ((++i))
+ done
+}
+
+# Join a bash array $1 is the glue
+join_by() {
+ local d=$1
+ shift
+ echo -n "$1"
+ shift
+ printf "%s" "${@/#/$d}"
+}
+
+fetch() {
+ local i=0
+ local query=()
+ local query_string=""
+ declare -a results
+
+ # create an array of queries
+ i=0
+ while [[ -v d_attr[$i,field] ]]; do
+ query+=("${d_attr[$i,sql]}")
+ ((++i))
+ done
+
+ # build query by joining the array elements
+ query_string=$(join_by " UNION ALL " "${query[@]}")
+
+ # obtain result using CLI call; don't supply password through
+ # command line; note that MySQL considers it insecure using
+ # an environment variable:
+ # >This method of specifying your MySQL password must
+ # >be considered extremely insecure and should not be used.
+ # >Some versions of ps include an option to display the
+ # >environment of running processes. [...]
+ result=$(MYSQL_PWD="$DB_PASSWORD" \
+ "$DB_CLI_CMD" \
+ --skip-column-names \
+ -h "$DB_HOST" \
+ -u "$DB_USER" \
+ -P "$DB_PORT" \
+ "$DB" \
+ -e "$query_string" )
+
+ # initialize array
+ mapfile -t results <<< "$result"
+
+ # extract result and echo it to stdout, which is
+ # captured by Munin
+ i=0
+ while [[ -v d_attr[$i,field] ]]; do
+ echo "${d_attr[$i,field]}.value ${results[$i]}"
+ ((++i))
+ done
+}
+
+
+# Main
+case ${1:-} in
+autoconf)
+ autoconf
+ ;;
+config)
+ config
+ [ "${MUNIN_CAP_DIRTYCONFIG:-}" = "1" ] && fetch
+ ;;
+*)
+ fetch
+ ;;
+esac
+
+exit 0
+