Tek-Tips is the largest IT community on the Internet today!

Members share and learn making Tek-Tips Forums the best source of peer-reviewed technical information on the Internet!

  • Congratulations TouchToneTommy on being selected by the Tek-Tips community for having the most helpful posts in the forums last week. Way to Go!

Working with a %HoH returned from a subroutine 2

Status
Not open for further replies.

netman4u

Technical User
Mar 16, 2005
176
US
Hello all,

I am working on a script that reads a config file and loads it into a HoH as below:

Code:
open (CFG, "$cfg_file") or die ("Error opening config file $cfg_file: $1");
#
# Read config file, load a Vendor => Device Type => CLI hash of hashes. Count the entries.
#
my %cmd;
my ($vendor, $device, $rest);
while (<CFG>) {
	next if /^#/;
    chomp;
    ($vendor, $device, $rest) = split(/\s*\&\s*/);
	if ($vendor) {
        $cmd{$vendor}->{$device} = $rest;
		my $hoh_cnt = scalar(keys(%cmd));
    }
}
close CFG;

The I run a Query in a subroutine that creates another HoH and returns it as below:

Code:
sub VistaQuery 
{
	##########################################################################################
	#
	#  Query the InfoVista DB and build an ip to vendor hash for all the devices
	#  we will be querying.
	#
	##########################################################################################
my $sub_vendor;
my $sub_ip;
my $sub_dev_type;
my %sub_db_results;
my $data_source = "dbi:Oracle:binvdp01";
  my $dbh = DBI->connect($data_source, $orauser, $orapass)
      or die "Can't connect to $data_source: $DBI::errstr";
  my $sth = $dbh->prepare( q{select T1.SVALUE, T2.SVALUE, T3.SVALUE from twtpropvalues T1, twtpropvalues T2, twtpropvalues T3 where T1.PROPID=(select ID from twtproperties where WID='00000000000000000000000000000001') and T2.PROPID=(select ID from twtproperties where WID='72B1577C795AB24888F4462B18D8F42D') and T3.PROPID=(select ID from twtproperties where WID='069003638BAFDA11BCB000166F0D3E5D') and T1.INSID=T2.INSID and T2.INSID=T3.INSID
}
  ) or die "Can't prepare statement: $DBI::errstr";
  my $rc = $sth->execute
      or die "Can't execute statement: $DBI::errstr";
  print "Query will return $sth->{NUM_OF_FIELDS} fields.\n\n";
  print "Field names: @{ $sth->{NAME} }\n";
  while (($sub_ip, $sub_vendor, $sub_dev_type) = $sth->fetchrow_array) {
	  $sub_db_results{$sub_vendor}->{$sub_dev_type} = $sub_ip; 
}
#
# search for problems which may have terminated the fetch early, disconnect and return the hash.
#
  die $sth->errstr if $sth->err;
  $dbh->disconnect;
  return \%sub_db_results;
}# End sub VistaQuery

All well and good but I am having trouble using the returned reference to the HoH returned from the subroutine. What I want to do is loop through each entry in the HoH returned from the sub and do a lookup in the config file HoH to determine what commands to run on the device based on the $vendor and $device in the config file HOH. Here is what I have tried (messy)

Code:
my %db_results;
my $db_results = VistaQuery();
my ($ip,$cli1);
for my $key ( keys %$db_results ) {
	$cli1 = $db_results->{ $key }->{'$device'};
	print "ip: $ip, vendor: $vendor, cli: $cli1\n";
}

This does not work as the output of the print is:

Code:
ip: , vendor: Cisco, cli:
ip: , vendor: Cisco, cli:
ip: , vendor: Cisco, cli:


I then attempt to loop through the HoH from the query as so:

Code:
while(my($ip,$device,$vendor) = each %db_results) {
	my @time_stamp;
	next unless ($vendor);
	print "$ip => $vendor\n";
	my $cli = $cmd{'$vendor'}->{'$device'};
	print "$cli\n";

etc. etc.

Which is not working either. Maybe I am approaching this wrong as this is my first real foray into HoHs and I'm not sure they are made to be looped through.

Thanks,

Nick

If at first you don't succeed, don't try skydiving.
 
Code:
  for $loop (keys %hash) {
    for $loop2 (keys %{$hash{$loop}}) {;
      print $hash{$loop}{$loop2}."\n";
    }
  }

HTH

Paul
------------------------------------
Spend an hour a week on CPAN, helps cure all known programming ailments ;-)
 
this doesn't look right:

Code:
while(my($ip,$device,$vendor) = each %db_results) {

"each" returns a key/value pair when called in list context, you have three variables in the list so I assume $vendor is probably undef.

- Kevin, perl coder unexceptional!
 
Thanks for the replies Keven and Paul. The method for looping through a HoH makes sense. I do not think my messy code spells out clearly what I am trying to do and I am not sure if 2 HoHs are the way to go.

I have a config file that allows my program to be customized for determining what CLI commands are run on a network device based on the "Vendor" and "Device Type":

Code:
#######################################################################################
#
#  Configuration file for the program. Each entry will be a Vendor name
#  followed by an "&", then the Device Type followed by an "&", then a tab followed by
#  a csv entry for all the commands that #  could be run on any device. 
#  All columns of the output file are represented. So far a total of
#  9 varieties of commands can be run. An entry will exist on each line for each command.
#  If a command is not to be run on the entries vendor type, a blank space and a comma
#  will be added. Each coma represents a column in the output file
#  (see output file notes in VistaBridge_Perl_Cli_Flow doc). The program will use the 
#  number of CSV value entries to determine the number of columns for the output file 
#  (and the corresponding number and type of commands that can be run).
#
#######################################################################################
#
#
#  Vendor	Device		Commands
#
Foundry&	IMG&		show ip nat statistics, , , , , , , , ,
Foundry&	DLB&		sho server sessions, , , , , , , , ,
Cisco&		BSR&		, ,sho idb, , , , , , ,
Cisco&		CAT&		, ,sho idb, , , , , , ,

As you can see the config file has three fields, the Vendor Device and the commands to run on that vendor and device. I load this file into a HoH with this code:

Code:
open (CFG, "$cfg_file") or die ("Error opening config file $cfg_file: $1");
#
# Read config file, load a Vendor => Device Type => CLI hash of hashes. Count the entries.
#
my %cmd;
my ($vendor, $device, $rest);
while (<CFG>) {
	next if /^#/;
    chomp;
    ($vendor, $device, $rest) = split(/\s*\&\s*/);
	if ($vendor) {
        $cmd{$vendor}->{$device} = $rest;
		my $hoh_cnt = scalar(keys(%cmd));
    }
}
close CFG;
print $cmd{'Foundry'}->{'IMG'}."\n";

In order to determine what devices the commands from the config script will be run on, I perform a query to a DB. The query returns an IP address, Vendor and Device Type for a HoH of devices to run the CLI commands on with this sub:

Code:
sub VistaQuery 
{
	##########################################################################################
	#
	#  Query the InfoVista DB and build an ip to vendor hash for all the devices
	#  we will be querying.
	#
	##########################################################################################
my $sub_vendor;
my $sub_ip;
my $sub_dev_type;
my %sub_db_results;
my $data_source = "dbi:Oracle:binvdp01";
  my $dbh = DBI->connect($data_source, $orauser, $orapass)
      or die "Can't connect to $data_source: $DBI::errstr";
  my $sth = $dbh->prepare( q{select T1.SVALUE, T2.SVALUE, T3.SVALUE from twtpropvalues T1, twtpropvalues T2, twtpropvalues T3 where T1.PROPID=(select ID from twtproperties where WID='00000000000000000000000000000001') and T2.PROPID=(select ID from twtproperties where WID='72B1577C795AB24888F4462B18D8F42D') and T3.PROPID=(select ID from twtproperties where WID='069003638BAFDA11BCB000166F0D3E5D') and T1.INSID=T2.INSID and T2.INSID=T3.INSID
}
  ) or die "Can't prepare statement: $DBI::errstr";
  my $rc = $sth->execute
      or die "Can't execute statement: $DBI::errstr";
  print "Query will return $sth->{NUM_OF_FIELDS} fields.\n\n";
  print "Field names: @{ $sth->{NAME} }\n";
  while (($sub_ip, $sub_vendor, $sub_dev_type) = $sth->fetchrow_array) {
	  $sub_db_results{$sub_ip}->{$sub_dev_type} = $sub_vendor; 
#	  print "Look Here: $sub_ip\t$sub_vendor\t$sub_dev_type\n";
  }
#
# search for problems which may have terminated the fetch early, disconnect and return the hash.
#
  die $sth->errstr if $sth->err;
  $dbh->disconnect;
  return \%sub_db_results;
}# End sub VistaQuery

Now that I have the config HoH loaded and the HoH for devices to run I need to loop through the query HoH and look up the commands to run in the config HoH based on the Vendor and Device Type from the query. I then need to use the IP Address from the query HoH and the CLI commands from the config file to SSH to each devices IP and run the commands. So I ultimately need to end up with a hash containing:

IP address->ClI Commands.

I hope that explains it better.

Any help is appreciated.

Nick


If at first you don't succeed, don't try skydiving.
 
Well Paul, it seems you gave me enough to figure this out. I am getting my "ip" -> "cli" hash with this code:

Code:
my %ip_cli;
for my $loop (keys %db_results) {
	print "loop = $loop\n";
    for my $loop2 (keys %{$db_results{$loop}}) {;
		print "loop2 = $loop2\n";
#      print $db_results{$loop}{$loop2}."\n";
	  $ip_cli{$db_results{$loop}{$loop2}} = $cmd{$loop}->{$loop2};
    }
  }

Not sure though why the semi colon is needed here:

for my $loop2 (keys %{$db_results{$loop}}) {;


Thanks,

Nick

If at first you don't succeed, don't try skydiving.
 
that'd be one of those typos we keep hearing about so much ;-)

Paul
------------------------------------
Spend an hour a week on CPAN, helps cure all known programming ailments ;-)
 
can;t trust those mangy semi-colons! Always popping up where they don;t belong! Ahh! [upsidedown]

- Kevin, perl coder unexceptional!
 
Haa! Well it still worked!

If at first you don't succeed, don't try skydiving.
 
Status
Not open for further replies.

Part and Inventory Search

Sponsor

Back
Top