diff --git a/experimental/examples/cpu.json b/experimental/examples/cpu.json index 00e50d520..9dc3781e9 100644 --- a/experimental/examples/cpu.json +++ b/experimental/examples/cpu.json @@ -1,7 +1,13 @@ { "leaf": { "name": "cpu", - "output": "{status}: {count} CPU(s) average usage is {total_cpu_avg} %", + "output": { + "status": { + "header": "{status}: ", + "text": "CPU {idx} usage: {value} %" + }, + "default": "{status}: {count} CPU(s) average usage is {total_cpu_avg} %" + }, "entries": [ { "Agregation": { "name": "total_cpu_avg", "op": "Average"}}, { "Query": { "name": "cpu_{idx}", "oid": "1.3.6.1.2.1.25.3.3.1.2", "query": "Walk" }} diff --git a/experimental/src/generic/mod.rs b/experimental/src/generic/mod.rs index c58751fe9..4c1ec5bc2 100644 --- a/experimental/src/generic/mod.rs +++ b/experimental/src/generic/mod.rs @@ -4,6 +4,34 @@ extern crate serde_json; use lib::{r_snmp_bulk_walk, SnmpResult}; use serde::Deserialize; +#[derive(Copy, Clone, PartialEq)] +pub enum Status { + Ok = 0, + Warning = 1, + Critical = 2, + Unknown = 3, +} + +fn worst(a: Status, b: Status) -> Status { + let a_int = match a { + Status::Ok => 0, + Status::Warning => 1, + Status::Critical => 3, + Status::Unknown => 2, + }; + let b_int = match b { + Status::Ok => 0, + Status::Warning => 1, + Status::Critical => 3, + Status::Unknown => 2, + }; + if a_int > b_int { + return a; + } else { + return b; + } +} + #[derive(Deserialize, Debug, Clone, Copy)] enum Operation { None, @@ -41,10 +69,22 @@ struct Data { max: Option, } +#[derive(Deserialize, Debug)] +struct StatusText { + header: String, + text: String, +} + +#[derive(Deserialize, Debug)] +struct OutputTable { + default: String, + status: Option, +} + #[derive(Deserialize, Debug)] struct Leaf { name: String, - output: String, + output: OutputTable, entries: Vec, data: Option, } @@ -55,7 +95,7 @@ pub struct Command { } pub struct CmdResult { - pub status: i32, + pub status: Status, pub output: String, } @@ -66,33 +106,20 @@ pub struct CommandExt { pub critical_agregation: Option, } -fn compute_status(value: f32, warn: &Option, crit: &Option) -> i32 { +fn compute_status(value: f32, warn: &Option, crit: &Option) -> Status { if let Some(c) = crit { let crit = c.parse().unwrap(); if value > crit { - return 2; + return Status::Critical; } } if let Some(w) = warn { let warn = w.parse().unwrap(); if value > warn { - return 1; + return Status::Warning; } } - 0 -} - -fn build_status(metrics: &Vec<(String, f32, i32)>) -> i32 { - let mut retval = 0; - metrics.iter().for_each(|(_, _, s)| { - if *s > retval { - retval = *s; - if retval == 2 { - return; - } - } - }); - return retval; + Status::Ok } fn build_metrics<'a>( @@ -100,11 +127,11 @@ fn build_metrics<'a>( ag: &Option<(&str, usize, f32)>, ext: &'a CommandExt, ) -> ( - Vec<(String, f32, &'a Option, &'a Option)>, - i32, + Vec<(String, f32, &'a Option, &'a Option, Status)>, + Status, ) { - let mut metrics: Vec<(String, f32, &Option, &Option)> = Vec::new(); - let mut status = 0; + let mut metrics: Vec<(String, f32, &Option, &Option, Status)> = Vec::new(); + let mut status = Status::Ok; match ag { Some(a) => { // The agregation is located in first place @@ -113,10 +140,8 @@ fn build_metrics<'a>( let c = &ext.critical_agregation; let current_status = compute_status(a.2, &ext.warning_agregation, &ext.critical_agregation); - metrics.push((a.0.to_string(), a.2, w, c)); - if current_status > status { - status = current_status; - } + metrics.push((a.0.to_string(), a.2, w, c, current_status)); + status = worst(current_status, status); } } None => (), @@ -128,10 +153,9 @@ fn build_metrics<'a>( v.1, &ext.warning_core, &ext.critical_core, + current_status, )); - if current_status > status { - status = current_status; - } + status = worst(current_status, status); }); match ag { Some(a) => { @@ -143,10 +167,9 @@ fn build_metrics<'a>( a.2, &ext.warning_agregation, &ext.critical_agregation, + current_status, )); - if current_status > status { - status = current_status; - } + status = worst(current_status, status); } } None => (), @@ -203,7 +226,7 @@ impl Command { } None => { return CmdResult { - status: 3, + status: Status::Unknown, output: "No result".to_string(), }; } @@ -213,35 +236,82 @@ impl Command { fn build_output( &self, count: usize, - status: i32, - metrics: &Vec<(String, f32, &Option, &Option)>, + status: Status, + metrics: &Vec<(String, f32, &Option, &Option, Status)>, ag: &Option<(&str, usize, f32)>, ext: &CommandExt, ) -> String { - let mut retval = self - .leaf - .output - .replace("{count}", count.to_string().as_str()) - .replace( - "{status}", - match status { - 0 => "OK", - 1 => "WARNING", - 2 => "CRITICAL", - _ => "UNKNOWN", - }, - ); - match ag { - Some(a) => { - retval = retval.replace(format!("{{{}}}", a.0).as_str(), a.2.to_string().as_str()); + let mut output_text: String; + if status == Status::Ok { + output_text = self + .leaf + .output + .default + .replace("{count}", count.to_string().as_str()) + .replace( + "{status}", + match status { + Status::Ok => "OK", + Status::Warning => "WARNING", + Status::Critical => "CRITICAL", + Status::Unknown => "UNKNOWN", + }, + ); + match ag { + Some(a) => { + output_text = output_text + .replace(format!("{{{}}}", a.0).as_str(), a.2.to_string().as_str()); + } + None => (), + }; + } else { + let mut warning_array = Vec::new(); + let mut critical_array = Vec::new(); + let part = &self.leaf.output.status; + for (idx, m) in metrics.iter().enumerate() { + if m.4 == Status::Warning { + let output_str = match *part { + Some(ref s) => { + s.text.replace("{value}", m.1.to_string().as_str()) + .replace("{idx}", idx.to_string().as_str()) + } + None => "".to_string(), + }; + warning_array.push(output_str); + } else if m.4 == Status::Critical { + let part = &self.leaf.output.status; + let output_str = match *part { + Some(ref s) => { + s.text.replace("{value}", m.1.to_string().as_str()) + .replace("{idx}", idx.to_string().as_str()) + } + None => "".to_string(), + }; + critical_array.push(output_str); + } } - None => (), - }; - retval += " |"; + let warn_header = match *part { + Some(ref s) => &s.header.replace("{status}", "WARNING"), + None => "", + }; + let crit_header = match *part { + Some(ref s) => &s.header.replace("{status}", "CRITICAL"), + None => "", + }; + if !warning_array.is_empty() && !critical_array.is_empty() { + output_text = format!("{} {} - {} {}", crit_header, &critical_array.join(" - "), warn_header, &warning_array.join(" - ")); + } else if !warning_array.is_empty() { + output_text = format!("{} {}", warn_header, &warning_array.join(" - ")); + } else { + output_text = format!("{} {}", crit_header, critical_array.join(" - ")); + } + } + + let mut perfdata = " |".to_string(); match &self.leaf.data { Some(d) => { - metrics.iter().for_each(|(k, v, w, c)| { - retval += format!( + metrics.iter().for_each(|(k, v, w, c, s)| { + perfdata += format!( " {}={}{};{};{};{};{}", k, v, @@ -267,8 +337,8 @@ impl Command { }); } None => { - metrics.iter().for_each(|(k, v, w, c)| { - retval += format!( + metrics.iter().for_each(|(k, v, w, c, s)| { + perfdata += format!( " {}={};{};{}", k, v, @@ -285,6 +355,6 @@ impl Command { }); } }; - retval + output_text + &perfdata } } diff --git a/experimental/src/main.rs b/experimental/src/main.rs index 7079754f7..3413dfbc6 100644 --- a/experimental/src/main.rs +++ b/experimental/src/main.rs @@ -72,5 +72,5 @@ fn main() { }; let result = cmd.execute(&url, &cli.snmp_version, &cli.community, &ext); println!("{}", result.output); - std::process::exit(result.status); + std::process::exit(result.status as i32); }