mirror of
https://github.com/centreon/centreon-plugins.git
synced 2025-07-29 16:45:04 +02:00
enh(generic-snmp): first version of the Rust generic-snmp plugin
This commit is contained in:
parent
75873668bf
commit
5f797f2ca5
2
experimental/.gitignore
vendored
Normal file
2
experimental/.gitignore
vendored
Normal file
@ -0,0 +1,2 @@
|
|||||||
|
Cargo.lock
|
||||||
|
target/*
|
20
experimental/Cargo.toml
Normal file
20
experimental/Cargo.toml
Normal file
@ -0,0 +1,20 @@
|
|||||||
|
[package]
|
||||||
|
name = "conn"
|
||||||
|
version = "1.1.0"
|
||||||
|
|
||||||
|
[lib]
|
||||||
|
crate-type = ["cdylib"]
|
||||||
|
|
||||||
|
[[bin]]
|
||||||
|
name = "generic-snmp"
|
||||||
|
path = "src/main.rs"
|
||||||
|
|
||||||
|
[dependencies]
|
||||||
|
regex = "*"
|
||||||
|
rasn = "*"
|
||||||
|
rasn-snmp = "*"
|
||||||
|
rasn-smi = "*"
|
||||||
|
log = "*"
|
||||||
|
clap = { version = "4.5.26", features = ["derive"] }
|
||||||
|
serde = { version = "1.0.104", features = ["derive"] }
|
||||||
|
serde_json = "1.0.44"
|
34
experimental/perl/with-ffi.pl
Executable file
34
experimental/perl/with-ffi.pl
Executable file
@ -0,0 +1,34 @@
|
|||||||
|
#!/usr/bin/perl
|
||||||
|
|
||||||
|
use strict;
|
||||||
|
use warnings;
|
||||||
|
use lib '/home/david/perl5/lib/perl5';
|
||||||
|
use FFI::Platypus 2.00;
|
||||||
|
my $ffi = FFI::Platypus->new(api => 2, lang => => 'Rust');
|
||||||
|
|
||||||
|
$ffi->lib(
|
||||||
|
'../target/debug/libconn.so');
|
||||||
|
|
||||||
|
### Types ###
|
||||||
|
$ffi->type('object(SnmpResult)' => 'snmpresult_t');
|
||||||
|
$ffi->type('object(SnmpVariable)' => 'snmpvariable_t');
|
||||||
|
|
||||||
|
### Global functions ###
|
||||||
|
$ffi->attach(snmp_get => ['string', 'string', 'string'] => 'snmpresult_t');
|
||||||
|
$ffi->attach(snmp_walk => ['string', 'string'] => 'snmpresult_t');
|
||||||
|
|
||||||
|
$ffi->attach(snmpresult_variables_count => ['snmpresult_t'] => 'usize');
|
||||||
|
$ffi->attach(snmpresult_get_variable => ['snmpresult_t', 'usize'] => 'snmpvariable_t');
|
||||||
|
$ffi->attach( snmpresult_DESTROY => [ 'snmpresult_t' ] );
|
||||||
|
|
||||||
|
$ffi->attach(snmpvariable_get_name => ['snmpvariable_t'] => 'string');
|
||||||
|
$ffi->attach(snmpvariable_get_value => ['snmpvariable_t'] => 'string');
|
||||||
|
$ffi->attach( snmpvariable_DESTROY => [ 'snmpvariable_t' ] );
|
||||||
|
|
||||||
|
### Main program ###
|
||||||
|
|
||||||
|
my $result = snmp_walk('127.0.0.1:161', '1.3.6.1.2.1.25.3.3.1.2');
|
||||||
|
for (my $i = 0; $i < snmpresult_variables_count($result); $i++) {
|
||||||
|
my $variable = snmpresult_get_variable($result, $i);
|
||||||
|
print snmpvariable_get_name($variable) . " => " . snmpvariable_get_value($variable) . "\n";
|
||||||
|
}
|
113
experimental/src/generic/mod.rs
Normal file
113
experimental/src/generic/mod.rs
Normal file
@ -0,0 +1,113 @@
|
|||||||
|
extern crate serde;
|
||||||
|
extern crate serde_json;
|
||||||
|
|
||||||
|
use serde::Deserialize;
|
||||||
|
use std::collections::{BTreeMap, HashMap};
|
||||||
|
use lib::{r_snmp_walk, SnmpResult};
|
||||||
|
|
||||||
|
#[derive(Deserialize, Debug, Clone, Copy)]
|
||||||
|
enum Operation {
|
||||||
|
None,
|
||||||
|
Average,
|
||||||
|
}
|
||||||
|
|
||||||
|
#[derive(Deserialize, Debug)]
|
||||||
|
enum QueryType {
|
||||||
|
Walk,
|
||||||
|
}
|
||||||
|
|
||||||
|
#[derive(Deserialize, Debug)]
|
||||||
|
struct EntryOperation {
|
||||||
|
name: String,
|
||||||
|
op: Operation,
|
||||||
|
}
|
||||||
|
|
||||||
|
#[derive(Deserialize, Debug)]
|
||||||
|
struct EntryQuery {
|
||||||
|
name: String,
|
||||||
|
oid: String,
|
||||||
|
query: QueryType,
|
||||||
|
}
|
||||||
|
|
||||||
|
#[derive(Deserialize, Debug)]
|
||||||
|
enum Entry {
|
||||||
|
Agregation(EntryOperation),
|
||||||
|
Query(EntryQuery),
|
||||||
|
}
|
||||||
|
|
||||||
|
#[derive(Deserialize, Debug)]
|
||||||
|
struct Leaf {
|
||||||
|
name: String,
|
||||||
|
output: String,
|
||||||
|
entries: Vec<Entry>,
|
||||||
|
}
|
||||||
|
|
||||||
|
#[derive(Deserialize, Debug)]
|
||||||
|
pub struct Command {
|
||||||
|
leaf: Leaf,
|
||||||
|
}
|
||||||
|
|
||||||
|
pub struct CmdResult {
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
impl Command {
|
||||||
|
pub fn execute(&self, target: &str) -> CmdResult {
|
||||||
|
let mut agregation = ("", Operation::None);
|
||||||
|
let mut res: Option<(&str, SnmpResult)> = None;
|
||||||
|
for entry in &self.leaf.entries {
|
||||||
|
match entry {
|
||||||
|
Entry::Agregation(op) => {
|
||||||
|
println!("Agregation: {:?}", op);
|
||||||
|
agregation = (&op.name, op.op);
|
||||||
|
},
|
||||||
|
Entry::Query(query) => {
|
||||||
|
match query.query {
|
||||||
|
QueryType::Walk => {
|
||||||
|
res = Some((&query.name, r_snmp_walk(target, &query.oid)));
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
match res {
|
||||||
|
Some(r) => {
|
||||||
|
let mut values: Vec<f32> = Vec::new();
|
||||||
|
let mut labels: Vec<String> = Vec::new();
|
||||||
|
let mut idx = 0;
|
||||||
|
r.1.variables.iter().for_each(|v| {
|
||||||
|
values.push(v.value.parse().unwrap());
|
||||||
|
let label = r.0.replace("{idx}", &idx.to_string());
|
||||||
|
labels.push(label);
|
||||||
|
idx += 1;
|
||||||
|
});
|
||||||
|
let count = values.len();
|
||||||
|
let ag = match agregation.1 {
|
||||||
|
Operation::Average => {
|
||||||
|
let sum: f32 = values.iter().sum();
|
||||||
|
Some((agregation.0, sum / values.len() as f32))
|
||||||
|
},
|
||||||
|
_ => None,
|
||||||
|
};
|
||||||
|
let metrics = self.build_metrics(&labels, &values, ag);
|
||||||
|
println!("Metrics: {:?}", metrics);
|
||||||
|
},
|
||||||
|
None => println!("No result"),
|
||||||
|
}
|
||||||
|
CmdResult {}
|
||||||
|
}
|
||||||
|
|
||||||
|
fn build_metrics(&self, labels: &Vec<String>, values: &Vec<f32>, ag: Option<(&str, f32)>) -> BTreeMap<String, f32> {
|
||||||
|
let mut metrics: BTreeMap<String, f32> = BTreeMap::new();
|
||||||
|
values.iter().enumerate().for_each(|(i, v)| {
|
||||||
|
metrics.insert(labels[i].clone(), *v);
|
||||||
|
});
|
||||||
|
match ag {
|
||||||
|
Some(a) => {
|
||||||
|
metrics.insert(a.0.to_string(), a.1);
|
||||||
|
},
|
||||||
|
None => (),
|
||||||
|
}
|
||||||
|
metrics
|
||||||
|
}
|
||||||
|
}
|
341
experimental/src/lib.rs
Normal file
341
experimental/src/lib.rs
Normal file
@ -0,0 +1,341 @@
|
|||||||
|
extern crate log;
|
||||||
|
extern crate rasn;
|
||||||
|
extern crate rasn_smi;
|
||||||
|
extern crate rasn_snmp;
|
||||||
|
extern crate regex;
|
||||||
|
|
||||||
|
use log::{info, trace, warn};
|
||||||
|
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::VarBind;
|
||||||
|
use rasn_snmp::v2::VarBindValue;
|
||||||
|
use rasn_snmp::v2c::Message;
|
||||||
|
use std::ffi::CStr;
|
||||||
|
use std::ffi::CString;
|
||||||
|
use std::net::UdpSocket;
|
||||||
|
use std::os::raw::{c_char, c_void};
|
||||||
|
|
||||||
|
#[derive(Debug, PartialEq)]
|
||||||
|
pub struct SnmpResult {
|
||||||
|
pub variables: Vec<SnmpVariable>,
|
||||||
|
}
|
||||||
|
|
||||||
|
type CSnmpVariable = c_void;
|
||||||
|
|
||||||
|
#[derive(Debug, PartialEq)]
|
||||||
|
pub struct SnmpVariable {
|
||||||
|
pub name: String,
|
||||||
|
pub value: String,
|
||||||
|
}
|
||||||
|
|
||||||
|
impl SnmpVariable {
|
||||||
|
fn new(name: String, value: String) -> SnmpVariable {
|
||||||
|
SnmpVariable { name, value }
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
type CSnmpResult = c_void;
|
||||||
|
|
||||||
|
impl SnmpResult {
|
||||||
|
fn new() -> SnmpResult {
|
||||||
|
SnmpResult {
|
||||||
|
variables: Vec::new(),
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
fn add_variable(&mut self, name: String, value: String) {
|
||||||
|
self.variables.push(SnmpVariable::new(name, value));
|
||||||
|
}
|
||||||
|
|
||||||
|
fn concat(&mut self, other: SnmpResult) {
|
||||||
|
self.variables.extend(other.variables);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
#[allow(non_snake_case)]
|
||||||
|
#[no_mangle]
|
||||||
|
pub extern "C" fn snmpresult_DESTROY(p: *mut CSnmpResult) {
|
||||||
|
unsafe { Box::from_raw(p as *mut SnmpResult) };
|
||||||
|
}
|
||||||
|
|
||||||
|
#[allow(non_snake_case)]
|
||||||
|
#[no_mangle]
|
||||||
|
pub extern "C" fn snmpresult_get_variable(p: *mut CSnmpResult, index: usize) -> *mut CSnmpVariable {
|
||||||
|
trace!("snmpresult_get_variable {}", index);
|
||||||
|
let p = p as *mut SnmpResult;
|
||||||
|
let p = unsafe { &mut *p };
|
||||||
|
if index >= p.variables.len() {
|
||||||
|
return Box::into_raw(Box::new(SnmpVariable::new("".to_string(), "".to_string())))
|
||||||
|
as *mut CSnmpVariable;
|
||||||
|
}
|
||||||
|
let v = &p.variables[index];
|
||||||
|
Box::into_raw(Box::new(SnmpVariable {
|
||||||
|
name: v.name.clone(),
|
||||||
|
value: v.value.clone(),
|
||||||
|
})) as *mut CSnmpVariable
|
||||||
|
}
|
||||||
|
|
||||||
|
#[allow(non_snake_case)]
|
||||||
|
#[no_mangle]
|
||||||
|
pub extern "C" fn snmpresult_variables_count(p: *mut CSnmpResult) -> usize {
|
||||||
|
let p = p as *mut SnmpResult;
|
||||||
|
let p = unsafe { &mut *p };
|
||||||
|
p.variables.len()
|
||||||
|
}
|
||||||
|
|
||||||
|
#[allow(non_snake_case)]
|
||||||
|
#[no_mangle]
|
||||||
|
pub extern "C" fn snmpvariable_DESTROY(p: *mut CSnmpVariable) {
|
||||||
|
unsafe { Box::from_raw(p as *mut SnmpVariable) };
|
||||||
|
}
|
||||||
|
|
||||||
|
#[allow(non_snake_case)]
|
||||||
|
#[no_mangle]
|
||||||
|
pub extern "C" fn snmpvariable_get_name(p: *mut CSnmpVariable) -> *mut c_char {
|
||||||
|
let p = p as *mut SnmpVariable;
|
||||||
|
let p = unsafe { &mut *p };
|
||||||
|
let c = CString::new(p.name.clone()).unwrap();
|
||||||
|
c.into_raw()
|
||||||
|
}
|
||||||
|
|
||||||
|
#[allow(non_snake_case)]
|
||||||
|
#[no_mangle]
|
||||||
|
pub extern "C" fn snmpvariable_get_value(p: *mut CSnmpVariable) -> *mut c_char {
|
||||||
|
let p = p as *mut SnmpVariable;
|
||||||
|
let p = unsafe { &mut *p };
|
||||||
|
let c = CString::new(p.value.clone()).unwrap();
|
||||||
|
c.into_raw()
|
||||||
|
}
|
||||||
|
|
||||||
|
#[no_mangle]
|
||||||
|
pub extern "C" fn snmp_get(target: *const c_char, oid: *const c_char) -> *mut CSnmpResult {
|
||||||
|
if target.is_null() {
|
||||||
|
return Box::into_raw(Box::new(SnmpResult::new())) as *mut CSnmpResult;
|
||||||
|
}
|
||||||
|
let target = unsafe { CStr::from_ptr(target) };
|
||||||
|
let target = match target.to_str() {
|
||||||
|
Ok(s) => s,
|
||||||
|
Err(_) => "",
|
||||||
|
};
|
||||||
|
|
||||||
|
if oid.is_null() {
|
||||||
|
return Box::into_raw(Box::new(SnmpResult::new())) as *mut CSnmpResult;
|
||||||
|
}
|
||||||
|
let oid = unsafe { CStr::from_ptr(oid) };
|
||||||
|
let oid = match oid.to_str() {
|
||||||
|
Ok(s) => s,
|
||||||
|
Err(_) => "",
|
||||||
|
};
|
||||||
|
|
||||||
|
Box::into_raw(Box::new(r_snmp_get(target, oid, "public"))) as *mut CSnmpResult
|
||||||
|
}
|
||||||
|
|
||||||
|
pub fn r_snmp_get(target: &str, oid: &str, community: &str) -> SnmpResult {
|
||||||
|
let oid_tab = oid
|
||||||
|
.split('.')
|
||||||
|
.map(|x| x.parse::<u32>().unwrap())
|
||||||
|
.collect::<Vec<u32>>();
|
||||||
|
|
||||||
|
let request_id = 1;
|
||||||
|
|
||||||
|
let variable_bindings = vec![VarBind {
|
||||||
|
name: ObjectIdentifier::new_unchecked(oid_tab.into()),
|
||||||
|
value: VarBindValue::Unspecified,
|
||||||
|
}];
|
||||||
|
|
||||||
|
let pdu = Pdu {
|
||||||
|
request_id,
|
||||||
|
error_status: 0,
|
||||||
|
error_index: 0,
|
||||||
|
variable_bindings,
|
||||||
|
};
|
||||||
|
|
||||||
|
let get_request = GetRequest(pdu);
|
||||||
|
|
||||||
|
let message: rasn_snmp::v2c::Message<GetRequest> = Message {
|
||||||
|
version: 1.into(),
|
||||||
|
community: community.to_string().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 = rasn::der::encode(&message).unwrap();
|
||||||
|
let res = socket.send(&encoded).unwrap();
|
||||||
|
assert!(res == encoded.len());
|
||||||
|
|
||||||
|
let mut buf = [0; 1024];
|
||||||
|
let resp = 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();
|
||||||
|
build_response(decoded)
|
||||||
|
}
|
||||||
|
|
||||||
|
#[no_mangle]
|
||||||
|
pub extern "C" fn snmp_walk(target: *const c_char, oid: *const c_char) -> *mut CSnmpResult {
|
||||||
|
if target.is_null() {
|
||||||
|
return Box::into_raw(Box::new(SnmpResult::new())) as *mut CSnmpResult;
|
||||||
|
}
|
||||||
|
let target = unsafe { CStr::from_ptr(target) };
|
||||||
|
let target = match target.to_str() {
|
||||||
|
Ok(s) => s,
|
||||||
|
Err(_) => "",
|
||||||
|
};
|
||||||
|
|
||||||
|
if oid.is_null() {
|
||||||
|
return Box::into_raw(Box::new(SnmpResult::new())) as *mut CSnmpResult;
|
||||||
|
}
|
||||||
|
let oid = unsafe { CStr::from_ptr(oid) };
|
||||||
|
let oid = match oid.to_str() {
|
||||||
|
Ok(s) => s,
|
||||||
|
Err(_) => "",
|
||||||
|
};
|
||||||
|
Box::into_raw(Box::new(r_snmp_walk(target, oid))) as *mut CSnmpResult
|
||||||
|
}
|
||||||
|
|
||||||
|
pub fn r_snmp_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 create_next_request = |id: i32, oid: &[u32]| -> Message<GetNextRequest> {
|
||||||
|
let variable_bindings = vec![VarBind {
|
||||||
|
name: ObjectIdentifier::new_unchecked(oid.to_vec().into()),
|
||||||
|
value: VarBindValue::Unspecified,
|
||||||
|
}];
|
||||||
|
|
||||||
|
let pdu = Pdu {
|
||||||
|
request_id: id,
|
||||||
|
error_status: 0,
|
||||||
|
error_index: 0,
|
||||||
|
variable_bindings,
|
||||||
|
};
|
||||||
|
let get_request: GetNextRequest = GetNextRequest(pdu);
|
||||||
|
|
||||||
|
Message {
|
||||||
|
version: 1.into(),
|
||||||
|
community: community.into(),
|
||||||
|
data: get_request.into(),
|
||||||
|
}
|
||||||
|
};
|
||||||
|
|
||||||
|
let mut message = create_next_request(request_id, &oid_tab);
|
||||||
|
|
||||||
|
loop {
|
||||||
|
// 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;
|
||||||
|
if resp_oid[0..n] != oid_tab[0..n] {
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
message = create_next_request(request_id, &resp_oid);
|
||||||
|
}
|
||||||
|
retval.concat(build_response(decoded));
|
||||||
|
request_id += 1;
|
||||||
|
}
|
||||||
|
retval
|
||||||
|
}
|
||||||
|
|
||||||
|
fn build_response(decoded: Message<Pdus>) -> SnmpResult {
|
||||||
|
let mut retval = SnmpResult::new();
|
||||||
|
|
||||||
|
if let Pdus::Response(resp) = &decoded.data {
|
||||||
|
let vars = &resp.0.variable_bindings;
|
||||||
|
for var in vars {
|
||||||
|
let name = var.name.to_string();
|
||||||
|
match &var.value {
|
||||||
|
VarBindValue::Unspecified => {
|
||||||
|
warn!("Unspecified");
|
||||||
|
}
|
||||||
|
VarBindValue::NoSuchObject => {
|
||||||
|
warn!("NoSuchObject");
|
||||||
|
}
|
||||||
|
VarBindValue::NoSuchInstance => {
|
||||||
|
warn!("NoSuchInstance");
|
||||||
|
}
|
||||||
|
VarBindValue::EndOfMibView => {
|
||||||
|
warn!("EndOfMibView");
|
||||||
|
}
|
||||||
|
VarBindValue::Value(value) => {
|
||||||
|
warn!("Value {:?}", &value);
|
||||||
|
match value {
|
||||||
|
rasn_smi::v2::ObjectSyntax::Simple(value) => {
|
||||||
|
info!("Simple {:?}", value);
|
||||||
|
match value {
|
||||||
|
rasn_smi::v2::SimpleSyntax::Integer(value) => {
|
||||||
|
retval.add_variable(name, value.to_string());
|
||||||
|
}
|
||||||
|
rasn_smi::v2::SimpleSyntax::String(value) => {
|
||||||
|
// We transform the value into a rust String
|
||||||
|
retval.add_variable(
|
||||||
|
name,
|
||||||
|
String::from_utf8(value.to_vec()).unwrap(),
|
||||||
|
);
|
||||||
|
}
|
||||||
|
_ => {
|
||||||
|
retval.add_variable(name, String::from("Other"));
|
||||||
|
}
|
||||||
|
};
|
||||||
|
}
|
||||||
|
rasn_smi::v2::ObjectSyntax::ApplicationWide(value) => {
|
||||||
|
info!("Application {:?}", value);
|
||||||
|
}
|
||||||
|
};
|
||||||
|
}
|
||||||
|
};
|
||||||
|
}
|
||||||
|
}
|
||||||
|
retval
|
||||||
|
}
|
||||||
|
|
||||||
|
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-28-amd64 #1 SMP PREEMPT_DYNAMIC Debian 6.1.119-1 (2024-11-22) 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));
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
60
experimental/src/main.rs
Normal file
60
experimental/src/main.rs
Normal file
@ -0,0 +1,60 @@
|
|||||||
|
extern crate clap;
|
||||||
|
extern crate log;
|
||||||
|
extern crate rasn;
|
||||||
|
extern crate rasn_smi;
|
||||||
|
extern crate rasn_snmp;
|
||||||
|
extern crate regex;
|
||||||
|
extern crate serde;
|
||||||
|
extern crate serde_json;
|
||||||
|
|
||||||
|
mod lib;
|
||||||
|
mod generic;
|
||||||
|
|
||||||
|
use clap::Parser;
|
||||||
|
use lib::r_snmp_get;
|
||||||
|
use serde_json::Result;
|
||||||
|
use std::fs;
|
||||||
|
use generic::{Command};
|
||||||
|
|
||||||
|
#[derive(Parser, Debug)]
|
||||||
|
#[command(version, about)]
|
||||||
|
struct Cli {
|
||||||
|
/// Hostname to operate on
|
||||||
|
#[arg(long, short='H')]
|
||||||
|
hostname: String,
|
||||||
|
|
||||||
|
#[arg(long, short, default_value_t = 161)]
|
||||||
|
port: u16,
|
||||||
|
|
||||||
|
#[arg(long, short='v')]
|
||||||
|
snmp_version: String,
|
||||||
|
|
||||||
|
#[arg(long, short)]
|
||||||
|
community: String,
|
||||||
|
|
||||||
|
#[arg(long, short)]
|
||||||
|
json_conf: String,
|
||||||
|
}
|
||||||
|
|
||||||
|
fn json_to_command(file_name: &str) -> Result<Command> {
|
||||||
|
|
||||||
|
// Transform content of the file into a string
|
||||||
|
let contents = match fs::read_to_string(file_name)
|
||||||
|
{
|
||||||
|
Ok(ret) => ret,
|
||||||
|
Err(err) => panic!("Could not deserialize the file, error code: {}", err)
|
||||||
|
};
|
||||||
|
|
||||||
|
let module: Result<Command> = serde_json::from_str(&contents.as_str());
|
||||||
|
module
|
||||||
|
}
|
||||||
|
|
||||||
|
fn main() {
|
||||||
|
let cli = Cli::parse();
|
||||||
|
let url = format!("{}:{}", cli.hostname, cli.port);
|
||||||
|
// let result = r_snmp_get(&url, "1.3.6.1.2.1.1.1.0", &cli.community);
|
||||||
|
// println!("Hello, {:?}!", &result);
|
||||||
|
let cmd = json_to_command(&cli.json_conf);
|
||||||
|
let cmd = cmd.unwrap();
|
||||||
|
let result = cmd.execute(&url);
|
||||||
|
}
|
10
experimental/test.json
Normal file
10
experimental/test.json
Normal file
@ -0,0 +1,10 @@
|
|||||||
|
{
|
||||||
|
"leaf": {
|
||||||
|
"name": "cpu",
|
||||||
|
"output": "{status}: {count} CPU(s) average usage is {total_cpu_avg} %",
|
||||||
|
"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"}}
|
||||||
|
]
|
||||||
|
}
|
||||||
|
}
|
Loading…
x
Reference in New Issue
Block a user