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
//! Config data for a munin plugin

// We do not want to write unsafe code
#![forbid(unsafe_code)]

use log::trace;
use std::{env, 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,

    /// 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 cfgsize: 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 fetchsize: usize,
}

impl Config {
    /// Create a new Config with defined plugin_name, also setting
    /// [Config::pidfile] 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 {
        trace!("Creating new config for plugin {plugin_name}");
        let pd = plugin_name.clone();
        let mut cfg = Self {
            plugin_name,
            ..Default::default()
        };
        cfg.pidfile = cfg.plugin_statedir.join(pd + ".pid");
        cfg
    }
}

/// 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 =
            PathBuf::from(env::var("MUNIN_PLUGSTATE").unwrap_or_else(|_| String::from("/tmp")));
        Self {
            plugin_name: String::from("Simple munin plugin in Rust"),
            plugin_statedir: statedir.clone(),
            dirtyconfig: match env::var("MUNIN_CAP_DIRTYCONFIG") {
                Ok(val) => val.eq(&"1"),
                Err(_) => false,
            },
            daemonize: false,
            pidfile: statedir.join("munin-plugin.pid"),
            cfgsize: 8192,
            fetchsize: 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.fetchsize, 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"));
        assert_eq!(config2, config3);
    }
}