restructure code from lib to mod
This commit is contained in:
296
src/rsnmplib/snmp.rs
Normal file
296
src/rsnmplib/snmp.rs
Normal file
@@ -0,0 +1,296 @@
|
||||
use log::{debug, error};
|
||||
use serde::{Deserialize, Serialize};
|
||||
use std::collections::BTreeMap;
|
||||
use std::error::Error;
|
||||
use std::fmt;
|
||||
use std::io;
|
||||
use std::num::ParseIntError;
|
||||
use std::str::FromStr;
|
||||
|
||||
#[derive(Debug, PartialEq)]
|
||||
pub enum OidError {
|
||||
PrefixMissmatch,
|
||||
PrefixTooLong,
|
||||
}
|
||||
|
||||
#[derive(Deserialize, Serialize, Debug, PartialEq, Eq, PartialOrd, Ord, Clone)]
|
||||
pub struct Oid(Vec<u32>);
|
||||
|
||||
impl FromStr for Oid {
|
||||
type Err = ParseIntError;
|
||||
|
||||
fn from_str(s: &str) -> Result<Self, Self::Err> {
|
||||
let r = s
|
||||
.split('.')
|
||||
.filter(|&s| !s.is_empty())
|
||||
.map(|s| s.parse::<u32>())
|
||||
.collect();
|
||||
match r {
|
||||
Ok(v) => Ok(Oid(v)),
|
||||
Err(e) => Err(e),
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
impl fmt::Display for Oid {
|
||||
fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
|
||||
write!(
|
||||
f,
|
||||
".{}",
|
||||
self.0.iter().map(|&n| n.to_string()).collect::<Vec<String>>().join(".")
|
||||
)
|
||||
}
|
||||
}
|
||||
|
||||
impl Oid {
|
||||
pub fn add_prefix(&self, o: &Oid) -> Oid {
|
||||
let mut x = o.clone();
|
||||
x.0.extend(&self.0);
|
||||
x
|
||||
}
|
||||
|
||||
/* pub fn add_suffix(&self, o: &Oid) -> Oid {
|
||||
let mut x = self.clone();
|
||||
x.0.extend(o.clone().0);
|
||||
x
|
||||
} */
|
||||
|
||||
pub fn add_suffix_int(&self, o: u32) -> Oid {
|
||||
let mut x = self.clone();
|
||||
x.0.push(o);
|
||||
x
|
||||
}
|
||||
|
||||
pub fn strip_prefix(&self, o: &Oid) -> Result<Oid, OidError> {
|
||||
let pl = o.0.len();
|
||||
if self.0.len() > pl {
|
||||
let mut x = self.0.clone();
|
||||
let y = x.split_off(pl);
|
||||
if x == o.0 {
|
||||
return Ok(Oid(y));
|
||||
} else {
|
||||
return Err(OidError::PrefixMissmatch);
|
||||
}
|
||||
}
|
||||
Err(OidError::PrefixTooLong)
|
||||
}
|
||||
}
|
||||
|
||||
#[derive(Deserialize, Serialize, Debug)]
|
||||
pub enum SnmpData {
|
||||
String(String),
|
||||
Gauge(u32),
|
||||
Integer(u32),
|
||||
Counter32(u32),
|
||||
Counter64(u64),
|
||||
// More data types ToDo ...
|
||||
//INTEGER
|
||||
//OCTET
|
||||
//IPADDRESS
|
||||
//TIMETICKS
|
||||
//OBJECTID
|
||||
// coding examples see https://github.com/nagius/snmp_passpersist/blob/master/snmp_passpersist.py
|
||||
}
|
||||
|
||||
impl fmt::Display for SnmpData {
|
||||
fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
|
||||
match self {
|
||||
Self::String(s) => write!(f, "string\n{}", s),
|
||||
Self::Gauge(i) => write!(f, "gauge\n{}", i),
|
||||
Self::Integer(i) => write!(f, "integer\n{}", i),
|
||||
Self::Counter32(i) => write!(f, "counter32\n{}", i),
|
||||
Self::Counter64(i) => write!(f, "counter64\n{}", i),
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
#[derive(Deserialize, Serialize, Debug)]
|
||||
pub struct OidData {
|
||||
pub(crate) base: Oid,
|
||||
pub(crate) data: BTreeMap<Oid, SnmpData>,
|
||||
}
|
||||
|
||||
impl OidData {
|
||||
/*
|
||||
pub fn new(base_oid: &str) -> Self {
|
||||
Self {
|
||||
base: base_oid.parse().expect("Unable to parse Oid"),
|
||||
data: BTreeMap::new(),
|
||||
}
|
||||
} */
|
||||
|
||||
pub fn new_oid(base_oid: &Oid) -> Self {
|
||||
Self {
|
||||
base: base_oid.clone(),
|
||||
data: BTreeMap::new(),
|
||||
}
|
||||
}
|
||||
|
||||
pub fn data_lookup(&self, key: &Oid) -> Option<&SnmpData> {
|
||||
self.data.get(key)
|
||||
}
|
||||
|
||||
pub fn data_lookup_next(&self, key: &Oid) -> Option<(&Oid, &SnmpData)> {
|
||||
for (k, v) in self.data.iter() {
|
||||
if k > key {
|
||||
return Some((k, v));
|
||||
};
|
||||
}
|
||||
None
|
||||
}
|
||||
}
|
||||
|
||||
#[derive(Deserialize, Serialize, Debug)]
|
||||
pub enum SnmpCommands {
|
||||
Ping,
|
||||
Get(Oid),
|
||||
GetNext(Oid),
|
||||
Set(Oid, String),
|
||||
Quit,
|
||||
}
|
||||
|
||||
impl fmt::Display for SnmpCommands {
|
||||
fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> fmt::Result {
|
||||
match self {
|
||||
Self::Get(s) => write!(f, "GET => {}", s),
|
||||
Self::GetNext(s) => write!(f, "GETNEXT => {}", s),
|
||||
Self::Ping => write!(f, "PING"),
|
||||
Self::Set(o, s) => write!(f, "SET => {} => {}", o, s),
|
||||
Self::Quit => write!(f, "QUIT"),
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
impl SnmpCommands {
|
||||
pub fn parse_command() -> Result<SnmpCommands, Box<dyn Error>> {
|
||||
let mut cmd = String::new();
|
||||
io::stdin().read_line(&mut cmd).expect("Failed to read line");
|
||||
cmd = cmd.to_lowercase().trim().to_string();
|
||||
let pc: SnmpCommands = match &cmd as &str {
|
||||
"quit" => SnmpCommands::Quit,
|
||||
"ping" => SnmpCommands::Ping,
|
||||
"set" => {
|
||||
let mut setoid = String::new();
|
||||
let mut setdata = String::new();
|
||||
// we need to read 2 lines of addional input after SET command, first OID, second
|
||||
io::stdin().read_line(&mut setoid).expect("Failed to read line");
|
||||
io::stdin().read_line(&mut setdata).expect("Failed to read line");
|
||||
let oid: Oid = match setoid.trim().to_string().parse() {
|
||||
Ok(v) => v,
|
||||
Err(_e) => {
|
||||
let mystr = format!("unable to parse {} into Oid", setoid.trim());
|
||||
error!("{}", mystr);
|
||||
return Err(mystr.into());
|
||||
}
|
||||
};
|
||||
SnmpCommands::Set(oid, format!("DATA: {}", setdata.trim()))
|
||||
}
|
||||
"get" => {
|
||||
let mut getoid = String::new();
|
||||
// we need to read 1 lines of addional input after GET command, OID
|
||||
io::stdin().read_line(&mut getoid).expect("Failed to read line");
|
||||
let oid: Oid = match getoid.trim().to_string().parse() {
|
||||
Ok(v) => v,
|
||||
Err(_e) => {
|
||||
let mystr = format!("unable to parse {} into Oid", getoid.trim());
|
||||
error!("{}", mystr);
|
||||
return Err(mystr.into());
|
||||
}
|
||||
};
|
||||
SnmpCommands::Get(oid)
|
||||
}
|
||||
"getnext" => {
|
||||
let mut getoid = String::new();
|
||||
// we need to read 1 lines of addional input after GETNEXT command, OID
|
||||
io::stdin().read_line(&mut getoid).expect("Failed to read line");
|
||||
let oid: Oid = match getoid.trim().to_string().parse() {
|
||||
Ok(v) => v,
|
||||
Err(_e) => {
|
||||
let mystr = format!("unable to parse {} into Oid", getoid.trim());
|
||||
error!("{}", mystr);
|
||||
return Err(mystr.into());
|
||||
}
|
||||
};
|
||||
SnmpCommands::GetNext(oid)
|
||||
}
|
||||
_ => {
|
||||
let mystr = format!("unable to parse {} into SnmpCommand", cmd);
|
||||
error!("{}", mystr);
|
||||
return Err(mystr.into());
|
||||
}
|
||||
};
|
||||
debug!("parsed snmp command: {}", pc);
|
||||
Ok(pc)
|
||||
}
|
||||
}
|
||||
|
||||
#[cfg(test)]
|
||||
mod tests {
|
||||
use super::*;
|
||||
|
||||
#[test]
|
||||
fn oid_sort1() {
|
||||
let oid1: Oid = "1.2.3".to_string().parse().unwrap();
|
||||
let oid2: Oid = "1.2.3.1".to_string().parse().unwrap();
|
||||
assert!(oid1 < oid2);
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn oid_sort2() {
|
||||
let oid1: Oid = "1.2.3.1".to_string().parse().unwrap();
|
||||
let oid2: Oid = "1.2.4".to_string().parse().unwrap();
|
||||
assert!(oid1 < oid2);
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn oid_sort3() {
|
||||
let oid1: Oid = "1.2.3".to_string().parse().unwrap();
|
||||
let oid2: Oid = "1.2.4".to_string().parse().unwrap();
|
||||
assert!(oid1 < oid2);
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn oid_sort4() {
|
||||
let oid1: Oid = "1.2.3".to_string().parse().unwrap();
|
||||
let oid2: Oid = "1.3.1".to_string().parse().unwrap();
|
||||
assert!(oid1 < oid2);
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn oid_add_prefix1() {
|
||||
let oid1: Oid = "1.2.3".to_string().parse().unwrap();
|
||||
let oid2: Oid = "4.5".to_string().parse().unwrap();
|
||||
let oid3 = oid2.add_prefix(&oid1);
|
||||
assert_eq!(oid3, Oid(vec![1, 2, 3, 4, 5]));
|
||||
}
|
||||
#[test]
|
||||
fn oid_stip_prefix1() {
|
||||
let oid1: Oid = "1.2.3.4.5".to_string().parse().unwrap();
|
||||
let oid2: Oid = "1.2".to_string().parse().unwrap();
|
||||
let oid3 = oid1.strip_prefix(&oid2).unwrap();
|
||||
assert_eq!(oid3, Oid(vec![3, 4, 5]));
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn oid_stip_prefix_missmatch() {
|
||||
let oid1: Oid = "1.2.3.4.5".to_string().parse().unwrap();
|
||||
let oid2: Oid = "1.3".to_string().parse().unwrap();
|
||||
let e1 = oid1.strip_prefix(&oid2).unwrap_err();
|
||||
assert_eq!(e1, OidError::PrefixMissmatch)
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn oid_stip_prefix_too_long() {
|
||||
let oid1: Oid = "1.2.3".to_string().parse().unwrap();
|
||||
let oid2: Oid = "1.2.3".to_string().parse().unwrap();
|
||||
let e1 = oid1.strip_prefix(&oid2).unwrap_err();
|
||||
assert_eq!(e1, OidError::PrefixTooLong)
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn oid_diplay_trait() {
|
||||
let oid1: Oid = "1.2.3".to_string().parse().unwrap();
|
||||
let s = format!("{}", oid1);
|
||||
assert_eq!(s, ".1.2.3".to_string());
|
||||
}
|
||||
}
|
||||
Reference in New Issue
Block a user