App-Netdisco
view release on metacpan or search on metacpan
lib/App/Netdisco/Util/Snapshot.pm view on Meta::CPAN
}
=head2 make_snmpwalk_browsable( $device )
Takes the device_browser rows for a device and rewrites them to convert
table rows to hashref, enum values translated, and oid_parts filled.
=cut
sub make_snmpwalk_browsable {
my $device = shift;
my %oids = ();
#Â to get relation from device_browser to snmp_object working for tables
#Â we need to temporarily populate device_browser with potential table oids.
#Â it will all be cleaned up after
my %value_oids = map {($_ => 1)} $device->oids->get_column('oid')->all;
my %table_oids = ();
foreach my $orig_oid (keys %value_oids) {
(my $oid = $orig_oid) =~ s/\.\d+$//;
my $new_oid = '';
while (length($oid)) {
$oid =~ s/^(\.\d+)//;
$new_oid .= $1;
$table_oids{$new_oid} = {oid => $new_oid, oid_parts => []}
unless exists $value_oids{$new_oid};
}
}
$device->oids->populate([values %table_oids]);
my @rows = $device->oids->search({},{
join => 'oid_fields',
columns => [qw/oid value/],
select => [qw/oid_fields.mib oid_fields.leaf oid_fields.enum/], as => [qw/mib leaf enum/],
})->hri->all;
$oids{$_->{oid}} = {
%{ $_ },
value => (defined $_->{value} ? decode_base64( (@{ from_json($_->{value}) })[0] ) : q{}),
} for grep {$_->{leaf} or length( (@{ from_json($_->{value}) })[0] )}
@rows;
%oids = collapse_snmp_tables(%oids);
%oids = resolve_enums(%oids);
#Â walk leaves and table leaves to b64 encode again
#Â build the oid_parts list
foreach my $k (keys %oids) {
my $value = (defined $oids{$k}->{value} ? $oids{$k}->{value} : q{});
#Â always a JSON array of single element
if (ref {} eq ref $value) {
$oids{$k}->{value} = to_json([{ map {($_ => encode_base64(trim($value->{$_}), ''))} keys %{ $value } }]);
}
else {
$oids{$k}->{value} = to_json([encode_base64(trim($value), '')]);
}
$oids{$k}->{oid_parts} = [ grep {length} (split m/\./, $oids{$k}->{oid}) ];
}
#Â store the device cache for real, now
schema('netdisco')->txn_do(sub {
$device->oids->delete;
$device->oids->populate([map {
{ oid => $_->{oid}, oid_parts => $_->{oid_parts}, value => $_->{value} }
} values %oids]);
debug sprintf 'replaced %d browsable oids in db', scalar keys %oids;
});
return %oids;
}
=head2 collapse_snmp_tables ( %oids )
In an snmpwalk where table rows are individual entries, gather them
up into a hashref. Returns %oids hash similar to what's passed in.
=cut
sub collapse_snmp_tables {
my %oids = @_;
return () unless scalar keys %oids;
OID: foreach my $orig_oid (sort {sortable_oid($a) cmp sortable_oid($b)} keys %oids) {
my $oid = $orig_oid;
my $idx = '';
# walk down the oid until we hit a known leaf
while (length($oid) and !defined $oids{$oid}->{leaf}) {
$oid =~ s/\.(\d+)$//;
$idx = (length $idx ? "${1}.${idx}" : $1);
}
if (0 == length($oid)) {
#Â we never found a leaf, delete it and move on
delete $oids{$orig_oid};
next OID;
}
$idx ||= '.0';
$idx =~ s/^\.//;
if ($idx eq '0') {
if ($oid eq $orig_oid and $oid =~ m/\.0$/) {
#Â generally considered to be a bad idea, sometimes the OID
# is standardised with .0 e.g. .1.3.6.1.2.1.1.3.0 sysUpTimeInstance
#Â - do nothing as the value is already OK
}
else {
$oids{$oid}->{value} = $oids{$orig_oid}->{value};
}
}
else {
#Â on rare occasions a vendor returns .0 and .something
#Â this will overwrite the .0 (requires the sorting above)
$oids{$oid}->{value} = {} if ref {} ne ref $oids{$oid}->{value};
$oids{$oid}->{value}->{$idx} = $oids{$orig_oid}->{value};
}
delete $oids{$orig_oid} if $orig_oid ne $oid;
}
#Â remove temporary entries added to resolve table names
delete $oids{$_}
for grep {!defined $oids{$_}->{value}
or (ref q{} eq ref $oids{$_}->{value} and $oids{$_}->{value} eq '')}
keys %oids;
return %oids;
}
=head2 resolve_enums ( %oids )
In an snmpwalk where the values are untranslated but enumerated types,
convert the values. Returns %oids hash similar to what's passed in.
=cut
sub resolve_enums {
my %oids = @_;
return () unless scalar keys %oids;
foreach my $oid (keys %oids) {
next unless $oids{$oid}->{enum};
my $value = $oids{$oid}->{value};
my %emap = map { reverse split m/\(/ }
map { s/\)//; $_ }
@{ $oids{$oid}->{enum} };
if (ref q{} eq ref $value) {
$oids{$oid}->{value} = $emap{$value} if exists $emap{$value};
}
elsif (ref {} eq ref $value) {
foreach my $k (keys %$value) {
$oids{$oid}->{value}->{$k} = $emap{ $value->{$k} }
if exists $emap{ $value->{$k} };
}
}
}
return %oids;
}
=head2 snmpwalk_to_snmpinfo_cache( %oids )
Takes an snmpwalk with collapsed tables and returns an SNMP::Info
instance using that as the cache.
=cut
sub snmpwalk_to_snmpinfo_cache {
my %walk = @_;
return () unless scalar keys %walk;
# unpack the values
foreach my $oid (keys %walk) {
my $value = $walk{$oid}->{value};
if (ref q{} eq ref $value) {
$walk{$oid}->{value} = decode_base64($walk{$oid}->{value});
}
elsif (ref {} eq ref $value) {
foreach my $k (keys %$value) {
$walk{$oid}->{value}->{$k}
= decode_base64($walk{$oid}->{value}->{$k});
}
}
}
my $info = SNMP::Info->new({
Offline => 1,
Cache => {},
Session => {},
MibDirs => [ get_mibdirs() ],
AutoSpecify => 0,
IgnoreNetSNMPConf => 1,
Debug => ($ENV{INFO_TRACE} || 0),
DebugSNMP => ($ENV{SNMP_TRACE} || 0),
});
foreach my $oid (keys %walk) {
my $qleaf = $walk{$oid}->{mib} . '::' . $walk{$oid}->{leaf};
(my $snmpqleaf = $qleaf) =~ s/[-:]/_/g;
$info->_cache($walk{$oid}->{leaf}, $walk{$oid}->{value});
$info->_cache($snmpqleaf, $walk{$oid}->{value});
( run in 0.413 second using v1.01-cache-2.11-cpan-39bf76dae61 )