Last active
April 7, 2022 20:05
-
-
Save PhrozenByte/2c0e03bbdb750da4c36d54f02c009430 to your computer and use it in GitHub Desktop.
Munin statefile support functions for munin shell plugins
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
# -*- sh -*- | |
# Munin statefile support functions for munin shell plugins | |
# | |
: << =cut | |
=head1 NAME | |
plugin-statefile.sh - Munin statefile support functions for munin shell plugins | |
=head1 AUTHOR | |
Copyright (C) 2019 Daniel Rudolf | |
=head1 LICENSE | |
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, version 3 of the License only. | |
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. | |
See <http://www.gnu.org/licenses/> to receive a full-text-copy of | |
the GNU General Public License. | |
=cut | |
MUNIN_STATEFILE_TMP="" | |
# Checks whether all given arguments are valid munin field names. | |
# | |
# `test_fieldname` takes a arbitrary number of parameters and returns with rc 0 | |
# when all given arguments are valid munin field names, otherwise it returns | |
# with rc 1. | |
# | |
# Usage: | |
# test_fieldname foo bar_42 | |
test_fieldname () { | |
[ $# -gt 0 ] || return 1 | |
for ARG in "$@"; do | |
if [ -z "$ARG" ] || ! echo "$ARG" | sed -ne '/^[A-Za-z_][A-Za-z0-9_]*$/!{q1}'; then | |
return 1 | |
fi | |
done | |
} | |
# Writes data to the temporary munin statefile. | |
# | |
# `write_statefile` takes three or any larger odd number of parameters. The | |
# first argument is the common field name to all attributes to store. All | |
# following argument tuples represent the names and values of attributes to | |
# write to the temporary statefile. | |
# | |
# Both field names and attribute names must meet munin's field name | |
# requirements. Use `clean_fieldname` to create compliant names. You can't | |
# store multiline values. | |
# | |
# All data is written to a temporary file until explicitly commited using | |
# `commit_statefile`. You can also discard all data written by calling | |
# `discard_statefile`. | |
# | |
# Usage: | |
# write_statefile my_field foo value_of_foo bar value_of_bar | |
# write_statefile my_other_field answer_to_life_universe_and_everything 42 | |
write_statefile () { | |
if [ -z "$MUNIN_STATEFILE_TMP" ]; then | |
MUNIN_STATEFILE_TMP="$(mktemp)" | |
echo "%MUNIN-STATE1.0" > "$MUNIN_STATEFILE_TMP" | |
fi | |
local FIELD="$1" | |
test_fieldname "$FIELD" || { echo "Invalid field name: $FIELD" >&2; return 1; } | |
shift | |
local ATTR="" | |
local VALUE="" | |
while [ $# -ge 2 ]; do | |
ATTR="$1" | |
test_fieldname "$ATTR" || { echo "Invalid attribute name: $ATTR" >&2; return 1; } | |
VALUE="$2" | |
[ "$(echo "$VALUE" | wc -l)" -eq 1 ] || { echo "Invalid multiline attribute value: $VALUE" >&2; return 1; } | |
shift 2 | |
[ -n "$VALUE" ] || continue | |
echo "$FIELD.$ATTR $(echo "$VALUE" | head -n 1)" >> "$MUNIN_STATEFILE_TMP" | |
done | |
} | |
# Discards the temporary munin statefile. | |
# | |
# `discard_statefile` deletes the temporary munin statefile and discards all | |
# uncommited data. | |
# | |
# Usage: | |
# discard_statefile | |
discard_statefile () { | |
[ -z "$MUNIN_STATEFILE_TMP" ] || rm -f "$MUNIN_STATEFILE_TMP" | |
MUNIN_STATEFILE_TMP="" | |
} | |
# Commits the temporary munin statefile. | |
# | |
# `commit_statefile` replaces the plugin's statefile by the temporary munin | |
# statefile (created by `write_statefile`). If there's no temporary munin | |
# statefile (i.e. `write_statefile` wasn't called yet), the plugin's statefile | |
# will be deleted. | |
# | |
# Usage: | |
# commit_statefile | |
commit_statefile () { | |
if [ -z "$MUNIN_STATEFILE_TMP" ]; then | |
rm -f "$MUNIN_STATEFILE" | |
return 0 | |
fi | |
mv "$MUNIN_STATEFILE_TMP" "$MUNIN_STATEFILE" | |
} | |
# Returns attribute values stored in the plugin's statefile. | |
# | |
# `read_statefile` switches behavior depending on the number of arguments | |
# given. It always reads the plugin's statefile and bypasses the temporary | |
# munin statefile until it was commited using `commit_statefile`. | |
# | |
# If no argument is given, `read_statefile` returns a list of all fields | |
# present in the plugin's statefile. | |
# | |
# If a single argument is given, `read_statefile` takes this argument as field | |
# name and returns a list of the names of all attributes stored for this field. | |
# | |
# If multiple arguments are given, `read_statefile` takes the first argument as | |
# common field name and all following arguments as attribute names. It returns | |
# the values of the searched attributes line by line. The number of lines | |
# returned strictly matches the number of attributes requested, resuting in | |
# empty lines for non-existing attributes. | |
# | |
# Usage: | |
# read_statefile | |
# Return: | |
# my_field | |
# my_other_field | |
# | |
# Usage: | |
# read_statefile my_field | |
# Return: | |
# foo | |
# bar | |
# | |
# Usage: | |
# read_statefile my_field foo non_existing bar | |
# Return: | |
# value_of_foo | |
# | |
# value_of_bar | |
read_statefile () { | |
if ! [ -f "$MUNIN_STATEFILE" ]; then | |
[ $# -lt 2 ] || seq 2 $# | xargs printf '\n%.0s' | |
return 0 | |
fi | |
[ "$(head -n 1 "$MUNIN_STATEFILE")" == "%MUNIN-STATE1.0" ] || { echo "Invalid statefile header" >&2; return 1; } | |
if [ $# -eq 0 ]; then | |
sed -ne '2,$s/^\([A-Za-z0-9_]*\)\.[A-Za-z0-9_]* .*$/\1/p' "$MUNIN_STATEFILE" | uniq | |
return 0 | |
elif [ $# -eq 1 ]; then | |
local FIELD="$1" | |
test_fieldname "$FIELD" || { echo "Invalid field name: $FIELD" >&2; return 1; } | |
sed -ne "2,\$s/^$FIELD\.\([A-Za-z0-9_]*\) .*$/\1/p" "$MUNIN_STATEFILE" | uniq | |
return 0 | |
fi | |
local FIELD="$1" | |
test_fieldname "$FIELD" || { echo "Invalid field name: $FIELD" >&2; return 1; } | |
shift | |
local ATTR="" | |
while [ $# -gt 0 ]; do | |
ATTR="$1" | |
test_fieldname "$ATTR" || { echo "Invalid attribute name: $ATTR" >&2; return 1; } | |
shift | |
echo "$(sed -ne "2,\$s/^$FIELD\.$ATTR \(.*\)$/\1/p" "$MUNIN_STATEFILE" | tail -n 1)" | |
done | |
} | |
# Assigns variables for all attributes stored in the plugin's statefile. | |
# | |
# `assign_statefile` takes a single parameter as field name and assigns | |
# variables for all attributes stored for this field. | |
# | |
# Example: | |
# write_statefile my_field foo value_of_foo bar value_of_bar | |
# commit_statefile | |
# assign_statefile my_field | |
# | |
# The above example will assign the variables `$foo` and `$bar` with the | |
# values "value_of_foo" resp. "value_of_bar". | |
# | |
# Usage: | |
# assign_statefile my_field | |
assign_statefile () { | |
[ -f "$MUNIN_STATEFILE" ] || return 0 | |
[ "$(head -n 1 "$MUNIN_STATEFILE")" == "%MUNIN-STATE1.0" ] || { echo "Invalid statefile header" >&2; return 1; } | |
local FIELD="$1" | |
test_fieldname "$FIELD" || { echo "Invalid field name: $FIELD" >&2; return 1; } | |
shift | |
local ATTR="" | |
local VALUE="" | |
while IFS=" " read -r ATTR VALUE; do | |
eval "$ATTR=\"\$VALUE\"" | |
done < <(sed -ne "2,\$s/^$FIELD\.\([A-Za-z0-9_]*\) \(.*\)$/\1 \2/p" "$MUNIN_STATEFILE") | |
} |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment