enh(generic-snmp): first steps for a little parser

This commit is contained in:
David Boucher 2025-03-22 14:46:07 +01:00
parent 44dca5dde0
commit 7d7fe2094f
6 changed files with 157 additions and 42 deletions

View File

@ -9,6 +9,9 @@ crate-type = ["cdylib"]
name = "generic-snmp" name = "generic-snmp"
path = "src/main.rs" path = "src/main.rs"
[build-dependencies]
lalrpop = "0.22.1"
[dependencies] [dependencies]
regex = "1.11.1" regex = "1.11.1"
rasn = "0.24.0" rasn = "0.24.0"
@ -18,3 +21,5 @@ log = "0.4.25"
clap = { version = "4.5.29", features = ["derive"] } clap = { version = "4.5.29", features = ["derive"] }
serde = { version = "1.0.217", features = ["derive"] } serde = { version = "1.0.217", features = ["derive"] }
serde_json = "1.0.138" serde_json = "1.0.138"
lalrpop-util = { version = "0.22.1", features = ["lexer"] }

3
experimental/build.rs Normal file
View File

@ -0,0 +1,3 @@
fn main() {
lalrpop::process_root().unwrap();
}

18
experimental/note.txt Normal file
View File

@ -0,0 +1,18 @@
/usr/lib/nagios/plugins/centreon_plugins.pl --plugin=os::linux::snmp::plugin --mode=memory --hostname=localhost --snmp-version=2c --snmp-port=161 --snmp-community=public --snmp-timeout=1
OK: Ram Total: 19.38 GB Used (-buffers/cache): 537.96 MB (2.71%) Free: 18.85 GB (97.29%), Buffer: 33.12 MB, Cached: 284.99 MB, Shared: 5.71 MB | 'used'=564088832B;;;0;20807671808 'free'=20243582976B;;;0;20807671808 'used_prct'=2.71%;;;0;100 'buffer'=34734080B;;;0; 'cached'=298831872B;;;0; 'shared'=5984256B;;;0;
snmpbulkget localhost -v 2c -c public -Cn0 -Cr1 1.3.6.1.4.1.2021.4.6.0 1.3.6.1.4.1.2021.4.4.0 1.3.6.1.4.1.2021.4.14.0 1.3.6.1.4.1.2021.4.13.0 1.3.6.1.4.1.2021.4.11.0 1.3.6.1.4.1.2021.4.5.0 1.3.6.1.4.1.2021.4.3.0 1.3.6.1.4.1.2021.4.15.0
root@CentreonDebian11:~# snmpbulkget localhost -v 2c -c public -Cn0 -Cr1 1.3.6.1.4.1.2021.4.6.0 1.3.6.1.4.1.2021.4.4.0 1.3.6.1.4.1.2021.4.14.0 1.3.6.1.4.1.2021.4.13.0 1.3.6.1.4.1.2021.4.11.0 1.3.6.1.4.1.2021.4.5.0 1.3.6.1.4.1.2021.4.3.0 1.3.6.1.4.1.2021.4.15.0
iso.3.6.1.4.1.2021.4.11.0 = INTEGER: 21789288
iso.3.6.1.4.1.2021.4.5.0 = INTEGER: 20319992
iso.3.6.1.4.1.2021.4.15.0 = INTEGER: 292104
iso.3.6.1.4.1.2021.4.14.0 = INTEGER: 34324
iso.3.6.1.4.1.2021.4.12.0 = INTEGER: 16000
iso.3.6.1.4.1.2021.4.6.0 = INTEGER: 19421804
iso.3.6.1.4.1.2021.4.4.0 = INTEGER: 2367484
iso.3.6.1.4.1.2021.4.18.0 = Counter64: 2367484
root@CentreonDebian11:~# /usr/lib/nagios/plugins/centreon_plugins.pl --plugin=os::linux::snmp::plugin --mode=memory --hostname=localhost --snmp-version=2c --snmp-port=161 --snmp-community=public --snmp-timeout=1
OK: Ram Total: 19.38 GB Used (-buffers/cache): 558.36 MB (2.81%) Free: 18.83 GB (97.19%), Buffer: 33.52 MB, Cached: 285.26 MB, Shared: 5.71 MB | 'used'=585482240B;;;0;20807671808 'free'=20222189568B;;;0;20807671808 'used_prct'=2.81%;;;0;100 'buffer'=35147776B;;;0; 'cached'=299114496B;;;0; 'shared'=5984256B;;;0;
root@CentreonDebian11:~#

View File

@ -0,0 +1,22 @@
use std::str::FromStr;
grammar;
pub Sum: f32 = {
<s:Sum> "+" <p:Product> => s + p,
<s:Sum> "-" <p:Product> => s - p,
<p:Product> => p,
};
pub Product: f32 = {
<p:Product> "*" <t:Term> => p * t,
<p:Product> "/" <t:Term> => p / t,
<t:Term> => t,
};
pub Term: f32 = {
<n:Num> => n,
"(" <t:Sum> ")" => t,
};
Num: f32 = <s:r"-?[0-9.]+"> => f32::from_str(s).unwrap();

View File

@ -327,7 +327,14 @@ pub fn r_snmp_bulk_walk(target: &str, _version: &str, community: &str, oid: &str
if completed { if completed {
break; break;
} }
oid_tab = retval.variables.last().unwrap().name.split('.').map(|x| x.parse::<u32>().unwrap()).collect::<Vec<u32>>(); oid_tab = retval
.variables
.last()
.unwrap()
.name
.split('.')
.map(|x| x.parse::<u32>().unwrap())
.collect::<Vec<u32>>();
} }
retval retval
} }
@ -396,43 +403,43 @@ fn build_response(decoded: Message<Pdus>, walk: bool) -> (SnmpResult, bool) {
(retval, completed) (retval, completed)
} }
mod tests { //mod tests {
use super::*; // use super::*;
//
#[test] // #[test]
fn test_snmp_get() { // fn test_snmp_get() {
let result = r_snmp_get("127.0.0.1:161", "1.3.6.1.2.1.1.1.0", "public"); // let result = r_snmp_get("127.0.0.1:161", "1.3.6.1.2.1.1.1.0", "public");
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-31-amd64 #1 SMP PREEMPT_DYNAMIC Debian 6.1.128-1 (2025-02-07) 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);
} // }
//
#[test] // #[test]
fn test_snmp_walk() { // fn test_snmp_walk() {
let result = r_snmp_walk("127.0.0.1:161", "1.3.6.1.2.1.25.3.3.1.2"); // let result = r_snmp_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(); // let re = Regex::new(r"[0-9]+").unwrap();
assert!(result.variables.len() > 0); // assert!(result.variables.len() > 0);
for v in result.variables.iter() { // for v in result.variables.iter() {
let name = &v.name; // let name = &v.name;
assert!(name.starts_with("1.3.6.1.2.1.25.3.3.1.2")); // assert!(name.starts_with("1.3.6.1.2.1.25.3.3.1.2"));
assert!(re.is_match(&v.value)); // assert!(re.is_match(&v.value));
} // }
} // }
//
#[test] // #[test]
fn test_snmp_bulk_walk() { // fn test_snmp_bulk_walk() {
let result = r_snmp_bulk_walk("127.0.0.1:161", "2c", "public", "1.3.6.1.2.1.25.3.3.1.2"); // let result = r_snmp_bulk_walk("127.0.0.1:161", "2c", "public", "1.3.6.1.2.1.25.3.3.1.2");
let re = Regex::new(r"[0-9]+").unwrap(); // let re = Regex::new(r"[0-9]+").unwrap();
assert!(result.variables.len() > 0); // assert!(result.variables.len() > 0);
for v in result.variables.iter() { // for v in result.variables.iter() {
println!("{:?}", v); // println!("{:?}", v);
let name = &v.name; // let name = &v.name;
assert!(name.starts_with("1.3.6.1.2.1.25.3.3.1.2")); // assert!(name.starts_with("1.3.6.1.2.1.25.3.3.1.2"));
assert!(re.is_match(&v.value)); // assert!(re.is_match(&v.value));
} // }
} // }
} //}

View File

@ -1,4 +1,5 @@
extern crate clap; extern crate clap;
extern crate lalrpop_util;
extern crate log; extern crate log;
extern crate rasn; extern crate rasn;
extern crate rasn_smi; extern crate rasn_smi;
@ -12,10 +13,13 @@ mod lib;
use clap::Parser; use clap::Parser;
use generic::{Command, CommandExt}; use generic::{Command, CommandExt};
use lalrpop_util::lalrpop_mod;
use lib::r_snmp_get; use lib::r_snmp_get;
use serde_json::Result; use serde_json::Result;
use std::fs; use std::fs;
lalrpop_mod!(grammar);
#[derive(Parser, Debug)] #[derive(Parser, Debug)]
#[command(version, about)] #[command(version, about)]
struct Cli { struct Cli {
@ -55,7 +59,7 @@ fn json_to_command(file_name: &str) -> Result<Command> {
Err(err) => { Err(err) => {
println!("erreur: {}", err); println!("erreur: {}", err);
std::process::exit(3); std::process::exit(3);
}, }
}; };
let module: Result<Command> = serde_json::from_str(&contents.as_str()); let module: Result<Command> = serde_json::from_str(&contents.as_str());
@ -77,3 +81,59 @@ fn main() {
println!("{}", result.output); println!("{}", result.output);
std::process::exit(result.status as i32); std::process::exit(result.status as i32);
} }
mod Test {
use super::*;
#[test]
fn term() {
assert!(grammar::TermParser::new().parse("132").is_ok());
assert!(grammar::TermParser::new().parse("((132))").is_ok());
assert!(grammar::TermParser::new().parse("((132)))").is_err());
}
#[test]
fn sum() {
let res = grammar::SumParser::new().parse("1 + 2");
assert!(res.is_ok());
assert!(res.unwrap() == 3_f32);
let res = grammar::SumParser::new().parse("1 + 2 + 3");
assert!(res.is_ok());
assert!(res.unwrap() == 6_f32);
let res = grammar::SumParser::new().parse("1 - 2 + 3");
assert!(res.is_ok());
assert!(res.unwrap() == 2_f32);
let res = grammar::SumParser::new().parse("1 + 2 - 3");
assert!(res.is_ok());
assert!(res.unwrap() == 0_f32);
}
#[test]
fn product() {
let res = grammar::ProductParser::new().parse("2 * 3");
assert!(res.is_ok());
assert!(res.unwrap() == 6_f32);
let res = grammar::ProductParser::new().parse("2 * 3 * 4");
assert!(res.is_ok());
assert!(res.unwrap() == 24_f32);
let res = grammar::ProductParser::new().parse("2 * 3 / 2");
assert!(res.is_ok());
assert!(res.unwrap() == 3_f32);
// let res = grammar::ProductParser::new().parse("2 / 0");
// assert!(res.is_err());
}
#[test]
fn sum_product() {
let res = grammar::SumParser::new().parse("1 + 2 * 3");
assert!(res.is_ok());
assert!(res.unwrap() == 7_f32);
let res = grammar::SumParser::new().parse("1 + (3 + 2 * 3) / 3");
assert!(res.is_ok());
assert!(res.unwrap() == 4_f32);
}
}