Storage.pm
上传用户:wxp200602
上传日期:2007-10-30
资源大小:4028k
文件大小:13k
源码类别:

SNMP编程

开发平台:

Unix_Linux

  1. #########################################################################
  2. package AnyData::Storage::SNMP;
  3. #########################################################################
  4. ## XXX: TODO:
  5. ##   scalar sets?
  6. ##   multi-hosts
  7. $AnyData::Storage::VERSION = '5.2.2';
  8. use strict;
  9. use vars qw(@basecols);
  10. @AnyData::Storage::SNMP::basecols = qw(hostname iid);
  11. $AnyData::Storage::SNMP::iidptr = 1; # must match array column of above
  12. @AnyData::Storage::SNMP::basetypes = qw(OCTETSTR OBJECTID);
  13. $AnyData::Storage::SNMP::debug = 0;
  14. $AnyData::Storage::SNMP::debugre = undef;
  15. use Data::Dumper;
  16. use AnyData::Storage::File;
  17. use SNMP;
  18. SNMP::init_snmp("AnyData::SNMP");
  19. sub new {
  20. #    DEBUG("calling AnyData::Storage::SNMP newn");
  21. #    DEBUG("new storage: ",Dumper(@_),"n");
  22.     my $class = shift;
  23.     my $self  = shift || {};
  24.     $self->{open_mode} = 'c';
  25.     return bless $self, $class;
  26. }
  27. sub open_table {
  28.     DEBUG("calling AnyData::Storage::SNMP open_tablen");
  29.     my ($self, $parser, $table, $mode, $tname) = @_;
  30.     $self->{'process_table'} = $tname;
  31.     DEBUG("open_table: ",Dumper(@_),"n");
  32. }
  33. sub get_col_names {
  34.     DEBUG("calling AnyData::Storage::SNMP get_col_namesn");
  35.     my ($self, $parser, $tname) = @_;
  36.     DEBUG("get_col_namesn",Dumper(@_),"n");
  37.     $tname = $self->{'process_table'} if (!$tname);
  38.     # get cached previous results
  39.     return $self->{col_names}{$tname} if (defined($self->{col_names}{$tname}));
  40.     # table name
  41.     $tname = $self->{'process_table'} if (!$tname);
  42.     # mib node setup
  43.     my $mib = $SNMP::MIB{$tname} || return warn "no such table $tname";
  44.     my $entry = $mib->{'children'}[0];
  45.     # base columns and types
  46.     my @cols = @AnyData::Storage::SNMP::basecols;
  47.     my @types = @AnyData::Storage::SNMP::basetypes;
  48.     my %donecol;
  49.     my $count = $#cols;
  50.     foreach my $index (@{$entry->{'indexes'}}) {
  51. push @cols, $index;
  52. push @types, $SNMP::MIB{$index}{type};
  53. $donecol{$index} = 1;
  54. $count++;
  55. if ($SNMP::MIB{$index}{parent}{label} eq $entry->{label}) {
  56.     # this index is a member of this table
  57.     $self->{columnmap}[$count] = $index;
  58.     $self->{coloffset} += 1;
  59. }
  60.     }
  61.     # search children list
  62.     foreach my $child  ( sort { $a->{'subID'} <=> $b->{'subID'} } @{$entry->{'children'}}) {
  63. push @{$self->{real_cols}}, $child->{'label'};
  64. next if ($donecol{$child->{label}});
  65. push @cols, $child->{'label'};
  66. push @types, $child->{'type'};
  67. $count++;
  68. $self->{columnmap}[$count] = $child->{'label'};
  69.     }
  70.     # save for later.
  71.     $parser->{col_names} = @cols;
  72.     $self->{col_types} = @types;
  73.     $self->{col_names} = @cols;
  74.     map { $self->{col_uc_map}{uc($_)} = $_ } @cols;
  75.     return @cols;
  76. }
  77. sub set_col_nums {
  78.     DEBUG("calling AnyData::Storage::SNMP set_col_numsn");
  79.     DEBUG("set_col_numsn",Dumper(@_),"n");
  80.     my ($self, $tname) = @_;
  81.     return $self->{col_nums} if (defined($self->{col_nums}));
  82.     my $mib = $SNMP::MIB{$tname};
  83.     my $entry = $mib->{'children'}[0];
  84.     my (%cols, %mibnodes);
  85.     my $cnt = -1;
  86.     foreach my $i (@{$self->{col_names}}) {
  87. $cols{$i} = ++$cnt;
  88.     }
  89.     $self->{col_nums} = %cols;
  90.     return %cols;
  91. }
  92. # not needed?
  93. sub get_file_handle {
  94.     DEBUG("calling AnyData::Storage::SNMP get_file_handlen");
  95.     DEBUG("get_file_handlen",Dumper(@_),"n");
  96.     return shift;
  97. }
  98. # not needed?
  99. sub get_file_name {
  100.     DEBUG("calling AnyData::Storage::SNMP get_file_namen");
  101.     DEBUG("get_file_namen",Dumper(@_),"n");
  102.     my $self = shift;
  103.     return $self->{process_table} || $self->{table_name};
  104. }
  105. sub truncate {
  106.     DEBUG("calling AnyData::Storage::SNMP truncaten");
  107.     my ($self) = @_;
  108.     DEBUG("trunacte, ", Dumper(@_));
  109.     # We must know how to delete rows or else this is all pointless.
  110. #     return $self->{col_nums}{$tname} if (defined($self->{col_nums}{$tname}));
  111.     my $tablemib = $SNMP::MIB{$self->{process_table}};
  112.     my $entrymib = $tablemib->{'children'}[0];
  113.     my ($delcolumn, $delcolumnname, $delcolumnvalue);
  114.     foreach my $child  (@{$entrymib->{'children'}}) {
  115. if ($child->{'textualConvention'} eq 'RowStatus') {
  116.     $delcolumn = $child->{subID};
  117.     $delcolumnname = $child->{label};
  118.     $delcolumnvalue = 6; # destroy
  119.     last;
  120. }
  121.     }
  122.     if (!$delcolumn) {
  123. return warn "Can't (or don't know how to) delete from table $self->{process_table}.  Failing.n";
  124.     }
  125.     # we should have a session, or else something is really wierd but...
  126.     $self->{'sess'} = $self->make_session() if (!$self->{'sess'});
  127.     # for each key left in our cache, delete it
  128.     foreach my $key (keys(%{$self->{'existtest'}})) {
  129. # xxx: fullyqualified oid better
  130. my $vblist = new SNMP::VarList([$delcolumnname, $key,
  131. $delcolumnvalue]);
  132. DEBUG("truncate $key: n", Dumper($vblist));
  133. $self->{'sess'}->set($vblist) || warn $self->{'sess'}->{ErrorStr};
  134.     }
  135.     return;
  136. }
  137. sub make_session {
  138.     DEBUG("calling AnyData::Storage::SNMP make_sessionn");
  139.     my $self = shift;
  140.     my @args = @_;
  141.     my @sessions;
  142.     foreach my $key (qw(SecName Version SecLevel AuthPass Community RemotePort Timeout Retries RetryNoSuch SecEngineId ContextEngineId Context AuthProto PrivProto PrivPass)) {
  143. push @args, $key, $self->{$key} if ($self->{$key});
  144.     }
  145.     foreach my $host (split(/,s*/,$self->{DestHost})) {
  146. push @sessions, new SNMP::Session(@args, 'DestHost' => $host);
  147.     }
  148.     return @sessions;
  149. }
  150. sub file2str {
  151.     DEBUG("calling AnyData::Storage::SNMP file2strn");
  152.     my ($self, $parser, $uccols) = @_;
  153.     my ($cols, @retcols);
  154.     DEBUG("file2strn",Dumper(@_),"n");
  155.   restart:
  156.     if (!$self->{lastnode}) {
  157. # my @vbstuff = @{$parser->{'col_names'}};
  158. # splice (@vbstuff,0,1+$#AnyData::Storage::SNMP::basecols);
  159. # map { $_ = [ $_ ] } @vbstuff;
  160. # $self->{lastnode} = new SNMP::VarList(@vbstuff);
  161. # splice (@$cols,0,1+$#AnyData::Storage::SNMP::basecols);
  162. map { push @$cols,$self->{col_uc_map}{$_} } @$uccols;
  163. if ($#$cols == -1) {
  164.     $cols = $self->{'col_names'};
  165.     # remove base columns
  166.     splice (@$cols,0,1+$#AnyData::Storage::SNMP::basecols);
  167.     # remove not accessible columns
  168.     foreach my $col (@$cols) {
  169. my $mib = $SNMP::MIB{$col};
  170. push @retcols, $col if ($mib->{'access'} =~ /Read|Create/);
  171.     }
  172. } else {
  173.     @retcols = @$cols;
  174.     # remove base columns
  175.     foreach my $c (@AnyData::Storage::SNMP::basecols) {
  176. @retcols = grep(!/^$c$/, @retcols);
  177.     }
  178.     # remove non-accessible columns
  179.     @retcols = grep {$SNMP::MIB{$_}{'access'} =~ /Read|Create/} @retcols;
  180. }
  181. map { $_ = [ $_ ] } @retcols;
  182. $self->{lastnode} = new SNMP::VarList(@retcols);
  183.     }
  184.     if (!$self->{'sess'}) {
  185. $self->{'sess'} = $self->make_session();
  186. if ($#{$self->{'sess'}} == 0 && $self->{'silence_single_host'}) {
  187.     $self->{'hostname'} = '';
  188. } else {
  189.     $self->{'hostname'} = $self->{'sess'}[0]{'DestHost'};
  190. }
  191.     }
  192.     # perform SNMP operation
  193.     my $lastnode = $self->{'lastnode'}[0][0];
  194.     my $result;
  195.     $result = $self->{'sess'}[0]->getnext($self->{lastnode});
  196.     if (!defined($result)) {
  197. warn " getnext of $self->{lastnode}[0][0] returned undefn";
  198.     }
  199.     DEBUG(" result: ",Dumper($self->{lastnode}),"n");
  200.     # XXX: check for holes!
  201.     # need proper oid compare here for all nodes
  202.     if ($self->{'lastnode'}[0][0] ne $lastnode) {
  203. if ($#{$self->{'sess'}} > 0) {
  204.     shift @{$self->{'sess'}};
  205.     delete($self->{'lastnode'});
  206.     @$cols = ();
  207.     $self->{'hostname'} = $self->{'sess'}[0]{'DestHost'} if($self->{'hostname'});
  208.     goto restart;
  209. }
  210. return undef;
  211.     }
  212.     
  213.     # add in basecols information:
  214.     my @ret = ($self->{'hostname'}, $self->{'lastnode'}[0][1]);
  215.     DEBUG("Dump row results: ",Dumper($self->{'lastnode'}),"n");
  216.     # build result array from result varbind contents
  217.     map { $ret[$self->{'col_nums'}{$_->[0]}] = map_data($_); } @{$self->{'lastnode'}};
  218.     # store instance ID for later use if deletion is needed later.
  219.     $self->{'existtest'}{$self->{'lastnode'}[0][1]} = 1;
  220.     DEBUG("Dump row results2: ",Dumper(@ret),"n");
  221.     return @ret;
  222. }
  223. sub map_data {
  224.     if ($_->[3] eq "OBJECTID") {
  225. $_->[2] = pretty_print_oid(@_);
  226.     }
  227.     return $_->[2];
  228. }
  229. sub pretty_print_oid {
  230.     use NetSNMP::default_store qw(:all);
  231.     netsnmp_ds_set_boolean(NETSNMP_DS_LIBRARY_ID, 
  232.    NETSNMP_DS_LIB_DONT_BREAKDOWN_OIDS,0);
  233.     my $new = SNMP::translateObj($_->[2], 0);
  234.     netsnmp_ds_set_boolean(NETSNMP_DS_LIBRARY_ID, 
  235.    NETSNMP_DS_LIB_DONT_BREAKDOWN_OIDS,1);
  236.     my $new2 = SNMP::translateObj($_->[2], 0);
  237.     if ($new) {
  238. $_->[2] = $new2 . "$new";
  239.     } else {
  240. $_->[2] = $_->[0] . $_->[1];
  241.     }
  242.     return $_->[2];
  243. }
  244. sub push_row {
  245.     DEBUG("calling AnyData::Storage::SNMP push_rown");
  246.     DEBUG("push_row: ",Dumper(@_),"n");
  247.     DEBUG("push_rown");
  248.     my ($self, $values, $parser, $cols) = @_;
  249.     my @callers = caller(3);
  250.     my $mode = $callers[3];
  251.     if ($mode =~ /DELETE/) {
  252. DEBUG("not deleting $values->[$AnyData::Storage::SNMP::iidptr]n");
  253. delete $self->{'existtest'}{$values->[$AnyData::Storage::SNMP::iidptr]};
  254. return;
  255.     }
  256.     my @origvars;
  257.     if ($#$cols == -1) {
  258. # no column info passed in.  Update everything (mode probably INSERTS).
  259. # @origvars = @{$self->{'col_names'}}};
  260. # splice (@origvars,0,1+$#AnyData::Storage::SNMP::basecols);
  261. map { push @origvars, $_ if $SNMP::MIB{$_}{'access'} =~ /Write|Create/; } @{$self->{'real_cols'}} ;
  262. DEBUG("set cols: ", Dumper(@origvars));
  263.     } else {
  264. # only update the columns in question.  (mode probably UPDATE)
  265. map { push @origvars, $self->{col_uc_map}{$_} } @$cols;
  266.     }
  267.     my @vars;
  268.     foreach my $var (@origvars) {
  269. my $access = $SNMP::MIB{$var}{'access'};
  270. # not in this table, probably (hopefully) an index from another:
  271. next if ($SNMP::MIB{$var}{'parent'}{'parent'}{'label'} ne 
  272.  $self->{process_table});
  273. DEBUG("$var -> $accessn");
  274. if ($access =~ /(Write|Create)/) {
  275.     push @vars, $var;
  276. } elsif ($mode eq 'insert') {
  277.     DEBUG("XXX: error if not indexn");
  278. } elsif ($mode eq 'update') {
  279.     DEBUG("update to non-writable column attempted (SNMP error coming)n");
  280. }
  281.     }
  282.     # generate index OID component if we don't have it.
  283.     if ($values->[$AnyData::Storage::SNMP::iidptr] eq '') {
  284. $values->[$AnyData::Storage::SNMP::iidptr] = 
  285.     $self->make_iid($self->{process_table}, $values);
  286.     }
  287.     # add in values to varbind columns passed in from incoming parameters
  288.     my @newvars;
  289.     foreach my $v (@vars) {
  290. my $num = $self->{'col_nums'}{$v};
  291. DEBUG("types: $v -> $num -> ", $self->{'col_types'}[$num], 
  292.       " -> val=", $values->[$num], "n");
  293. next if (!defined($values->[$num]));
  294. # build varbind: column-oid, instance-id, value type, value
  295. push @newvars, [$v, $values->[1], $values->[$num],
  296. $self->{'col_types'}[$num]];
  297.     };
  298.     # create the varbindlist
  299. #    print STDERR Dumper(@newvars);
  300.     my $vblist = new SNMP::VarList(@newvars);
  301. #    print STDERR Dumper($vblist);
  302.     DEBUG("set: ", Dumper($vblist));
  303.     $self->{'sess'} = $self->make_session() if (!$self->{'sess'});
  304.     if (!$self->{'sess'}[0]) {
  305. warn "couldn't create SNMP session";
  306.     } elsif (!$self->{'sess'}[0]->set($vblist)) {
  307. my $err = "$self->{process_table}: " . $self->{'sess'}[0]->{ErrorStr};
  308. if ($self->{'sess'}[0]->{ErrorInd}) {
  309.     $err = $err . " (at varbind #" 
  310. . $self->{'sess'}[0]->{ErrorInd}  . " = " ;
  311.     my $dump = Data::Dumper->new([$vblist->[$self->{'sess'}[0]->{ErrorInd} -1]]);
  312.     $err .= $dump->Indent(0)->Terse(1)->Dump;
  313. }
  314. warn $err;
  315.     }
  316. }
  317. sub seek {
  318.     DEBUG("calling AnyData::Storage::SNMP seekn");
  319.     my ($self, $parser) = @_;
  320.     DEBUG("seekn",Dumper(@_),"n");
  321. }
  322. sub make_iid {
  323.     DEBUG("calling AnyData::Storage::SNMP make_iidn");
  324.     my ($self, $tname, $vals) = @_;
  325.     
  326.     # Get indexes
  327.     my $mib = $SNMP::MIB{$tname};
  328.     my $entry = $mib->{'children'}[0];
  329.     my $indexes = $entry->{'indexes'};
  330.     my $iid;
  331.     # XXX: implied
  332. #    print STDERR "INDEXES: ", Dumper($vals),"n";
  333.     foreach my $index (@$indexes) {
  334. warn "A null index value was found, which I doubt is correct." if (!defined($vals->[$self->{col_nums}{$index}]));
  335. my $val = $vals->[$self->{col_nums}{$index}];
  336. my $type = $SNMP::MIB{$index}->{'type'};
  337. DEBUG("index type: $index -> $type -> $val -> " . length($val) . "n");
  338. if ($type eq "OCTETSTR") {
  339.     $iid .= "." . length($val) . "." . join(".", unpack("c*", $val));
  340. } elsif ($type eq "OBJID") {
  341.     $iid .= "." . (scalar grep(/./,$val) + 1) . "." . $val;
  342. } else {
  343.     # should be only an INTEGER?
  344.     $iid .= "." . $val;
  345. }
  346.     }
  347.     DEBUG("made iid: $iidn");
  348.     return $iid;
  349. }
  350. sub DEBUG {
  351.     my @info = caller(1);
  352.     if ($AnyData::Storage::SNMP::debug
  353. || ($AnyData::Storage::SNMP::debugre &&
  354.     $_[0] =~ /$AnyData::Storage::SNMP::debugre/)) {
  355. DEBUGIT(@info, @_);
  356.     }
  357. }
  358. sub DEBUGIT {
  359.     my $info;
  360.     if (ref($_[0]) eq 'ARRAY') {
  361. $info = shift @_;
  362.     } else {
  363. my @y;
  364. my $c=0;
  365. print STDERR "debug chain: ";
  366. for(@y = caller($c); $#y > -1; $c++, @y = caller($c)) {
  367.     print STDERR "  $c: $y[3]n";
  368. }
  369. my @x = caller(1);
  370. $info = @x;
  371.     }
  372.     print STDERR "$info->[3]: ";
  373.     print STDERR @_;
  374. }
  375. 1;