File: //var/opt/OV/bin/instrumentation/OvCluster.pm
###############################
#
# HP Operations Smart Plug-ins for Infrastructure 11.14.014 06/07/14
#
###############################
package OvCluster;
my $catalog = OvCommon::GetCatalog(qw/ClusterPerl/);
use DiscoverResult;
use OvTrace;
use Data::Dumper;
use File::Path;
use Fcntl qw(:flock);
use Encode;
sub new
{
my $class = shift;
my $self = {};
$self->{CLUSTYPE} = ();
$self->{CLUSNAME} = ();
$self->{CLUSSTATUS} = ();
$self->{NODE} = ();
$self->{RG} = ();
$self->{DR} = DiscoverResult->new;
$self->{TRACE} = OvTrace->new("OvCluster",,,);
bless ($self, $class);
return $self;
}
sub discoverCluster
{
my $self = shift;
my $clusthashref = shift;
my %clusthash = %$clusthashref;
$self->{CLUSTYPE} = $clusthash{type};
$self->{CLUSNAME} = $clusthash{name};
$self->{CLUSSTATUS} = $clusthash{status};
}
sub discoverClusterMember
{
my $self = shift;
my $nodehashref = shift;
my %nodehash = %$nodehashref;
my %thisnode = {};
$thisnode{"nodename"} = OvCommon::getFQDN($nodehash{"Node"});
$thisnode{"nodestate"} = $nodehash{"state"};
$thisnode{"nodeid"} = $nodehash{"id"};
push (@nodearray, \%thisnode);
$self->{NODE} = \@nodearray;
}
sub discoverRG
{
my $self = shift;
my $rghashref = shift;
my %rghash = %$rghashref;
my %thisrg = {};
$thisrg{"rgname"} = $rghash{"Group"};
$thisrg{"rgstate"} = $rghash{"state"};
$thisrg{"rglocalstate"} = $rghash{"local state"};
$thisrg{"rgnodes"} = $rghash{"nodes"};
$thisrg{"rgvirtualip"} = OvCommon::getFQDN($rghash{"virtual IP"});
if ($rghash{"active node"} ne "") {
$thisrg{"rgactivenode"} = OvCommon::getFQDN($rghash{"active node"});
} else {
$thisrg{"rgactivenode"} = "none";
}
$thisrg{"rgvirtualip"} = OvCommon::getFQDN($rghash{"virtual IP"});
push (@rgarray, \%thisrg);
$self->{RG} = \@rgarray;
}
sub getClusterInfo
{
my $self = shift;
if ($^O eq qw/MSWin32/)
{
#get windows current codepage
my $WinCurrentEncoding="";
my $WinTargetEncoding="utf8";
open (CPDATA, "chcp |");
while (<CPDATA>)
{
chomp;
my @cp_val = split(': ', $_);
# Windows code pages for Japenese (simplified)
if($cp_val[$#cp_val] == 932)
{
$WinCurrentEncoding="shiftjis";
}
# Windows code pages for Chinese (simplified)
elsif ($cp_val[$#cp_val] == 936)
{
$WinCurrentEncoding="cp936";
}
# Windows code pages for Chinese (Traditional)
elsif ($cp_val[$#cp_val] == 950)
{
$WinCurrentEncoding="cp950";
}
}
close (CPDATA);
$self->getClusterInfoEx($WinCurrentEncoding,$WinTargetEncoding);
}
else
{
$self->getClusterInfoEx("","");
}
}
sub getClusterInfoEx
{
my $self = shift;
my $decodefrom = shift;
my $encodeto = shift;
my $datadir = OvCommon::GetDataDir();
my $cispi_path=$datadir."conf/cispi/";
my $cispi_cfg = $cispi_path."/cispi.cfg";
my $SEMAPHORE_CFG = $cispi_cfg.'.lck';
my $SEMAPHORE_PIPE = $cispi_path."/ovclusterinfo".'.lck';
# Set # as record separator
local $/ = "\n#";
local @nodearray=();
local @rgarray=();
my $traceObj = $self->{TRACE};
open(SP,">$SEMAPHORE_PIPE") or warn $!;
flock(SP,LOCK_EX) or warn "flock() failed for $SEMAPHORE_PIPE: $!";
if (!defined(open (OVCLUSTERINFODUMP, "ovclusterinfo -a |")))
{
$traceObj-> SendOpcmsg ("CISPI", "Cluster Info", "Error(s) running ovclusterinfo: ".$!, "major");
close SP;
exit;
}
my @Parentsections = <OVCLUSTERINFODUMP>;
close (OVCLUSTERINFODUMP);
close SP;
foreach (@Parentsections)
{
my %cur_hash = ();
my $class = undef;
#print "The line is $_ \n";
my @sections = split (/\n/, $_);
foreach my $line (@sections)
{
if ($line)
{
chomp;
if (defined $encodeto && $encodeto ne '' && defined $decodefrom && $decodefrom ne '')
{
$line=Encode::encode($encodeto,Encode::decode($decodefrom,$line));
}
if ($line =~ /^#Cluster/)
{
$class = "Cluster";
%cur_hash = ();
}
elsif ($line =~ /^Node\s(.*)/)
{
$class = "Node";
%cur_hash = ();
$cur_hash{'Node'} = $1;
}
elsif ($line =~ /^Group\s(.*)/)
{
$class = "Group";
%cur_hash = ();
$cur_hash{'Group'} = $1;
}
my @temparray = split (/ +/, $line, 2);
$cur_hash{"$temparray[0]"} = $temparray[1];
}
}
#Initiate discovery of cluster & cluster memebers.
if ($class eq qw/Cluster/)
{
$self->discoverCluster(\%cur_hash);
# Record cluster info(clustername, clustertype) first time around in cispi.cfg file!
if ( $cur_hash{status} eq "Up" )
{
if ( !-d $cispi_path )
{
&File::Path::mkpath ($cispi_path, 0, 02755);
my ($uid, $gid) = (getpwnam(qw/bin/))[2,3] if ($^O ne qw/MSWin32/);
chown ($uid, $gid, $cispi_path) if ($uid);
}
open(SC,">$SEMAPHORE_CFG") or warn $!;
flock(SC,LOCK_EX) or warn "flock() failed for $SEMAPHORE_CFG: $!";
open(CLUSCFGFILE, ">$cispi_cfg") or warn "Cannont open the config file: $!";
print CLUSCFGFILE "$cur_hash{name}:$cur_hash{type}\n";
close CLUSCFGFILE;
close SC;
}
}
elsif ($class eq qw/Node/)
{
$self->discoverClusterMember(\%cur_hash);
}
elsif ($class eq qw/Group/)
{
$self->discoverRG(\%cur_hash);
}
}
return 0;
}
sub genTopXml
{
my $self = shift;
my $dr = $self->{DR};
# define ClusterInfrastructure element - do not create service
$dr->DefineInstance ("hCI","HAClusterInfrastructure",true);
$dr->DefineInstance ("hCV","Class_ClusterVendor",true); # true - virtual
$dr->AddAttr("hCV", "vendor", $self->{CLUSTYPE});
# create top-level service and child relationship to ClusterInfrastructure
$dr->CreateService ("hCV");
$dr->CreateComponent("hCI", "hCV");
# create element pertaining to Cluster
$dr->DefineInstance ("hCluster","Class_HACluster",true); # true - virtual
# both attributes hCluster are required here
$dr->AddAttr("hCluster", "clustername", $self->{CLUSNAME});
$dr->AddAttr("hCluster", "status", $self->{CLUSSTATUS});
$dr->AddAttr("hCluster", "vendor", $self->{CLUSTYPE});
# set parent for hCluster element as hCV name
$dr->CreateService ("hCluster");
$dr->CreateComponent("hCV", "hCluster");
}
sub genErrXml
{
}
sub dispXml
{
my $self = shift;
my $dr = $self->{DR};
$dr->OutputResult;
}
sub genClusterMemberXml
{
my $self = shift;
my $dr = $self->{DR};
# create the ClusterNode Collection Element
$dr->DefineInstance("hClusterMemberCollection", "Class_HAMemberCollection", true);
$dr->AddAttr("hClusterMemberCollection", "clustername", $self->{CLUSNAME});
$dr->AddAttr("hClusterMemberCollection", "vendor", $self->{CLUSTYPE});
$dr->CreateService("hClusterMemberCollection");
$dr->CreateComponent("hCluster", "hClusterMemberCollection");
my @nodearray = @{ $self->{NODE} };
my $product_name;
foreach my $node (@nodearray) {
$dr->DefineInstance("hClusterMember".$node->{"nodename"}, "Class_HAMember", false, $node->{"nodename"});
$dr->AddAttr("hClusterMember".$node->{"nodename"}, "membername", $node->{"nodename"});
$dr->AddAttr("hClusterMember".$node->{"nodename"}, "id", $node->{"nodeid"});
$dr->AddAttr("hClusterMember".$node->{"nodename"}, "memberstate", $node->{"nodestate"});
$dr->AddAttr("hClusterMember".$node->{"nodename"}, "clustername", $self->{CLUSNAME});
$dr->AddAttr("hClusterMember".$node->{"nodename"}, "vendor", $self->{CLUSTYPE});
if ($self->{CLUSTYPE} =~ /^Microsoft.*/i)
{
$product_name = "microsoft_cluster";
}
elsif ($self->{CLUSTYPE} =~ /^MC.*/i)
{
$product_name = "service_guard_cluster";
}
elsif ($self->{CLUSTYPE} =~ /^VERITAS.*/i)
{
$product_name = "veritas_cluster";
}
elsif ($self->{CLUSTYPE} =~ /^Red.*/i)
{
$product_name = "redhat_cluster";
}
elsif ($self->{CLUSTYPE} =~ /^AIX.*/i)
{
$product_name = "ibm_hacmp_cluster";
}
elsif ($self->{CLUSTYPE} =~ /^SUN.*/i)
{
$product_name = "sun_cluster";
}
else
{
$product_name = "unknown";
}
$dr->AddAttr("hClusterMember".$node->{"nodename"}, "productname", $product_name);
$dr->CreateService("hClusterMember".$node->{"nodename"});
$dr->CreateComponent("hClusterMemberCollection","hClusterMember".$node->{"nodename"});
$dr->DefineInstance ("hNode".$node->{"nodename"},"Class_NodeSystem",false, $node->{"nodename"}, "SI@@");
$dr->CreateDependent("hClusterMember".$node->{"nodename"}, "hNode".$node->{"nodename"});
}
}
sub genRGXml
{
my $self = shift;
my $dr = $self->{DR};
# create the ClusterRG Collection Element
$dr->DefineInstance("hClusterRGCollection", "Class_RGCollection", true);
$dr->AddAttr("hClusterRGCollection", "clustername", $self->{CLUSNAME});
$dr->AddAttr("hClusterRGCollection", "vendor", $self->{CLUSTYPE});
$dr->CreateService("hClusterRGCollection");
$dr->CreateComponent("hCluster","hClusterRGCollection");
my @rgarray = @{ $self->{RG} };
my $rg_names;
my $rg_name;
foreach my $rg (@rgarray) {
if ($rg->{rgvirtualip} !~ /None/) {
$dr->DefineInstance("hClusterRG".$rg->{"rgname"}, "Class_RG", false, $rg->{rgvirtualip}); # false - hosted-on
} else {
# ($sRef, $Std, $Virtual, $Guid, $Key, $GraphID, $attrs)
# key for non-hosted RG's (without Virtual IP) is CI:<ClusterName>:<RGName> - virtual service
$dr->DefineInstance("hClusterRG".$rg->{"rgname"}, "Class_RG", true, "", "CI:".$self->{CLUSNAME}.":".$rg->{"rgname"}); # virtual service
}
$dr->AddAttr("hClusterRG".$rg->{"rgname"}, "rgname", $rg->{"rgname"});
$dr->AddAttr("hClusterRG".$rg->{"rgname"}, "rglocalstate", $rg->{"rglocalstate"});
$dr->AddAttr("hClusterRG".$rg->{"rgname"}, "rgstate", $rg->{"rgstate"});
#$rg->{"rgnodes"} eg: tcpc096 tcpc097
$rg_names = $rg->{"rgnodes"};
$rg_name = undef;
map{ $rg_name .= " " . OvCommon::getFQDN($_); } split(/ /,$rg_names);
$rg->{"rgnodes"} = $rg_name;
$dr->AddAttr("hClusterRG".$rg->{"rgname"}, "rgnodes", $rg->{"rgnodes"});
$dr->AddAttr("hClusterRG".$rg->{"rgname"}, "activenode", $rg->{"rgactivenode"});
$dr->AddAttr("hClusterRG".$rg->{"rgname"}, "rgvirtualip", $rg->{"rgvirtualip"});
$dr->AddAttr("hClusterRG".$rg->{"rgname"}, "dynamicrgtype", eval {my $z = `ovxplmsg -c $catalog -m 23 -t "Resource Group"`;$z =~ s/\\x22/\x22/g;$z =~ s/\\x25/\x25/g;$z =~ s/\\x27/\x27/g;$z =~ s/\\\\/\\/g;$z =~ s/\\\$/@%@%@/g;$z =~ s/(\$[\w_!?]+[\[\{][\w_!?\$]+[\]\}])/$1/eeg;$z =~ s/(\$[\w_!?^]+)/$1/eeg;$z =~ s/@%@%@/\$/g;$z =~ s/\\x24/\x24/g;chomp($z);return($z);});
$dr->AddAttr("hClusterRG".$rg->{"rgname"}, "clustername", $self->{CLUSNAME});
$dr->AddAttr("hClusterRG".$rg->{"rgname"}, "vendor", $self->{CLUSTYPE});
$dr->CreateService("hClusterRG".$rg->{"rgname"});
$dr->CreateComponent("hClusterRGCollection","hClusterRG".$rg->{"rgname"});
$dr->CreateDependent("hClusterRG".$rg->{"rgname"}, "hClusterMember".$rg->{"rgactivenode"});
}
}
1;