mirror of
https://github.com/centreon/centreon-plugins.git
synced 2025-07-24 06:05:17 +02:00
enh(lib/generic): order in leafs has its importance and snmpbulkwalk is almost implemented
This commit is contained in:
parent
66abd1c93c
commit
5318cb5c38
@ -1,7 +1,7 @@
|
|||||||
extern crate serde;
|
extern crate serde;
|
||||||
extern crate serde_json;
|
extern crate serde_json;
|
||||||
|
|
||||||
use lib::{r_snmp_walk, SnmpResult};
|
use lib::{r_snmp_bulk_walk, SnmpResult};
|
||||||
use serde::Deserialize;
|
use serde::Deserialize;
|
||||||
use std::collections::{BTreeMap, HashMap};
|
use std::collections::{BTreeMap, HashMap};
|
||||||
|
|
||||||
@ -54,16 +54,16 @@ pub struct CmdResult {
|
|||||||
|
|
||||||
impl Command {
|
impl Command {
|
||||||
pub fn execute(&self, target: &str) -> CmdResult {
|
pub fn execute(&self, target: &str) -> CmdResult {
|
||||||
let mut agregation = ("", Operation::None);
|
let mut agregation = ("", 0, Operation::None);
|
||||||
let mut res: Option<(&str, SnmpResult)> = None;
|
let mut res: Option<(&str, SnmpResult)> = None;
|
||||||
for entry in &self.leaf.entries {
|
for (idx, entry) in self.leaf.entries.iter().enumerate() {
|
||||||
match entry {
|
match entry {
|
||||||
Entry::Agregation(op) => {
|
Entry::Agregation(op) => {
|
||||||
agregation = (&op.name, op.op);
|
agregation = (&op.name, idx, op.op);
|
||||||
}
|
}
|
||||||
Entry::Query(query) => match query.query {
|
Entry::Query(query) => match query.query {
|
||||||
QueryType::Walk => {
|
QueryType::Walk => {
|
||||||
res = Some((&query.name, r_snmp_walk(target, &query.oid)));
|
res = Some((&query.name, r_snmp_bulk_walk(target, &query.oid)));
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
}
|
}
|
||||||
@ -80,16 +80,16 @@ impl Command {
|
|||||||
idx += 1;
|
idx += 1;
|
||||||
});
|
});
|
||||||
let count = values.len();
|
let count = values.len();
|
||||||
let ag = match agregation.1 {
|
let ag = match agregation.2 {
|
||||||
Operation::Average => {
|
Operation::Average => {
|
||||||
let sum: f32 = values.iter().sum();
|
let sum: f32 = values.iter().sum();
|
||||||
Some((agregation.0, sum / values.len() as f32))
|
Some((agregation.0, agregation.1, sum / values.len() as f32))
|
||||||
}
|
}
|
||||||
_ => None,
|
_ => None,
|
||||||
};
|
};
|
||||||
let metrics = self.build_metrics(&labels, &values, &ag);
|
let metrics = self.build_metrics(&labels, &values, &ag);
|
||||||
let status = self.build_status();
|
let status = self.build_status();
|
||||||
let output = self.build_output(&ag, count, status, &metrics);
|
let output = self.build_output(count, status, &metrics);
|
||||||
return CmdResult { status, output };
|
return CmdResult { status, output };
|
||||||
}
|
}
|
||||||
None => {
|
None => {
|
||||||
@ -107,10 +107,9 @@ impl Command {
|
|||||||
|
|
||||||
fn build_output(
|
fn build_output(
|
||||||
&self,
|
&self,
|
||||||
ag: &Option<(&str, f32)>,
|
|
||||||
count: usize,
|
count: usize,
|
||||||
status: i32,
|
status: i32,
|
||||||
metrics: &BTreeMap<String, f32>,
|
metrics: &Vec<(String, f32)>,
|
||||||
) -> String {
|
) -> String {
|
||||||
let mut retval = self
|
let mut retval = self
|
||||||
.leaf
|
.leaf
|
||||||
@ -125,12 +124,6 @@ impl Command {
|
|||||||
_ => "UNKNOWN",
|
_ => "UNKNOWN",
|
||||||
},
|
},
|
||||||
);
|
);
|
||||||
match ag {
|
|
||||||
Some(a) => {
|
|
||||||
retval = retval.replace(format!("{{{}}}", a.0).as_str(), a.1.to_string().as_str());
|
|
||||||
}
|
|
||||||
None => {}
|
|
||||||
};
|
|
||||||
retval += " |";
|
retval += " |";
|
||||||
metrics.iter().for_each(|(k, v)| {
|
metrics.iter().for_each(|(k, v)| {
|
||||||
retval += format!(" {}={}", k, v).as_str();
|
retval += format!(" {}={}", k, v).as_str();
|
||||||
@ -142,15 +135,25 @@ impl Command {
|
|||||||
&self,
|
&self,
|
||||||
labels: &Vec<String>,
|
labels: &Vec<String>,
|
||||||
values: &Vec<f32>,
|
values: &Vec<f32>,
|
||||||
ag: &Option<(&str, f32)>,
|
ag: &Option<(&str, usize, f32)>,
|
||||||
) -> BTreeMap<String, f32> {
|
) -> Vec<(String, f32)> {
|
||||||
let mut metrics: BTreeMap<String, f32> = BTreeMap::new();
|
let mut metrics: Vec<(String, f32)> = Vec::new();
|
||||||
|
match ag {
|
||||||
|
Some(a) => {
|
||||||
|
if a.1 == 0 {
|
||||||
|
metrics.push((a.0.to_string(), a.2));
|
||||||
|
}
|
||||||
|
}
|
||||||
|
None => (),
|
||||||
|
}
|
||||||
values.iter().enumerate().for_each(|(i, v)| {
|
values.iter().enumerate().for_each(|(i, v)| {
|
||||||
metrics.insert(labels[i].clone(), *v);
|
metrics.push((labels[i].clone(), *v));
|
||||||
});
|
});
|
||||||
match ag {
|
match ag {
|
||||||
Some(a) => {
|
Some(a) => {
|
||||||
metrics.insert(a.0.to_string(), a.1);
|
if a.1 > 0 {
|
||||||
|
metrics.push((a.0.to_string(), a.2));
|
||||||
|
}
|
||||||
}
|
}
|
||||||
None => (),
|
None => (),
|
||||||
}
|
}
|
||||||
|
@ -6,13 +6,13 @@ extern crate regex;
|
|||||||
|
|
||||||
use log::{info, trace, warn};
|
use log::{info, trace, warn};
|
||||||
use rasn::types::ObjectIdentifier;
|
use rasn::types::ObjectIdentifier;
|
||||||
use rasn_snmp::v2::GetNextRequest;
|
|
||||||
use rasn_snmp::v2::GetRequest;
|
|
||||||
use rasn_snmp::v2::Pdu;
|
|
||||||
use rasn_snmp::v2::Pdus;
|
use rasn_snmp::v2::Pdus;
|
||||||
use rasn_snmp::v2::VarBind;
|
use rasn_snmp::v2::VarBind;
|
||||||
use rasn_snmp::v2::VarBindValue;
|
use rasn_snmp::v2::VarBindValue;
|
||||||
|
use rasn_snmp::v2::{BulkPdu, Pdu};
|
||||||
|
use rasn_snmp::v2::{GetBulkRequest, GetNextRequest, GetRequest};
|
||||||
use rasn_snmp::v2c::Message;
|
use rasn_snmp::v2c::Message;
|
||||||
|
use regex::Regex;
|
||||||
use std::ffi::CStr;
|
use std::ffi::CStr;
|
||||||
use std::ffi::CString;
|
use std::ffi::CString;
|
||||||
use std::net::UdpSocket;
|
use std::net::UdpSocket;
|
||||||
@ -174,7 +174,7 @@ pub fn r_snmp_get(target: &str, oid: &str, community: &str) -> SnmpResult {
|
|||||||
trace!("Received {} bytes", resp.0);
|
trace!("Received {} bytes", resp.0);
|
||||||
assert!(resp.0 > 0);
|
assert!(resp.0 > 0);
|
||||||
let decoded: Message<Pdus> = rasn::ber::decode(&buf[0..resp.0]).unwrap();
|
let decoded: Message<Pdus> = rasn::ber::decode(&buf[0..resp.0]).unwrap();
|
||||||
build_response(decoded)
|
build_response(decoded, false)
|
||||||
}
|
}
|
||||||
|
|
||||||
#[no_mangle]
|
#[no_mangle]
|
||||||
@ -254,19 +254,95 @@ pub fn r_snmp_walk(target: &str, oid: &str) -> SnmpResult {
|
|||||||
}
|
}
|
||||||
message = create_next_request(request_id, &resp_oid);
|
message = create_next_request(request_id, &resp_oid);
|
||||||
}
|
}
|
||||||
retval.concat(build_response(decoded));
|
retval.concat(build_response(decoded, true));
|
||||||
request_id += 1;
|
request_id += 1;
|
||||||
}
|
}
|
||||||
retval
|
retval
|
||||||
}
|
}
|
||||||
|
|
||||||
fn build_response(decoded: Message<Pdus>) -> SnmpResult {
|
///
|
||||||
|
/// Bulk walk
|
||||||
|
/// This function is similar to the walk function but it uses the GetBulkRequest PDU
|
||||||
|
/// to retrieve multiple values at once.
|
||||||
|
///
|
||||||
|
/// # Arguments
|
||||||
|
/// * `target` - The target IP address and port
|
||||||
|
/// * `oid` - The OID to walk
|
||||||
|
/// # Returns
|
||||||
|
/// An SnmpResult structure containing the variables
|
||||||
|
///
|
||||||
|
/// # Example
|
||||||
|
/// ```
|
||||||
|
/// use snmp_rust::r_snmp_bulk_walk;
|
||||||
|
/// let result = r_snmp_bulk_walk("127.0.0.1:161", "1.3.6.1.2.1.25.3.3.1.2");
|
||||||
|
/// ```
|
||||||
|
pub fn r_snmp_bulk_walk(target: &str, oid: &str) -> SnmpResult {
|
||||||
|
let community = "public";
|
||||||
|
let oid_tab = oid
|
||||||
|
.split('.')
|
||||||
|
.map(|x| x.parse::<u32>().unwrap())
|
||||||
|
.collect::<Vec<u32>>();
|
||||||
|
|
||||||
|
let mut retval = SnmpResult::new();
|
||||||
|
let mut request_id: i32 = 1;
|
||||||
|
|
||||||
|
let variable_bindings = vec![VarBind {
|
||||||
|
name: ObjectIdentifier::new_unchecked(oid_tab.to_vec().into()),
|
||||||
|
value: VarBindValue::Unspecified,
|
||||||
|
}];
|
||||||
|
|
||||||
|
let pdu = BulkPdu {
|
||||||
|
request_id,
|
||||||
|
non_repeaters: 0,
|
||||||
|
max_repetitions: 10,
|
||||||
|
variable_bindings,
|
||||||
|
};
|
||||||
|
let get_request: GetBulkRequest = GetBulkRequest(pdu);
|
||||||
|
|
||||||
|
let message: Message<GetBulkRequest> = Message {
|
||||||
|
version: 1.into(),
|
||||||
|
community: community.into(),
|
||||||
|
data: get_request.into(),
|
||||||
|
};
|
||||||
|
|
||||||
|
// Send the message through an UDP socket
|
||||||
|
let socket = UdpSocket::bind("0.0.0.0:0").unwrap();
|
||||||
|
socket.connect(target).expect("connect function failed");
|
||||||
|
let encoded: Vec<u8> = rasn::der::encode(&message).unwrap();
|
||||||
|
let res: usize = socket.send(&encoded).unwrap();
|
||||||
|
assert!(res == encoded.len());
|
||||||
|
|
||||||
|
let mut buf: [u8; 1024] = [0; 1024];
|
||||||
|
let resp: (usize, std::net::SocketAddr) = socket.recv_from(buf.as_mut_slice()).unwrap();
|
||||||
|
|
||||||
|
trace!("Received {} bytes", resp.0);
|
||||||
|
assert!(resp.0 > 0);
|
||||||
|
let decoded: Message<Pdus> = rasn::ber::decode(&buf[0..resp.0]).unwrap();
|
||||||
|
if let Pdus::Response(resp) = &decoded.data {
|
||||||
|
let resp_oid = &resp.0.variable_bindings[0].name;
|
||||||
|
let n = resp_oid.len() - 1;
|
||||||
|
}
|
||||||
|
retval.concat(build_response(decoded, true));
|
||||||
|
retval
|
||||||
|
}
|
||||||
|
|
||||||
|
fn build_response(decoded: Message<Pdus>, walk: bool) -> SnmpResult {
|
||||||
let mut retval = SnmpResult::new();
|
let mut retval = SnmpResult::new();
|
||||||
|
|
||||||
if let Pdus::Response(resp) = &decoded.data {
|
if let Pdus::Response(resp) = &decoded.data {
|
||||||
let vars = &resp.0.variable_bindings;
|
let vars = &resp.0.variable_bindings;
|
||||||
|
let mut header = "".to_string();
|
||||||
for var in vars {
|
for var in vars {
|
||||||
let name = var.name.to_string();
|
let name = var.name.to_string();
|
||||||
|
if walk {
|
||||||
|
if header == "" {
|
||||||
|
// We remove from name the last number after the last "." to get the header.
|
||||||
|
let n = name.rfind('.').unwrap();
|
||||||
|
header = name[0..n].to_string();
|
||||||
|
} else if !name.starts_with(&header) {
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
}
|
||||||
match &var.value {
|
match &var.value {
|
||||||
VarBindValue::Unspecified => {
|
VarBindValue::Unspecified => {
|
||||||
warn!("Unspecified");
|
warn!("Unspecified");
|
||||||
@ -321,7 +397,7 @@ mod tests {
|
|||||||
let expected = SnmpResult {
|
let expected = SnmpResult {
|
||||||
variables: vec![SnmpVariable::new(
|
variables: vec![SnmpVariable::new(
|
||||||
"1.3.6.1.2.1.1.1.0".to_string(),
|
"1.3.6.1.2.1.1.1.0".to_string(),
|
||||||
"Linux CNTR-PORT-A104 6.1.0-28-amd64 #1 SMP PREEMPT_DYNAMIC Debian 6.1.119-1 (2024-11-22) x86_64".to_string())],
|
"Linux CNTR-PORT-A104 6.1.0-31-amd64 #1 SMP PREEMPT_DYNAMIC Debian 6.1.128-1 (2025-02-07) x86_64".to_string())],
|
||||||
};
|
};
|
||||||
assert_eq!(result, expected);
|
assert_eq!(result, expected);
|
||||||
}
|
}
|
||||||
@ -338,4 +414,17 @@ mod tests {
|
|||||||
assert!(re.is_match(&v.value));
|
assert!(re.is_match(&v.value));
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
#[test]
|
||||||
|
fn test_snmp_bulk_walk() {
|
||||||
|
let result = r_snmp_bulk_walk("127.0.0.1:161", "1.3.6.1.2.1.25.3.3.1.2");
|
||||||
|
let re = Regex::new(r"[0-9]+").unwrap();
|
||||||
|
assert!(result.variables.len() > 0);
|
||||||
|
for v in result.variables.iter() {
|
||||||
|
println!("{:?}", v);
|
||||||
|
let name = &v.name;
|
||||||
|
assert!(name.starts_with("1.3.6.1.2.1.25.3.3.1.2"));
|
||||||
|
assert!(re.is_match(&v.value));
|
||||||
|
}
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
@ -3,8 +3,8 @@
|
|||||||
"name": "cpu",
|
"name": "cpu",
|
||||||
"output": "{status}: {count} CPU(s) average usage is {total_cpu_avg} %",
|
"output": "{status}: {count} CPU(s) average usage is {total_cpu_avg} %",
|
||||||
"entries": [
|
"entries": [
|
||||||
{ "Query": { "name": "cpu_{idx}", "oid": "1.3.6.1.2.1.25.3.3.1.2", "query": "Walk" }},
|
{ "Agregation": { "name": "total_cpu_avg", "op": "Average"}},
|
||||||
{ "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" }}
|
||||||
]
|
]
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
Loading…
x
Reference in New Issue
Block a user