#!/usr/bin/perl ## ## Ultraviolet 0.1 written 060613 by Bowie Poag ## ## Ultraviolet examines two VIO servers and attempts to divine if their configurations are logically equivalent. ## If not, it reports the discrepancies. ## ## Usage: ultraviolet.pl ## ## Example: ultraviolet.pl argonvioA.foo.com argonvioB.foo.com ## ## use Data::Dumper; ## The above dependency is optional. It's only there in the event you wish to examine the hash visually... in which case, set $DEBUG to 1. $DEBUG=0; $vioA=$ARGV[0]; $vioB=$ARGV[1]; gatherConfigurations(); buildConfigHashes(); compareContents(); reportAnyProblems(); sub gatherConfigurations() { print "\nUltraviolet: Starting up..\n"; print "Ultraviolet: Collecting configuration info from $vioA and $vioB.."; @lsmapDumpA=vioCommand("vio",$vioA,"lsmap -all"); print ".."; @templspvDumpA=vioCommand("vio",$vioA,"lspv"); print ".."; @lsmapDumpB=vioCommand("vio",$vioB,"lsmap -all"); print ".."; @templspvDumpB=vioCommand("vio",$vioB,"lspv"); print "..\n"; ## We don't care about hdisk enumeration, so, let's get that out of the way. foreach $item (@templspvDumpA) { chomp($item); $item=~s/hdisk\d+\s+//g; $item=~s/\s+/ /g; $item=~s/None//g; if ($item=~/None/i) { push (@lspvDumpA,$item); } } foreach $item (@templspvDumpB) { chomp($item); $item=~s/hdisk\d+\s+//g; $item=~s/\s+/ /g; $item=~s/None//g; if ($item=~/None/i) { push (@lspvDumpB,$item); } } @lspvDumpA=sort @lspvDumpA; @lspvDumpB=sort @lspvDumpB; $vioAPVCount=scalar @lspvDumpA; $vioBPVCount=scalar @lspvDumpB; if ($DEBUG==1) { foreach $item (@lspvDumpA) { print "Ultraviolet: $vioA LSPV: $item\n"; } foreach $item (@lspvDumpB) { print "Ultraviolet: $vioB LSPV: $item\n"; } } } sub compareContents() { $numValidPVIDs=0; printf ("Ultraviolet: %-20s %-6s %-50s\n","Test","Result","Notes"); print "Ultraviolet: -------------------------------------------------------------------------------------------------\n"; ## ## PV Count Test. ## if ($vioAPVCount!=$vioBPVCount) { printf ("Ultraviolet: %-20s %-6s %-50s\n","PV Count","FAIL","Mismatch detected!"); push (@problems,"The number of PVs differs between $vioA and $vioB. $vioA has $vioAPVCount PVs, and $vioB has $vioBPVCount PVs. Both should be equal.\n"); } else { printf ("Ultraviolet: %-20s %-6s %-50s\n","PV Count","PASS","Overall PV counts are equivalent between VIO servers."); } ## ## PVID A-to-B Match Test ## foreach $item (@lspvDumpA) { if (grep(/$item/,@lspvDumpB)) { $numValidPVIDs++; } } if ($numValidPVIDs==$vioAPVCount) { printf ("Ultraviolet: %-20s %-6s %-50s\n","PV Match A to B","PASS","All PVIDs present on $vioA are present on $vioB."); } else { printf ("Ultraviolet: %-20s %-6s %-50s\n","PV Match A to B","FAIL","One or more PVIDs found on $vioA were not found on $vioB."); push (@problems,"PVID $item exists on $vioA, but does not exist on $vioB\n"); } $numValidPVIDs=0; ## ## PVID B-to-A Match Test ## foreach $item (@lspvDumpB) { if (grep(/$item/,@lspvDumpA)) { $numValidPVIDs++; } } if ($numValidPVIDs==$vioBPVCount) { printf ("Ultraviolet: %-20s %-6s %-50s\n","PV Match B to A","PASS","All PVIDs present on $vioB are present on $vioA."); } else { printf ("Ultraviolet: %-20s %-6s %-50s\n","PV Match B to A","FAIL","One or more PVIDs found on $vioB were not found on $vioA."); push (@problems,"PVID $item exists on $vioB, but does not exist on $vioA\n"); } ## ## Vhost Count Test ## $numActiveVhostsA=scalar(keys %vioA); $numActiveVhostsB=scalar(keys %vioB); if ($numActiveVhostsA==$numActiveVhostsB) { printf ("Ultraviolet: %-20s %-6s %-50s\n","Active Vhost Count","PASS","The same number of vhosts are active on both VIO servers."); } else { printf ("Ultraviolet: %-20s %-6s %-50s\n","Active Vhost Count","FAIL","$vioA and $vioB have differing numbers of vhosts with storage mapped to them."); push (@problems,"The number of vhosts with storage mapped to them differs between $vioA and $vioB.. $numActiveVhostsA and $numActiveVhostsB, respectively."); } ## ## LPAR Count Test ## $LPARCountA=0; $LPARCountB=0; foreach $item (sort keys %vioA) { $LPARCountA++; } foreach $item (sort keys %vioB) { $LPARCountB++; } if ($LPARCountA==$LPARCountB) { printf ("Ultraviolet: %-20s %-6s %-50s\n","Involved LPAR Count","PASS","The same number of of LPARS are involved on both VIO servers."); } else { printf ("Ultraviolet: %-20s %-6s %-50s\n","Involved LPAR Count","FAIL","The VIO servers have differing numbers of LPARs involved..$LPARCountA and $LPARCountB, respectively."); push (@problems,"The number of LPARs that have storage mapped to them differ in number between $vioA and $vioB." ); } @LPARsOnA=sort keys %vioA; @LPARsOnB=sort keys %vioB; $numValidLPARs=0; foreach $item (@LPARsOnA) { if (grep(/$item/,@LPARsOnB)) { $numValidLPARs++; } } if ($numValidLPARs==$LPARCountA) { printf ("Ultraviolet: %-20s %-6s %-50s\n","LPARs A to B","PASS","All LPARs mentioned on $vioA are present on $vioB."); } else { printf ("Ultraviolet: %-20s %-6s %-50s\n","LPARs A to B","FAIL","Not all LPARs mentioned on $vioA are present on $vioB."); push (@problems,"Not all LPARs mentioned on $vioA are present on $vioB." ); } $numValidLPARs=0; foreach $item (@LPARsOnB) { if (grep(/$item/,@LPARsOnA)) { $numValidLPARs++; } } if ($numValidLPARs==$LPARCountB) { printf ("Ultraviolet: %-20s %-6s %-50s\n","LPARs B to A","PASS","All LPARs mentioned on $vioB are present on $vioA."); } else { printf ("Ultraviolet: %-20s %-6s %-50s\n","LPARs B to A","FAIL","Not all LPARs mentioned on $vioB are present on $vioA."); push (@problems,"Not all LPARs mentioned on $vioB are present on $vioA." ); } ## ## Definition Test (status, backingDevice, physLoc, ID..) ## foreach $LPAR (@LPARsOnA) { foreach $vhost (keys $vioA{$LPAR}) { foreach $LUN (keys $vioA{$LPAR}{$vhost}) { if ($vioA{$LPAR}{$vhost}{$LUN}{ID} ne $vioB{$LPAR}{$vhost}{$LUN}{ID}) { push (@problems, "LUN Name-to-ID mismatch detected. ($LUN has a LUN ID of $vioA{$LPAR}{$vhost}{$LUN}{ID} on $vioA, but on $vioB it's $vioB{$LPAR}{$vhost}{$LUN}{ID})"); $LUNIDMatchTestFail=1; } if ($vioA{$LPAR}{$vhost}{$LUN}{backingDevice} ne $vioB{$LPAR}{$vhost}{$LUN}{backingDevice}) { push (@problems, "Backing device mismatch detected. ($LUN is $vioA{$LPAR}{$vhost}{$LUN}{backingDevice} on $vioA, but on $vioB it's $vioB{$LPAR}{$vhost}{$LUN}{backingDevice})"); $LUNBackingDeviceTestFail=1; } } } } if ($LUNIDMatchTestFail==0) { printf ("Ultraviolet: %-20s %-6s %-50s\n","LUN ID Match","PASS","LUN IDs match between $vioA and $vioB."); } else { printf ("Ultraviolet: %-20s %-6s %-50s\n","LUN ID Match","FAIL","LUN IDs don't match between $vioA and $vioB."); } if ($LUNBackingDeviceTestFail==0) { printf ("Ultraviolet: %-20s %-6s %-50s\n","Backing Device Match","PASS","Backing devices match between $vioA and $vioB."); } else { printf ("Ultraviolet: %-20s %-6s %-50s\n","Backing Device Match","FAIL","The hdisk enumeration is different between $vioA and $vioB."); } } sub reportAnyProblems() { print "Ultraviolet:\n"; print "Ultraviolet: Problems found:\n"; print "Ultraviolet:\n"; @problems=sort(@problems); foreach $item (@problems) { print "Ultraviolet: $item\n"; } } sub buildConfigHashes() { print "Ultraviolet: Sorting things out.."; foreach $item (@lsmapDumpA) { chomp ($item); $item=~s/\s+/ /g; @tempA=split(" ",$item); if ($tempA[0]=~/vhost/) { $vhost=$tempA[0]; $LPAR=$tempA[2]; $DEBUG && print "Ultraviolet: Discovered new vhost on $LPAR: $vhost\n"; } if ($tempA[0]=~/VTD/) { $LUNName=$tempA[1]; if ($LUNName=~/NO/) { $DEBUG && print "Ultraviolet: No LUNs are mapped to $vhost.\n"; } else { $vioA{$LPAR}{$vhost}{$LUNName}{ID}="Unknown"; $DEBUG && print "Ultraviolet: Found new LUN mapping for $vioA $vhost: $LUNName\n"; } } if ($tempA[0]=~/Status/) { $LUNStatus=$tempA[1]; $vioA{$LPAR}{$vhost}{$LUNName}{status}=$LUNStatus; $DEBUG && print "Ultraviolet: Status for this LUN is: $LUNStatus\n"; } if ($tempA[0]=~/LUN/) { $LUNID=$tempA[1]; $vioA{$LPAR}{$vhost}{$LUNName}{ID}=$LUNID; $DEBUG && print "Ultraviolet: LUN ID for for this LUN is: $LUNID\n"; } if ($tempA[0]=~/Backing/) { $backingDevice=$tempA[2]; $vioA{$LPAR}{$vhost}{$LUNName}{backingDevice}=$backingDevice; $DEBUG && print "Ultraviolet: Backing device for this LUN is $backingDevice.\n"; } if ($tempA[0]=~/Physloc/) { $LUNPhysLoc=$tempA[1]; $vioA{$LPAR}{$vhost}{$LUNName}{physLoc}=$LUNPhysLoc; $DEBUG && print "Ultraviolet: Physical location for this LUN is $LUNPhysLoc.\n"; } } print "..."; foreach $item (@lsmapDumpB) { chomp ($item); $item=~s/\s+/ /g; @tempB=split(" ",$item); if ($tempB[0]=~/vhost/) { $vhost=$tempB[0]; $LPAR=$tempB[2]; $DEBUG && print "Ultraviolet: Discovered new vhost on $LPAR: $vhost\n"; } if ($tempB[0]=~/VTD/) { $LUNName=$tempB[1]; if ($LUNName=~/NO/) { $DEBUG && print "Ultraviolet: No LUNs are mapped to $vhost.\n"; } else { $vioB{$LPAR}{$vhost}{$LUNName}{ID}="Unknown"; $DEBUG && print "Ultraviolet: Found new LUN mapping for $vioB $vhost: $LUNName\n"; } } if ($tempB[0]=~/Status/) { $LUNStatus=$tempB[1]; $vioB{$LPAR}{$vhost}{$LUNName}{status}=$LUNStatus; $DEBUG && print "Ultraviolet: Status for this LUN is: $LUNStatus\n"; } if ($tempB[0]=~/LUN/) { $LUNID=$tempB[1]; $vioB{$LPAR}{$vhost}{$LUNName}{ID}=$LUNID; $DEBUG && print "Ultraviolet: LUN ID for for this LUN is: $LUNID\n"; } if ($tempB[0]=~/Backing/) { $backingDevice=$tempB[2]; $vioB{$LPAR}{$vhost}{$LUNName}{backingDevice}=$backingDevice; $DEBUG && print "Ultraviolet: Backing device for this LUN is $backingDevice.\n"; } if ($tempB[0]=~/Physloc/) { $LUNPhysLoc=$tempB[1]; $vioB{$LPAR}{$vhost}{$LUNName}{physLoc}=$LUNPhysLoc; $DEBUG && print "Ultraviolet: Physical location for this LUN is $LUNPhysLoc.\n"; } } print "\n"; ##$DEBUG && print Dumper (\%vioB); ##$DEBUG && print "\n-----------------------------------------------------------\n"; ##$DEBUG && print Dumper (\%vioB); } sub vioCommand($$$) { my $cmdType=shift; my $vioServer=shift; my $cmdStr=shift; my $sshCmd=''; if ($cmdType=~/aix/i) { $sshCmd="echo \"$cmdStr\" | ioscli oem_setup_env"; } elsif ($cmdType=~/vio/i) { $sshCmd="ioscli $cmdStr"; } else { die ("Improper command type.\n"); } my @retvalue=`ssh padmin\@$vioServer '$sshCmd'`; chomp(@retvalue); return @retvalue; }