1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 100 101 102 103 104 105 106 107 108 109 110 111 112 113 114 115 116 117 118 119 120 121 122 123 124 125 126 127 128 129 130 131 132 133 134 135 136 137 138 139 140 141 142 143 144 145 146 147 148 149 150 151 152 153 154 155 156 157 158 159 160 161 162 163 164 165 166 167 168 169 170 171 172 173 174 175 176 177 178 179 180 181 182 183 184 185 186 187 188 189 190 191 192 193 194 195 196 197
//! Config data for a munin plugin
// We do not want to write unsafe code
#![forbid(unsafe_code)]
use fastrand;
use log::trace;
use std::{
env,
iter::repeat_with,
path::{Path, PathBuf},
};
/// Plugin configuration.
#[derive(Clone, Debug, Eq, Hash, PartialEq)]
pub struct Config {
/// The name of the plugin.
///
/// Default is "Simple munin plugin in Rust"
pub plugin_name: String,
/// Plugins state directory
///
/// Fallback to /tmp if environment variable MUNIN_PLUGSTATE is
/// not set.
pub plugin_statedir: PathBuf,
/// Cachefile for the plugin
///
/// Plugins that daemonize and continuously fetch data need to
/// write them somewhere, so that the
/// [MuninPlugin::fetch](super::MuninPlugin::fetch) function can
/// output them. The default is a combination of
/// [Config::plugin_statedir] and a random string, with _munin_ and
/// _value_ added, in [std::format!] syntax: `"{}.munin.{}.value",
/// [Config::plugin_statedir], randomstring`.
pub plugin_cache: PathBuf,
/// Does munin support dirtyconfig? (Send data after sending config)
///
/// Checks MUNIN_CAP_DIRTYCONFIG environment variable, if set to 1,
/// this is true, otherwise false.
pub dirtyconfig: bool,
/// Does this plugin need to run in background, continuously fetching data?
///
/// Default to false
pub daemonize: bool,
/// If plugin uses daemonize, whats the pidfile name?
///
/// Defaults to [Config::plugin_statedir] plus "munin-plugin.pid", using
/// [Config::new] will set it to
/// [Config::plugin_statedir]/[Config::plugin_name].pid
pub pidfile: PathBuf,
/// Size of buffer for BufWriter for [MuninPlugin::config](super::MuninPlugin::config).
///
/// Defaults to 8192, but if the plugin outputs huge munin
/// configuration (trivial with multigraph plugins), you may want
/// to increase this.
pub config_size: usize,
/// Size of buffer for BufWriter for [MuninPlugin::fetch](super::MuninPlugin::fetch).
///
/// Defaults to 8192, but if the plugin outputs large datasets, it
/// is useful to increase this.
pub fetch_size: usize,
}
impl Config {
/// Return the plugin state directory as munin wants it - or /tmp
/// if no environment variable is set.
fn get_statedir() -> PathBuf {
PathBuf::from(env::var("MUNIN_PLUGSTATE").unwrap_or_else(|_| String::from("/tmp")))
}
/// Create a new Config with defined plugin_name, also setting
/// [Config::pidfile] and [Config::plugin_cache] to a sensible
/// value using the [Config::plugin_name].
///
/// # Examples
///
/// ```
/// # use munin_plugin::config::Config;
/// let config = Config::new(String::from("great-plugin"));
/// println!("My pidfile is {:?}", config.pidfile);
/// ```
pub fn new(plugin_name: String) -> Self {
Config::realnew(plugin_name, false)
}
/// Create a new Config for a streaming (daemonizing) plugin with
/// defined plugin_name, also setting [Config::pidfile] and
/// [Config::plugin_cache] to a sensible value using the
/// [Config::plugin_name].
///
/// # Examples
///
/// ```
/// # use munin_plugin::config::Config;
/// let config = Config::new_daemon(String::from("great-plugin"));
/// println!("My pidfile is {:?}", config.pidfile);
/// ```
pub fn new_daemon(plugin_name: String) -> Self {
Config::realnew(plugin_name, true)
}
/// Actually do the work of creating the config element
fn realnew(plugin_name: String, daemonize: bool) -> Self {
trace!("Creating new config for plugin {plugin_name}, daemon: {daemonize}");
let pd = plugin_name.clone();
Self {
plugin_name,
daemonize: daemonize,
pidfile: Config::get_statedir().join(format!("{}.pid", pd)),
plugin_cache: Config::get_statedir().join(format!("munin.{}.value", pd)),
..Default::default()
}
}
}
/// Useful defaults, if possible based on munin environment.
impl Default for Config {
/// Set default values, try to read munin environment variables to
/// fill [Config::plugin_statedir] and [Config::dirtyconfig].
/// [Config::plugin_statedir] falls back to _/tmp_ if no munin
/// environment variables are present.
fn default() -> Self {
let statedir = Config::get_statedir();
let insert: String = repeat_with(fastrand::alphanumeric).take(10).collect();
let cachename = Path::new(&statedir).join(format!("munin.{}.value", insert));
Self {
plugin_name: String::from("Simple munin plugin in Rust"),
plugin_statedir: statedir.clone(),
plugin_cache: cachename,
dirtyconfig: match env::var("MUNIN_CAP_DIRTYCONFIG") {
Ok(val) => val.eq(&"1"),
Err(_) => false,
},
daemonize: false,
pidfile: statedir.join("munin-plugin.pid"),
config_size: 8192,
fetch_size: 8192,
}
}
}
#[cfg(test)]
mod tests {
use super::*;
use std::path::PathBuf;
#[test]
fn test_modconfig() {
// Whole set of defaults
let config = Config {
..Default::default()
};
assert_eq!(
config.plugin_name,
String::from("Simple munin plugin in Rust")
);
// Use defaults (except for name)
let mut config2 = Config {
plugin_name: String::from("Lala"),
..Default::default()
};
// Is plugin name as given?
assert_eq!(config2.plugin_name, String::from("Lala"));
// Defaults as expected?
assert!(!config2.daemonize);
assert_eq!(config2.fetch_size, 8192);
config2.pidfile = PathBuf::new();
config2.pidfile.push(&config2.plugin_statedir);
config2.pidfile.push(String::from("Lala.pid"));
let config3 = Config::new(String::from("Lala"));
// At this point, the plugin_cache should be different
assert_ne!(config2, config3);
config2.plugin_cache = config2.plugin_statedir.join("munin.Lala.value");
assert_eq!(config2, config3);
}
#[test]
fn test_new_daemon() {
let config = Config::new_daemon(String::from("great-plugin"));
assert_eq!(config.plugin_name, String::from("great-plugin"));
assert_eq!(
config.plugin_cache,
PathBuf::from(String::from("/tmp/munin.great-plugin.value"))
);
assert!(config.daemonize);
}
}