1
0
Fork 0
mirror of https://github.com/munin-monitoring/contrib.git synced 2025-07-21 18:41:03 +00:00

Merge pull request #1502 from brknkfr/mas

[mas_]: Add plugin to check users on a matrix authentication service (currently only for matrix synapse)
This commit is contained in:
Kenyon Ralph 2025-07-13 12:49:58 -07:00 committed by GitHub
commit d094af6765
No known key found for this signature in database
GPG key ID: B5690EEEBB952194
2 changed files with 223 additions and 37 deletions

169
plugins/synapse/mas_ Normal file
View file

@ -0,0 +1,169 @@
#!/usr/bin/env sh
# shellcheck shell=dash
set -e
: << =cut
=head1 NAME
mas_ - Monitor users on a matrix authentication service over admin API
=head1 APPLICABLE SYSTEMS
Matrix authentication service (currently only with matrix-synapse systems)
=head1 CONFIGURATION
Requires installed curl and jq, a command-line json processor.
This is a wildcard plugin. It monitors some simple values over the admin API
of matrix authentication service. Link mas_<masurl> to this file. The admin
endpoint has to be reachable from the plugin. The adminapi endpoint on the
matrix authentication service has to be enabled and a client (with client_id
and client_id) has to be configured accordingly.
ln -s /usr/share/munin/plugins/mas_ \
/etc/munin/plugins/mas_domain.tld
Set parameters in your munin-node configuration
[mas_masurl]
env.client_id <client_id>
env.client_secret <client_secret>
env.bot_names <list of bot names>
env.port <port>
env.scheme <default: https>
env.timeout <default: 2s>
To monitor a matrix authentication service instance on localhost you need
following:
ln -s /usr/share/munin/plugins/mas_ \
/etc/munin/plugins/mas_localhost
[mas_localhost]
env.client_id <client_id>
env.client_secret <client_secret>
env.port 8081
env.scheme http
=head1 AUTHOR
Copyright (C) 2025 Sebastian L. (https://momou.ch),
=head1 LICENSE
GPLv2
=head1 MAGIC MARKERS
#%# family=manual
#%# capabilities=autoconf
=cut
# shellcheck disable=SC1090
. "$MUNIN_LIBDIR/plugins/plugin.sh"
if [ "${MUNIN_DEBUG:-0}" = 1 ]; then
set -x
fi
CLIENT_ID="${client_id:-}"
CLIENT_SECRET="${client_secret:-}"
PORT="${port:-443}"
QUERY_LIMIT="${query_limit:-10000}"
MASSERVER="${0##*mas_}"
SCHEME="${scheme:-https}://"
TIMEOUT="${timeout:-2}"
CLEANMASSERVER="$(clean_fieldname "${MASSERVER}")"
get_access_token () {
ACCESS_TOKEN=$(curl -s -f -m "${TIMEOUT}" -u "$CLIENT_ID:$CLIENT_SECRET" -d "grant_type=client_credentials&scope=urn:mas:admin" "${SCHEME}${MASSERVER}/oauth2/token" | jq -r '.access_token')
}
fetch_url () {
get_access_token
curl -s -f -m "${TIMEOUT}" "$@"
}
case $1 in
autoconf)
if [ ! -x "$(command -v curl)" ]; then
echo "no (curl not found)"
elif [ ! -x "$(command -v jq)" ]; then
echo "no (jq not found)"
else
get_access_token
fetch_url -I -H "Authorization: Bearer ${ACCESS_TOKEN}" -I "${SCHEME}${MASSERVER}:${PORT}/api/admin/v1/users" \
| grep -iq "Content-Type: application/json" \
&& echo "yes" \
|| echo "no (invalid or empty response from matrix authentication service admin api)"
fi
exit 0
;;
config)
cat << EOM
multigraph mas_users_${CLEANMASSERVER}
graph_title Users on ${MASSERVER} (matrix authentication service)
graph_args --base 1000 -l 0
graph_printf %.0lf
graph_vlabel users
graph_info users
graph_category chat
registered.label registered users
registered.info registered users
registered.min 0
active.label active users
active.info active users
active.min 0
bots.label active bots
bots.info active bots
bots.min 0
deactivated.label deactivated users
deactivated.info deactivated users
deactivated.min 0
sessions.label user sessions
sessions.info user sessions
sessions.min 0
sessions.draw LINE2
EOM
exit 0
;;
esac
mktemp_command="${mktemp_command:-/usr/bin/mktemp}"
USERS_FILE=$($mktemp_command) || exit 73
trap 'rm -f "$USERS_FILE"' EXIT
get_access_token
fetch_url -g -H "Authorization: Bearer ${ACCESS_TOKEN}" "${SCHEME}${MASSERVER}:${PORT}/api/admin/v1/users?page[first]=${QUERY_LIMIT}" > "$USERS_FILE"
sessions=$(fetch_url -g -H "Authorization: Bearer ${ACCESS_TOKEN}" "${SCHEME}${MASSERVER}:${PORT}/api/admin/v1/user-sessions?filter[status]=active&page[first]=${QUERY_LIMIT}" | jq .meta[])
echo "multigraph mas_users_${CLEANMASSERVER}"
if total="$(jq -r .meta[] "$USERS_FILE" | grep -E "^[0-9]+$")"; then
if [ -n "$bot_names" ]; then
bot_names_grep=$(echo "$bot_names" | tr ' ' '|')
bot_names_grep="$bot_names_grep|"
fi
active_bots=$(jq '.data[] | select(.attributes.locked_at == null)' "$USERS_FILE" | grep -cE "\"username\": \"${bot_names_grep}.*bot\"")
deactivated_users=$(jq '.data[] | select(.attributes.locked_at != null)' "$USERS_FILE" | grep -E "\"username\": \"" | { grep -vcE "\"${bot_names_grep}.*bot\"" || true; })
registered_users=$(( total - active_bots ))
active_users=$(( registered_users - deactivated_users ))
echo registered.value "$registered_users"
echo active.value "$active_users"
echo bots.value "$active_bots"
echo deactivated.value "$deactivated_users"
echo sessions.value "$sessions"
else
echo "registered.value U"
echo "active.value U"
echo "bots.value U"
echo "deactivated.value U"
echo "sessions.value U"
fi

View file

@ -21,6 +21,10 @@ This is a wildcard plugin. It monitors some simple values over the admin API
of synapse matrix homeserver. Link synapse_<homeserverurl> to this file. The of synapse matrix homeserver. Link synapse_<homeserverurl> to this file. The
admin endpoint has to be reachable from the plugin. admin endpoint has to be reachable from the plugin.
If matrix authentication service is used, env.disable_users has to be set to
false and the env.auth_token has to be a compatibility token from the matrix
authentication service.
ln -s /usr/share/munin/plugins/synapse_ \ ln -s /usr/share/munin/plugins/synapse_ \
/etc/munin/plugins/synapse_domain.tld /etc/munin/plugins/synapse_domain.tld
@ -28,6 +32,7 @@ Set parameters in your munin-node configuration
[synapse_homeserverurl] [synapse_homeserverurl]
env.auth_token <auth_token> env.auth_token <auth_token>
env.disable_users <default: false>
env.interval <seconds> env.interval <seconds>
env.port <port> env.port <port>
env.admin_api_path <default: /_synapse/admin> env.admin_api_path <default: /_synapse/admin>
@ -48,6 +53,9 @@ To monitor a synapse instance on localhost you need following:
It's advised to use a dedicated munin bot account (user_type bot) with admin It's advised to use a dedicated munin bot account (user_type bot) with admin
rights on your matrix synapse server for this plugin. rights on your matrix synapse server for this plugin.
If matrix authentication service is enabled on the matrix synapse server,
disable the users check and use a compatibility token.
=head1 AUTHOR =head1 AUTHOR
Copyright (C) 2024 Sebastian L. (https://momou.ch), Copyright (C) 2024 Sebastian L. (https://momou.ch),
@ -71,6 +79,7 @@ if [ "${MUNIN_DEBUG:-0}" = 1 ]; then
fi fi
AUTH_TOKEN="${auth_token:-}" AUTH_TOKEN="${auth_token:-}"
DISABLE_USERS="${disable_users:-false}"
INTERVAL="${interval:-300}" INTERVAL="${interval:-300}"
PORT="${port:-443}" PORT="${port:-443}"
ADMIN_API_PATH="${admin_api_path:-/_synapse/admin}" ADMIN_API_PATH="${admin_api_path:-/_synapse/admin}"
@ -101,8 +110,9 @@ case $1 in
exit 0 exit 0
;; ;;
config) config)
USERS_CONFIG=""
cat << EOM if [ "$DISABLE_USERS" != "true" ]; then
USERS_CONFIG="
multigraph synapse_users_${CLEANHOMESERVER} multigraph synapse_users_${CLEANHOMESERVER}
graph_title Synapse users on ${HOMESERVER} graph_title Synapse users on ${HOMESERVER}
graph_args --base 1000 -l 0 graph_args --base 1000 -l 0
@ -128,7 +138,11 @@ deactivated_users.info deactivated users
deactivated_users.min 0 deactivated_users.min 0
erased_users.label erased users erased_users.label erased users
erased_users.info erased users erased_users.info erased users
erased_users.min 0 erased_users.min 0"
fi
cat << EOM
$USERS_CONFIG
multigraph synapse_rooms_${CLEANHOMESERVER} multigraph synapse_rooms_${CLEANHOMESERVER}
graph_title Synapse spaces and rooms on ${HOMESERVER} graph_title Synapse spaces and rooms on ${HOMESERVER}
graph_args --base 1000 -l 0 graph_args --base 1000 -l 0
@ -168,45 +182,48 @@ EOM
esac esac
mktemp_command="${mktemp_command:-/usr/bin/mktemp}" if [ "$DISABLE_USERS" != "true" ]; then
USERS_FILE=$($mktemp_command) || exit 73 mktemp_command="${mktemp_command:-/usr/bin/mktemp}"
trap 'rm -f "$USERS_FILE"' EXIT USERS_FILE=$($mktemp_command) || exit 73
trap 'rm -f "$USERS_FILE"' EXIT
fetch_url -H "Authorization: Bearer ${AUTH_TOKEN}" "${SCHEME}${HOMESERVER}:${PORT}${ADMIN_API_PATH}/v2/users?deactivated=true&limit=${QUERY_LIMIT}" > "$USERS_FILE" fetch_url -H "Authorization: Bearer ${AUTH_TOKEN}" "${SCHEME}${HOMESERVER}:${PORT}${ADMIN_API_PATH}/v2/users?deactivated=true&limit=${QUERY_LIMIT}" > "$USERS_FILE"
fi
ROOMS=$(fetch_url -H "Authorization: Bearer ${AUTH_TOKEN}" "${SCHEME}${HOMESERVER}:${PORT}${ADMIN_API_PATH}/v1/rooms?limit=${QUERY_LIMIT}") ROOMS=$(fetch_url -H "Authorization: Bearer ${AUTH_TOKEN}" "${SCHEME}${HOMESERVER}:${PORT}${ADMIN_API_PATH}/v1/rooms?limit=${QUERY_LIMIT}")
REPORTS=$(fetch_url -H "Authorization: Bearer ${AUTH_TOKEN}" "${SCHEME}${HOMESERVER}:${PORT}${ADMIN_API_PATH}/v1/event_reports" | jq .total) REPORTS=$(fetch_url -H "Authorization: Bearer ${AUTH_TOKEN}" "${SCHEME}${HOMESERVER}:${PORT}${ADMIN_API_PATH}/v1/event_reports" | jq .total)
echo "multigraph synapse_users_${CLEANHOMESERVER}" if [ "$DISABLE_USERS" != "true" ]; then
if total_number="$(jq -r .total "$USERS_FILE" | grep -E "^[0-9]+$")"; then echo "multigraph synapse_users_${CLEANHOMESERVER}"
puppets="$(jq -r '.users[] | select(.user_type!="bot") | select(.user_type!="support") | select(.last_seen_ts==null)' "$USERS_FILE")" if total_number="$(jq -r .total "$USERS_FILE" | grep -E "^[0-9]+$")"; then
bots="$(jq -r '.users[] | select(.user_type=="bot")' "$USERS_FILE")" puppets="$(jq -r '.users[] | select(.user_type!="bot") | select(.user_type!="support") | select(.last_seen_ts==null)' "$USERS_FILE")"
users="$(jq -r '.users[] | select(.user_type!="support") | select(.user_type!="bot") | select(.last_seen_ts!=null)' "$USERS_FILE")" bots="$(jq -r '.users[] | select(.user_type=="bot")' "$USERS_FILE")"
users="$(jq -r '.users[] | select(.user_type!="support") | select(.user_type!="bot") | select(.last_seen_ts!=null)' "$USERS_FILE")"
puppets_number="$(echo "$puppets" | grep -c '"last_seen_ts": null')" puppets_number="$(echo "$puppets" | grep -c '"last_seen_ts": null')"
bots_number="$(echo "$bots" | grep -c '"user_type": "bot"')" bots_number="$(echo "$bots" | grep -c '"user_type": "bot"')"
virtual_users_number=$(( puppets_number + bots_number )) virtual_users_number=$(( puppets_number + bots_number ))
total_registered_number=$(( total_number - virtual_users_number )) total_registered_number=$(( total_number - virtual_users_number ))
# Convert to miliseconds # Convert to miliseconds
time_ms=$(($(date +%s) * 1000)) time_ms=$(($(date +%s) * 1000))
interval_ms=$((INTERVAL * 1000)) interval_ms=$((INTERVAL * 1000))
time_interval_ago=$(( time_ms - interval_ms )) time_interval_ago=$(( time_ms - interval_ms ))
last_seen_times_ms=$(echo "$users" | jq -r 'select(.deactivated==false)' | grep -E "\"last_seen_ts\": [0-9]+") last_seen_times_ms=$(echo "$users" | jq -r 'select(.deactivated==false)' | grep -E "\"last_seen_ts\": [0-9]+")
online_users_number="$(echo "$last_seen_times_ms" | awk -v "count=0" -F": " '$2 > "'$time_interval_ago'" {count++} END {print count}')" online_users_number="$(echo "$last_seen_times_ms" | awk -v "count=0" -F": " '$2 > "'$time_interval_ago'" {count++} END {print count}')"
echo total_registered.value "$total_registered_number" echo total_registered.value "$total_registered_number"
echo active_users.value "$(echo "$users" | grep -c '"deactivated": false')" echo active_users.value "$(echo "$users" | grep -c '"deactivated": false')"
echo bots.value "$(echo "$bots" | grep -c '"deactivated": false')" echo bots.value "$(echo "$bots" | grep -c '"deactivated": false')"
echo online_users.value "$online_users_number" echo online_users.value "$online_users_number"
echo deactivated_users.value "$(echo "$users" | grep -c '"deactivated": true')" echo deactivated_users.value "$(echo "$users" | grep -c '"deactivated": true')"
echo erased_users.value "$(echo "$users" | grep -c '"erased": true')" echo erased_users.value "$(echo "$users" | grep -c '"erased": true')"
else else
echo "total_registered.value U" echo "total_registered.value U"
echo "active_users.value U" echo "active_users.value U"
echo "bots.value U" echo "bots.value U"
echo "online_users.value U" echo "online_users.value U"
echo "deactivated_users.value U" echo "deactivated_users.value U"
echo "erased_users.value U" echo "erased_users.value U"
fi
fi fi
echo multigraph synapse_rooms_"${CLEANHOMESERVER}" echo multigraph synapse_rooms_"${CLEANHOMESERVER}"