Skip to content
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
26 changes: 13 additions & 13 deletions rust-plugins/Cargo.toml
Original file line number Diff line number Diff line change
Expand Up @@ -4,23 +4,23 @@ version = "1.0.0"
edition = "2024"

[build-dependencies]
lalrpop = "0.22.1"
lalrpop = "0.23.1"

[dependencies]
env_logger = "0.11.8"
lalrpop-util = { version = "0.22.1", features = ["lexer"] }
lexopt = "0.3.1"
log = "0.4.27"
rasn = "0.26.2"
rasn-smi = "0.26.2"
rasn-snmp = "0.26.2"
regex = "1.11.1"
serde = { version = "1.0.219", features = ["derive"] }
serde_json = "1.0.140"
snafu = "0.8.5"
env_logger = "0.11.11"
lalrpop-util = { version = "0.23.1", features = ["lexer"] }
lexopt = "0.3.2"
log = "0.4.33"
rasn = "0.28.13"
rasn-smi = "0.28.13"
rasn-snmp = "0.28.13"
regex = "1.13.1"
serde = { version = "1.0.229", features = ["derive"] }
serde_json = "1.0.151"
snafu = "0.9.2"

[dev-dependencies]
criterion = { version = "0.5", features = ["html_reports"] }
criterion = { version = "0.8.2", features = ["html_reports"] }

[[bench]]
name = "bench"
Expand Down
2 changes: 1 addition & 1 deletion rust-plugins/src/compute/ast.rs
Original file line number Diff line number Diff line change
Expand Up @@ -35,7 +35,7 @@ pub enum Func {
}

/// Result of evaluating an expression: either a numeric value/vector or a string.
#[derive(Debug)]
#[derive(Debug, PartialEq)]
pub enum ExprResult {
/// A vector of floating-point values.
Vector(Vec<f64>),
Expand Down
6 changes: 6 additions & 0 deletions rust-plugins/src/generic/error.rs
Original file line number Diff line number Diff line change
Expand Up @@ -36,6 +36,12 @@ pub enum Error {
#[snafu(display("Could not decode Snmp PDU received from server : {}", err))]
InvalidSnmpPduDecode { err: String },

#[snafu(display("Could not decode a value in the Snmp response : {}", detail))]
InvalidSnmpValue { detail: String },

#[snafu(display("Expected Type : {} for snmp oid", detail))]
InvalidSnmpType { detail: String },

#[snafu(display(
"Empty response from the server. Does the community have sufficient permissions ?"
))]
Expand Down
132 changes: 69 additions & 63 deletions rust-plugins/src/generic/mod.rs
Original file line number Diff line number Diff line change
Expand Up @@ -14,13 +14,13 @@ pub mod error;
use self::error::Result;
use crate::compute::{Compute, Parser, ast::ExprResult, threshold::Threshold};
use crate::output::{Output, OutputFormatter};
use crate::snmp::SnmpResult;
use crate::snmp::{snmp_bulk_get, snmp_bulk_walk, snmp_bulk_walk_with_labels};
use log::{debug, trace};
use regex::Regex;
use serde::Deserialize;
use std::collections::HashMap;

use crate::snmp::SnmpResult;
use std::convert::Into;

/// A single metric data point, ready to be included in plugin output.
///
Expand Down Expand Up @@ -49,50 +49,41 @@ pub enum Status {
Critical = 2,
Unknown = 3,
}

impl Status {
fn as_str(&self) -> &str {
match *self {
Status::Ok => "OK",
Status::Warning => "WARNING",
Status::Critical => "CRITICAL",
Status::Unknown => "UNKNOWN",
impl Into<i32> for Status {
fn into(self) -> i32 {
match self {
Status::Ok => 0,
Status::Warning => 1,
Status::Critical => 3,
Status::Unknown => 2,
}
}

}
impl Into<String> for Status {
fn into(self) -> String {
match self {
Status::Ok => "OK".to_string(),
Status::Warning => "WARNING".to_string(),
Status::Critical => "CRITICAL".to_string(),
Status::Unknown => "UNKNOWN".to_string(),
}
}
}
impl Status {
/// Returns `true` if `self` is at least as severe as `other`.
///
/// Severity order: `Ok < Warning < Unknown < Critical`.
pub fn is_worse_than(&self, other: Status) -> bool {
let self_int = match self {
Status::Ok => 0,
Status::Warning => 1,
Status::Critical => 3,
Status::Unknown => 2,
};
let other_int = match other {
Status::Ok => 0,
Status::Warning => 1,
Status::Critical => 3,
Status::Unknown => 2,
};
let self_int: i32 = (*self).into();
let other_int: i32 = other.into();
self_int >= other_int
}
}

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,
};
let a_int: i32 = a.into();
let b_int: i32 = b.into();

if a_int > b_int {
return a;
} else {
Expand Down Expand Up @@ -241,7 +232,10 @@ impl Command {
}

let output = if lines.len() <= 1 {
format!("OK: {}", lines.first().unwrap_or(&"No response".to_string()))
format!(
"OK: {}",
lines.first().unwrap_or(&"No response".to_string())
)
} else {
format!("OK: Response received\n{}", lines.join("\n"))
};
Expand Down Expand Up @@ -280,35 +274,41 @@ impl Command {
}
collect.push(SnmpResult::new(items));
}
} else {
let mut to_get = Vec::new();
let mut get_name = Vec::new();
for s in self.collect.snmp.iter() {
match s.query {
QueryType::Walk => {
if let Some(lab) = &s.labels {
let r = snmp_bulk_walk_with_labels(
target, version, community, &s.oid, &s.name, &lab,
);
collect.push(r?);
} else {
let r = snmp_bulk_walk(target, version, community, &s.oid, &s.name);
collect.push(r?);
return Ok(collect);
}
let mut to_get = Vec::new();
let mut get_name = Vec::new();
for s in self.collect.snmp.iter() {
match s.query {
QueryType::Walk => {
if let Some(lab) = &s.labels {
let r = snmp_bulk_walk_with_labels(
target, version, community, &s.oid, &s.name, &lab,
)?;
if !r.items.is_empty() {
collect.push(r);
}
} else {
let r = snmp_bulk_walk(target, version, community, &s.oid, &s.name)?;
if !r.items.is_empty() {
collect.push(r);
}
}
QueryType::Get => {
to_get.push(s.oid.as_str());
get_name.push(s.name.as_str());
}
}
}

if !to_get.is_empty() {
let r = snmp_bulk_get(target, version, community, 1, 1, &to_get, &get_name);
collect.push(r?);
QueryType::Get => {
to_get.push(s.oid.as_str());
get_name.push(s.name.as_str());
}
}
}

if !to_get.is_empty() {
let r = snmp_bulk_get(target, version, community, 1, 1, &to_get, &get_name);
collect.push(r?);
}
if collect.is_empty() {
return Err(error::Error::EmptyResponse {});
}
Ok(collect)
}

Expand Down Expand Up @@ -648,17 +648,23 @@ impl Command {

if !self.compute.metrics.is_empty() {
for metric in &self.compute.metrics {
let suffix = metric.threshold_suffix.as_deref().unwrap_or( "(no suffix)" );
println!(" {} (--warning-{}, --critical-{})", metric.name, suffix, suffix);
let suffix = metric.threshold_suffix.as_deref().unwrap_or("(no suffix)");
println!(
" {} (--warning-{}, --critical-{})",
metric.name, suffix, suffix
);
}
}

if let Some(aggregations) = self.compute.aggregations.as_ref() {
if !aggregations.is_empty() {
println!("Aggregations:");
for metric in aggregations {
let suffix = metric.threshold_suffix.as_deref().unwrap_or( "(no suffix)" );
println!(" {} (--warning-{}, --critical-{})", metric.name, suffix, suffix);
let suffix = metric.threshold_suffix.as_deref().unwrap_or("(no suffix)");
println!(
" {} (--warning-{}, --critical-{})",
metric.name, suffix, suffix
);
}
}
}
Expand Down
9 changes: 8 additions & 1 deletion rust-plugins/src/main.rs
Original file line number Diff line number Diff line change
Expand Up @@ -51,8 +51,14 @@ fn main() -> Result<(), Error> {
match std::panic::catch_unwind(|| snmp_plugin()) {
std::result::Result::Ok(plugin_result) => plugin_result,
Err(e) => {
let message = e
.downcast_ref::<&str>()
.map(|s| s.to_string())
.or_else(|| e.downcast_ref::<String>().cloned())
.unwrap_or_else(|| "unknown panic payload".to_string());
println!(
"Unexpected error while executing the plugin, please use RUST_BACKTRACE=1 or PLUGIN_LOG=trace to find more information"
"Unexpected error : '{}' while executing the plugin, please use RUST_BACKTRACE=1 or PLUGIN_LOG=trace to find more information ",
message
);
std::process::exit(3);
}
Expand Down Expand Up @@ -261,6 +267,7 @@ fn snmp_plugin() -> Result<(), Error> {
println!("JSON is valid");
} else {
println!("{}", result.output);
std::process::exit(result.status.into());
}

Ok(())
Expand Down
Loading
Loading