From 0a7a075346b43d21bdc616a5baeb80a630be7c45 Mon Sep 17 00:00:00 2001 From: VC Date: Sun, 27 Oct 2024 07:38:52 +0100 Subject: [PATCH] =?UTF-8?q?=E2=9C=A8:=20munin=20zfs=20capability?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- roles/munin_client/files/zpool_capacity | 278 ++++++++++++++++++++++++ roles/munin_client/tasks/main.yml | 6 +- roles/munin_client/tasks/zfs.yml | 10 + 3 files changed, 291 insertions(+), 3 deletions(-) create mode 100644 roles/munin_client/files/zpool_capacity create mode 100644 roles/munin_client/tasks/zfs.yml diff --git a/roles/munin_client/files/zpool_capacity b/roles/munin_client/files/zpool_capacity new file mode 100644 index 0000000..4267365 --- /dev/null +++ b/roles/munin_client/files/zpool_capacity @@ -0,0 +1,278 @@ +#!/bin/bash + +: << =cut + +=head1 NAME + + zpool_capacity - Munin plugin to monitor ZFS capacity + + These functions are implemented: + capacity : to monitor zpool capacity % + fragmentation : to monitor zpool fragmentation % + allocated : to monitor zpool allocated bytes + dedup : to monitor zpool dedup and compress ratio + + Tested with Solaris 10 and 11, OpenIndiana Hipster, FreeBSD 11, CentOS 7 + +=head1 CONFIGURATION + + Make symlink: + cd /path/to/munin/etc/plugins + ln -s /path/to/munin/lib/plugins/zpool_capacity . + + For FreeBSD, it should be necessary to change shebang /bin/bash -> /usr/local/bin/bash + + For Linux, root privilege is necessary to run zpool command. + [zpool_capacity] + user root + +=head1 ENVIRONMENT VARIABLES + + critical : default 90 + warning : default 80 + +=head1 AUTHOR + + K.Cima https://github.com/shakemid + + Fragmentation graph by https://github.com/rantal + +=head1 LICENSE + + GPLv2 + +=head1 Magic markers + + #%# family=contrib + #%# capabilities=autoconf + +=cut + +# Include plugin.sh +. "${MUNIN_LIBDIR:-}/plugins/plugin.sh" +is_multigraph "$@" + +# Shell options +set -o nounset + +# Global variables +plugin_name=zpool_capacity +functions='capacity fragmentation allocated dedup' +zpool_cmd=/sbin/zpool +zfs_cmd=/sbin/zfs + +# Environment variables +: "${warning:=80}" +: "${critical:=90}" + +# Note: The performance of ZFS may significantly degrade when zpool capacity > 90% +# See also: https://docs.oracle.com/cd/E53394_01/html/E54801/zfspools-4.html + +# Functions + +preconfig() { + local func="$1" + local p c + + # data_attr format: field type draw label + # label can contain white-spaces. + data_attr= + + case $func in + capacity) + global_attr=" + graph_title ZFS storage pool - Capacity + graph_category fs + graph_args --base 1000 --lower-limit 0 --upper-limit 100 + graph_vlabel % allocated + graph_info ZFS storage pool - Capacity + warning ${warning} + critical ${critical} + " + for p in $pool_list + do + data_attr="${data_attr} + ${p} GAUGE LINE2 ${p}" + done + ;; + fragmentation) + global_attr=" + graph_title ZFS storage pool - Fragmentation + graph_category fs + graph_args --base 1000 --lower-limit 0 --upper-limit 100 + graph_vlabel % fragmentation + graph_info ZFS storage pool - Fragmentation + " + for p in $pool_list + do + data_attr="${data_attr} + ${p} GAUGE LINE2 ${p}" + done + ;; + allocated) + global_attr=" + graph_title ZFS storage pool - Allocated bytes + graph_category fs + graph_args --base 1024 --lower-limit 0 + graph_vlabel Bytes + graph_info ZFS storage pool - Allocated bytes + " + c=0 + for p in $pool_list + do + data_attr="${data_attr} + ${p}_size GAUGE LINE ${p} size + ${p}_allocated GAUGE LINE2 ${p} allocated" + global_attr="${global_attr} + ${p}_size.colour COLOUR${c} + ${p}_allocated.colour COLOUR${c}" + c=$(( c + 1 )) + done + ;; + dedup) + global_attr=" + graph_title ZFS storage pool - Dedup and compress ratio + graph_category fs + graph_args --base 1000 --lower-limit 1 + graph_vlabel Ratio + graph_info ZFS storage pool - Dedup and compress ratio + " + for p in $pool_list + do + data_attr="${data_attr} + ${p}_dedup GAUGE LINE ${p} dedup + ${p}_compress GAUGE LINE ${p} compress" + done + ;; + esac +} + +do_config() { + local func="$1" + local label_max_length=45 + local field type draw label + + preconfig "$func" + echo "multigraph ${plugin_name}_${func}" + + # print global attributes + echo "$global_attr" | sed -e 's/^ *//' -e '/^$/d' + + # print data source attributes + echo "$data_attr" | while read -r field type draw label + do + [ -z "$field" ] && continue + + field=$( clean_fieldname "$field" ) + echo "${field}.type ${type}" + echo "${field}.draw ${draw}" + echo "${field}.label ${label:0:${label_max_length}}" + if [ "$type" = 'DERIVE' ]; then + echo "${field}.min 0" + fi + if [ "$label" = 'dummy' ]; then + echo "${field}.graph no" + fi + done + + echo +} + +get_stats() { + local func="$1" + + case $func in + capacity) + "$zpool_cmd" list -H -o name,capacity | sed 's/%$//' + ;; + fragmentation) + "$zpool_cmd" list -H -o name,fragmentation | sed 's/%$//' + ;; + allocated) + ( "$zpool_cmd" list -H -p -o name,allocated \ + | awk '{ print $1"_allocated", $2 }' + "$zpool_cmd" list -H -p -o name,size \ + | awk '{ print $1"_size", $2 }' + ) + ;; + dedup) + "$zpool_cmd" list -H -o name,dedup \ + | sed 's/x$//' \ + | awk '{ print $1"_dedup", $2 }' + # example output: + # $ zpool list -H -o name,dedup + # rpool 1.00x + # ... + + "$zpool_cmd" list -H -o name \ + | xargs "$zfs_cmd" get -H -o name,value compressratio \ + | sed 's/x$//' \ + | awk '{ print $1"_compress", $2 }' + # example output: + # $ zfs get -H -o name,value compressratio rpool + # rpool 1.00x + ;; + esac +} + +do_fetch() { + local func="$1" + local zpool_stats field value + + # zpool_stats contains 'key value\n' + zpool_stats=$( get_stats "$func" ) + + echo "multigraph ${plugin_name}_${func}" + + echo "$zpool_stats" | while read -r field value + do + field=$( clean_fieldname "$field" ) + echo "${field}.value ${value}" + done + + echo +} + +autoconf() { + if [ -x "$zpool_cmd" ]; then + echo yes + else + echo "no (failed to find executable 'zpool')" + fi +} + +config() { + local func + + pool_list=$( "$zpool_cmd" list -H -o name ) + + for func in $functions + do + do_config "$func" + done +} + +fetch() { + local func + + for func in $functions + do + do_fetch "$func" + done +} + +# Main +case ${1:-} in +autoconf) + autoconf + ;; +config) + config + if [ "${MUNIN_CAP_DIRTYCONFIG:-0}" = "1" ]; then fetch; fi + ;; +*) + fetch + ;; +esac + +exit 0 diff --git a/roles/munin_client/tasks/main.yml b/roles/munin_client/tasks/main.yml index 93d3e23..3562449 100644 --- a/roles/munin_client/tasks/main.yml +++ b/roles/munin_client/tasks/main.yml @@ -111,9 +111,9 @@ ansible.builtin.include_tasks: hypervisors.yml when: "'hypervisors' in group_names" -# - name: Execute specific ZFS commands -# ansible.builtin.include_tasks: zfs.yml -# when: "'zfsservers' in group_names" +- name: Execute specific ZFS commands + ansible.builtin.include_tasks: zfs.yml + when: "'zfsservers' in group_names" # Specific LXC commands - name: Execute specific LXC commands diff --git a/roles/munin_client/tasks/zfs.yml b/roles/munin_client/tasks/zfs.yml new file mode 100644 index 0000000..9f226a3 --- /dev/null +++ b/roles/munin_client/tasks/zfs.yml @@ -0,0 +1,10 @@ +--- +- name: Put zpool_capacity script + ansible.builtin.copy: + src: files/zpool_capacity + dest: /etc/munin/plugins/zpool_capacity + owner: root + group: root + mode: "0o755" + notify: + - Restart munin-node