in reply to snmpwalk to CSV #2

If I knew more about snmpwalk and related tools, I would suggest that you find a way to get the same amount of information using fewer runs (e.g. get all information for a given host in a single snmpwalk command execution per host). But since I don't know enough to suggest that...

Do the host names you show at the top correspond to the IP addresses shown in each of the snmpwalk runs? So you have something already that does the IP address lookup for the host name, and you want to run a set of 4 snmpwalk commands on each IP?

Start out with a hash whose keys are the IP addresses. Each element of this hash will be a reference to another hash, whose keys are the four types of information needed. For each type of info on a given host, there will be a reference to an array of port values. That is, your data structure will end up as a "hash of hashes of arrays" (HoHoA). Now, it's just a matter of looping over IP's and info types.

(Also, since there are -- or could be -- commas in the data, you'll want to quote the fields in the csv output that you create.)

#!/usr/bin/perl use strict; # make sure we can open input and output files open( H, "host_list_file" ) or die "host_list_file: $!"; open( O, ">output.csv" ) or die "output.csv: $!"; # read host list my @hosts = <H>; close H; chomp @hosts; # remove "\r\n" from ends of lines my @iplist; for my $host ( @hosts ) { my $ip = ... # do whatever you do to get $ip for $host (and chomp if needed) push @iplist, $ip; } my %ipdata; my @infolist = qw/ifDescr ifOperStatus ifAdminStatus ifLastChange/; my $cmdarg = "public interfaces.ifTable.ifEntry."; # UPDATED to includ +e final "." for my $ip ( @iplist ) { for my $info ( @infolist ) { my @pdata = `snmpwalk $ip $cmdarg$info`; chomp @pdata; # remove line-terminations s/.* = // for (@pdata); # remove redundant text $ipdata{$ip}{$info} = [ @pdata ]; # create array ref in the ha +sh structure $ipdata{$ip}{lastport} = $#pdata; # keep track of how many por +ts } } # now print the csv data for my $ip ( @iplist ) { for my $portid ( 0 .. $ipdata{$ip}{lastport} ) { my $outstr = ''; for my $info ( @infolist ) { $outstr .= '"' . $ipdata{$ip}{$info}[$portid] . '",'; } $outstr =~ s/,$/\n/; # replace trailing comma print O $outstr; } }
Now, I think that will do what you want (it's untested), but I would have expected that including the IP address and maybe the port number on each line would be a good idea too -- if that's true, just change  $outstr = ''; to  $outstr = sprintf( "%s,%s,", $ip, $portid+1 );

Replies are listed 'Best First'.
Re^2: snmpwalk to CSV #2
by getwithrob (Initiate) on Sep 23, 2005 at 15:24 UTC
    DNS is running and is doing the name resolution. I do want to perform 4 different snmp queries against each host in this file. I'm not exactly sure what you mean when you say: Start out with a hash whose keys are the IP addresses. I copied and pasted the file over to the unix box and made one change to reflect the name of the file that contains the hosts. I tried to execute it but it says: johnsonr@nmscrme01 > ./snmptest.pl syntax error at ./snmptest.pl line 17, near "= ..." Global symbol "$ip" requires explicit package name at ./snmptest.pl line 19. Execution of ./snmptest.pl aborted due to compilation errors. johnsonr@nmscrme01 >
      Since I'm not able to test the code myself, I was expecting you to actually try to read it first, before running it. Just because you don't know much about programming now, this doesn't mean you can't start to learn a little about programming...

      The line cited in the error message is the place where you have to insert some code yourself, which will translate the host name into an IP address (this is mentioned in the comment next to that line). Do you not know how you are getting the IP address for a given host name in your existing script?

      Let's suppose you use a unix command like "host" to get an IP address -- e.g., on my macosx/BSD box, looking up the IP for perlmonks.org goes like this:

      $ host www.perlmonks.org www.perlmonks.org is an alias for perlmonks.org. perlmonks.org has address 209.197.123.153 perlmonks.org has address 66.39.54.27
      Probably you'll only get one IP per host in your list, and in any case, the first IP you get will probably work. So replace that line causing the error with something like these two lines:
      my $ip = `host $host`; $ip =~ s/.*?(\d+\.\d+\.\d+\.\d+).*/$1/s;
      Now, if that fixes the syntax error but other problems still remain, you can just keep popping back for more corrections (which will annoy the rest of us), or you can start looking things up on your own, and see if you can figure out what to try next.
        Oops. I forgot one thing... How can I get the name of the node being walked to display for each port or at least at the beginning of the ports for that node? I will use the script to walk against a lot of devices and need to be able to differentiate between them. I'm guessing it has something to do with the chomp statement. Here's what I have for the script:
        #!/usr/bin/perl use strict; # make sure we can open input and output files open( H, "/opt/home/johnsonr/scripts/nodes" ) or die "/opt/home/johnso +nr/scripts/nodes: $!"; open( O, ">output.csv" ) or die "output.csv: $!"; # read host list my @hosts = <H>; close H; chomp @hosts; # remove "\r\n" from ends of lines my @iplist; for my $host ( @hosts ) { my $ip = `getent hosts $host`; $ip =~ s/.*?(\d+\.\d+\.\d+\.\d+).*/$1/s; # do whatever you do to get $ip for $host (and chomp if needed) push @iplist, $ip; } my %ipdata; my @infolist = qw/ifDescr ifOperStatus ifAdminStatus ifLastChange/; my $cmdarg = "VER143r interfaces.ifTable.ifEntry."; # UPDATED to inclu +de final "." for my $ip ( @iplist ) { for my $info ( @infolist ) { my @pdata = `snmpwalk $ip $cmdarg$info`; chomp @pdata; # remove line-terminations s/.* = // for (@pdata); # remove redundant text $ipdata{$ip}{$info} = [ @pdata ]; # create array ref in the ha +sh structure $ipdata{$ip}{lastport} = $#pdata; # keep track of how many por +ts } } # now print the csv data for my $ip ( @iplist ) { for my $portid ( 0 .. $ipdata{$ip}{lastport} ) { my $outstr = ''; for my $info ( @infolist ) { $outstr .= '"' . $ipdata{$ip}{$info}[$portid] . '",'; } $outstr =~ s/,$/\n/; # replace trailing comma print O $outstr; } }
        OK. It works and works exactly how I wanted it to. I can't thank you enough for your help!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!