getwithrob has asked for the wisdom of the Perl Monks concerning the following question:

I had a previous post on this issue but feel it's now burried too deep and is quiet muddled up so I'm posting again to try to be more clear and get it back to the top. I'm not a programmer so please, please help me out!!! What I want to do is this:
1. Read Cisco devices from a file I create: host1.domain.com host2.domain.com host3.domain.com 2. For each device in this list do snmpgets to get: a. a port description for each port (devices will have 16, 24, 48 or m +ore ports) b. the oper status for each port c. the admin status for each port d. the last change status for each port 3. I want the output to be in a CSV format so the file can be opened w +ith Excel 4. The variables I will be polling are: a. snmpwalk interfaces.ifTable.ifEntry.ifDescr public $host b. snmpwalk interfaces.ifTable.ifEntry.ifOperStatus public $host c. snmpwalk interfaces.ifTable.ifEntry.ifAdminStatus public $host d. snmpwalk interfaces.ifTable.ifEntry.ifLastChange public $host 5. Here is a sample snmpwalk for each variable above. a. johnsonr@nmscrme01 > snmpwalk 10.245.159.57 public interfaces.ifTa +ble.ifEntry.ifDescr interfaces.ifTable.ifEntry.ifDescr.1 = FastEthernet0/1 interfaces.ifTable.ifEntry.ifDescr.2 = FastEthernet0/2 interfaces.ifTable.ifEntry.ifDescr.3 = FastEthernet0/3 ..... b. johnsonr@nmscrme01 > snmpwalk 10.245.159.57 public interfaces.ifTa +ble.ifEntry.ifOperStatus interfaces.ifTable.ifEntry.ifOperStatus.1 = up(2) interfaces.ifTable.ifEntry.ifOperStatus.2 = up(2) interfaces.ifTable.ifEntry.ifOperStatus.3 = down(2) ..... c. johnsonr@nmscrme01 > snmpwalk 10.245.159.57 public interfaces.ifTa +ble.ifEntry.ifAdminStatus interfaces.ifTable.ifEntry.ifAdminStatus.1 = up(2) interfaces.ifTable.ifEntry.ifAdminStatus.2 = up(2) interfaces.ifTable.ifEntry.ifAdminStatus.3 = down(2) ..... d. johnsonr@nmscrme01 > snmpwalk 10.245.159.57 public interfaces.ifTa +ble.ifEntry.ifLastChange interfaces.ifTable.ifEntry.ifLastChange.1 = Timeticks: (628809469) 72 +days, 18:41:34.69 interfaces.ifTable.ifEntry.ifLastChange.2 = Timeticks: (2297919248) 26 +5 days, 23:06:32.48 interfaces.ifTable.ifEntry.ifLastChange.3 = Timeticks: (5370) 0:00:53. +70 ..... My goal is this, open the csv file using Excel so the output will look + something like this: FastEthernet0/1 up(2) up(2) Timeticks: (628809469) 72 days, 1 +8:41:34.69 FastEthernet0/2 up(2) up(2) Timeticks: (2297919248) 265 days, + 23:06:32.48 FastEthernet0/3 down(2) down(2) Timeticks: (5370) 0:00:53.70 Of course it would like this before opening it as a .csv FastEthernet0/1,up(2),up(2),Timeticks: (628809469) 72 days, 18:41:34.6 +9 FastEthernet0/2,up(2),up(2),Timeticks: (2297919248) 265 days, 23:06:32 +.48 FastEthernet0/3,down(2),down(2),Timeticks: (5370) 0:00:53.70
Again, please keep in mind my programming skills are pretty much zero.

Replies are listed 'Best First'.
Re: snmpwalk to CSV #2
by graff (Chancellor) on Sep 23, 2005 at 14:12 UTC
    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 );
      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.