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 a0b5c87277
commit 7c2d9ab973
6 changed files with 157 additions and 42 deletions

View File

@ -9,6 +9,9 @@ crate-type = ["cdylib"]
name = "generic-snmp"
path = "src/main.rs"
[build-dependencies]
lalrpop = "0.22.1"
[dependencies]
regex = "1.11.1"
rasn = "0.24.0"
@ -18,3 +21,5 @@ log = "0.4.25"
clap = { version = "4.5.29", features = ["derive"] }
serde = { version = "1.0.217", features = ["derive"] }
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 {
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
}
@ -396,43 +403,43 @@ fn build_response(decoded: Message<Pdus>, walk: bool) -> (SnmpResult, bool) {
(retval, completed)
}
mod tests {
use super::*;
#[test]
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 expected = SnmpResult {
variables: vec![SnmpVariable::new(
"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())],
};
assert_eq!(result, expected);
}
#[test]
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 re = Regex::new(r"[0-9]+").unwrap();
assert!(result.variables.len() > 0);
for v in result.variables.iter() {
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));
}
}
#[test]
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 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));
}
}
}
//mod tests {
// use super::*;
//
// #[test]
// 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 expected = SnmpResult {
// variables: vec![SnmpVariable::new(
// "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())],
// };
// assert_eq!(result, expected);
// }
//
// #[test]
// 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 re = Regex::new(r"[0-9]+").unwrap();
// assert!(result.variables.len() > 0);
// for v in result.variables.iter() {
// 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));
// }
// }
//
// #[test]
// 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 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));
// }
// }
//}

View File

@ -1,4 +1,5 @@
extern crate clap;
extern crate lalrpop_util;
extern crate log;
extern crate rasn;
extern crate rasn_smi;
@ -12,10 +13,13 @@ mod lib;
use clap::Parser;
use generic::{Command, CommandExt};
use lalrpop_util::lalrpop_mod;
use lib::r_snmp_get;
use serde_json::Result;
use std::fs;
lalrpop_mod!(grammar);
#[derive(Parser, Debug)]
#[command(version, about)]
struct Cli {
@ -55,7 +59,7 @@ fn json_to_command(file_name: &str) -> Result<Command> {
Err(err) => {
println!("erreur: {}", err);
std::process::exit(3);
},
}
};
let module: Result<Command> = serde_json::from_str(&contents.as_str());
@ -77,3 +81,59 @@ fn main() {
println!("{}", result.output);
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);
}
}