wiki:PluginConcise

HowToWritePlugins > Concise plugins

The Concise guide to plugin authoring

Attention: Content of this page should be moved to the Munin-Guide --> Visit the Guide now.

First of all you should have read the HOWTO. This page is an attempt to be brief and yet complete rather than helpful to a newbie.

What is a plugin?

A plugin is a stand-alone program. In its most common form, it is a small perl program or shell script.

The plugins are run by munin-node, and invoked when contacted by the munin master. When this happens the munin-node runs each plugin twice. Once with the argument "config" to get graph configuration, and once with no argument to get graph data.

Arguments

Run time

A plugin is invoked twice every update-cycle. Once to emit config information and once to fetch values. Please see Data exchange between master and node for more information about the over-the-wire transactions.

config (mandatory)

The config output describes the plugin and the graph it creates. The full set of attributes you can use is found in the config reference.

fetch (mandatory)

When the node receives a fetch command for a plugin the plugin is invoked without any arguments on the command line and is expected to emit one or more field.value attribute values. One for each thing the plugin observes as defined by the config output. Plotting of graphs may be disabled by the config output.

Please note the following about plugin values:

  • If the plugin, for any reason, has no value to report it may send the value U for undefined. It should report values for every field it has configured during config.
  • In 1.3.4 and later: The plugin may back-date values by reporting them on the format field.value <epoch>:<value>, where <epoch> seconds since 1970/1/1 00:00 (unix epoch) and <value> is the value in the ordinary way. This can be useful for systems where the plugin receives old data and gives the correct time axis on the graph.

Install time

Install time is managed by one program: munin-node-configure. This program can both auto configure host plugins and given the right options it will auto configure snmp plugins for a specific host.

This program looks in plugins to see support at install-time determine how plug-and-play they are going to be for the user.

At install time an automated installation will run munin-node-configure to try to determine what plugins to run.

Every plugin with a family=auto magic marker (#%# family=auto) will be interrogated automatically by the first script with the "autoconf" and perhaps the "suggest" methods. You can change the family list with the --families option.

Any snmp__* plugins will be auto configured and installed by munin-node-configure --snmp with the apropriate arguments.

Every plugin magic marked with family=snmpauto and capabilities=snmpconf will be interrogated - when appropriately run by munin-node-configure.

Magic markers

See in Munin-Guide

autoconf

A plugin with a capabilities=autoconf magic marker will first be invoked with autoconf as the sole argument. When invoked thus the plugin should do one of these two:

  1. Print "yes" to signal that the plugin thinks it can be useful on this host
  2. Print "no" to signal that the plugin does not think so.

The plugin should always exit 0, even if the response is "no".

If the answer was "yes", and it's not a wildcard plugin, the plugin will be linked into the plugins catalog of munin-node.

Example:

# ./load autoconf
yes

If the answer is "no" the plugin may give a reason in parentheses. This may help the user to troubleshoot why the plugin is not used/does not work.

# ./load autoconf
no (No /proc/loadavg)

NOTE: If a plugin is autoconf-igurable it SHOULD not terminate in a uncontrolled way during autoconfiguration. Please make sure that whatever happens it ends up printing a yes or a no with a reasonable reason for why not.

In particular plugins written in Perl, Python and the like SHOULD not require non-core modules without protecting the code section. In perl one would do something like this (from apache_accesses at the time I write this):

if (! eval "require LWP::UserAgent;") {
    $ret = "LWP::UserAgent not found";
}
...
if ( defined $ARGV[0] and $ARGV[0] eq "autoconf" ) {
    if ($ret) {
        print "no ($ret)\n";
        exit 0;
    }
}

If the plugin is to be distributed with Munin the SHOULDs above are MUSTs.

suggest

Munin creates one graph per plugin. To create many graphs from one plugin, you can write a wildcard plugin.

These plugins take one or more bits of configuration from the file name it is run as. The plugin is stored as one file in the directory for available plugins, but is linked as multiple files in the directory for enabled plugins. This creates one graph per link name, using just one plugin as source.

Example:

/etc/munin/plugins/if_eth0 -> /usr/share/munin/plugins/if_
/etc/munin/plugins/if_eth1 -> /usr/share/munin/plugins/if_

As you see: wildcard plugins are easily recognized by their names ending in _.

A wildcard plugin that has a capabilites=suggest magic marker will after "autoconf" be invoked with "suggest" as the sole argument. When invoked thus the plugin should examine the system and determine which of the similar things it can report on and output a list of thse.

# ./if_ suggest
eth0
eth1

This means that the plugin can be run as if_eth0 and if_eth1. The plugin will then have to examine what's in C is called ARGV[0], and in perl and shell scripts as $0 to determine what exactly the start command was.

snmpconf

As stated above a plugin magic marked with family=snmpauto and capabilites=snmpconf will be invoked with "snmpconf" as the sole argument. A SNMP plugin is by definition a wildcard plugin, it may examine any host that supports SNMP. The name convention for a SNMP plugin is examplified by the df plugin: snmp__df. The hostname goes between the two consecutive underlines (_), and when invoked the plugin may examine $0, as any wildcard plugin must, to determine the name of the host it is to work with. It may also contain two wildcards as in snmp__if_. Here the index of the network interface appears after the third underline (_) at the end of the string. e.g. snmp_foo.example.com_if_1.

On the occasion of being run with "snmpconf" the plugin shall output one or more of the following:

For a plugin that is to monitor a number of (enumerated) items: the items have to be counted and indexed in the MIB and the plugin can express this so:

  • The word number followed by a OID giving the number of items
  • The word index, ending in a followed by a OID with a trailing dot on to the table of indecies

Both the snmp__df and the snmp__if_ plugins use this. The df plugin because it monitors multiple storage resources and wants to monitor only fixed disks. It expresses this by asking for the index OID for storage be present. The snmp__if_ plugin uses both number and index. The number OID gives the number of network interfaces on the device.

For a plugin named in the pattern analogous to snmp__if_ each of indecies will be used at the end of the plugin name, e.g. snmp_switch_if_10 for a device named switch, interface index 10.

  • The word require followed by an OID or the root of an OID that must exist on a SNMP agent. The OID may optionally be followed by a string or RE-pattern that specifies what sort of response is expected. For a indexed plugin (one that gives "number" and "index" the indecies will be appended to the require OID to check that OID for each indexed item (e.g. a interface)

Example:

# ./snmp__if_ snmpconf
number  1.3.6.1.2.1.2.1.0
index   1.3.6.1.2.1.2.2.1.1.
require 1.3.6.1.2.1.2.2.1.5. [0-9]
require 1.3.6.1.2.1.2.2.1.10. [0-9]

A require supports any perl RE, so for example one could require (6|32) from a OID to filter out only certain kinds of items.

If all the named items require and number, index given are found (and matched if a RE is given) the plugin will be activated by munin-node-configure.

munin-node-configure will send queries to devices the user has said are interesting to see if these OIDs exist and have matching values if required. If so the plugin will be linked into the munin-node plugin directory.

Configuration

Plugins are configured through files on each node.

The munin-node plugin configuration files reside in /etc/munin/plugin-conf.d/. These are used by munin-node to determine which privileges a plugin has (which user and group runs the plugin), and sets environment variables for the plugins to use. The files in /etc/munin/plugin-conf.d/ can contain configuration for one or more plugin each.

The configuration files are read in no particular order, and configuration in the the last read file overrides earlier configuration.

The format is:

[name or wildcard]
  user <username>
  group <group>
  env.<variable name> <variable content>

Privileges

Munin usually runs each plugin as an unprivileged user.

To run the plugin as a specific user:

[example]
 user someuser

To run a plugin with an additional group:

[example]
 group somegroup

Environment variables

To set the variable "logfile" to "/var/log/example.log" is:

[example]
 env.logfile /var/log/some.log

When using environment variables in your plugins, the plugin should contain sensible defaults.

Example /bin/sh code. This adds an environment variable called $LOG, and sets it to the value of $logfile (from "env.logfile" in the munin plugin configuration), with a default of "/var/log/syslog" if $logfile is empty:

#!/bin/sh

LOG=${logfile:-/var/log/syslog}

Example configuration

This plugin reads from /var/log/example.log, which readable by user "root" and group "adm". We set an environment variable for the logfile, and we need additional privileges to be able to read it. Choosing the least amount of privileges, we choose to run the plugin with the group "adm", instead of as the user "root".

[example]
 group adm
 env.logfile /var/log/example.log

Activating a munin plugin

To activate a plugin, it needs to be executable, and present in the munin plugin directory, commonly "/etc/munin/plugins". It can be copied or symlinked here.

Plugins distributed by munin is available in the directory for available munin plugins, commonly "/usr/share/munin/plugins". To activate these, make a symlink to the munin plugin directory.

Running a munin plugin interactively

A munin plugin is often run with other privileges and with a set of environment variables. To run a plugin with the correct set of variables, use the "munin-run" command. This takes a plugin file name as the first argument, and any plugin arguments as the next.

Example (with long lines broken):

ssm@mavis:~$ munin-run load config
graph_title Load average
graph_args --base 1000 -l 0
graph_vlabel load
graph_scale no
graph_category system
load.label load
load.warning 10
load.critical 120
graph_info The load average of the machine describes how many processes \
           are in the run-queue (scheduled to run "immediately").
load.info Average load for the five minutes.
ssm@mavis:~$ munin-run load 
load.value 0.11
Last modified at 2016-10-21T16:18:21+02:00 Last modified on 2016-10-21T16:18:21+02:00