File SAPHanaSRTools.pm of Package SAPHanaSR.2773
#
#
# SAPHanaSRTools.pm
# (c) 2014 SUSE Linux Products GmbH
# (c) 2015 SUSE Linux GmbH
# Author: Fabian Herschel
# License: Check if we publish that under GPL v2+
# Version: 0.17.2016.02.16.1
#
##################################################################
package SAPHanaSRTools;
require Exporter;
use POSIX;
# TODO: PRIO2: Get it stric again
#use strict;
use Sys::Syslog;
use Sys::Hostname;
use File::Path;
my $VERSION="1.0";
my $newAttributeModel=0;
my $cibFile="";
use vars qw(@ISA @EXPORT @EXPORT_OK);
@ISA = qw(Exporter);
# Init immediately so their contents can be used in the 'use vars' below.
@EXPORT = qw(max get_nodes_online mysyslog max mysyslog get_nodes_online get_node_status get_sid_and_InstNr get_hana_attributes get_hana_sync_state get_number_primary check_node_status check_node_mode get_number_secondary get_host_primary get_host_secondary check_lpa_status check_all_ok host_attr2string get_lpa_by_host get_site_by_host print_attr_host print_host_attr set_new_attribute_model get_new_attribute_model get_number_HANA_standby get_HANA_nodes get_node_list set_cibFile insertAttribute);
# @EXPORT_OK = qw(max mysyslog get_nodes_online);
sub set_new_attribute_model()
{
$newAttributeModel=1;
}
sub set_cibFile($)
{
$cibFile=shift();
}
sub get_new_attribute_model()
{
return $newAttributeModel;
}
sub max {
# thanks to http://www.perlunity.de/perl/forum/thread_018329.shtml
my $a = shift;
my $b = shift;
return $a > $b ? $a : $b;
}
sub mysyslog ( $$$ ) {
my ($prio, $form, @param) = ( @_ );
syslog $prio, $form, @param;
}
sub get_nodes_online
{
my $rc=0;
my $match="Ok:\s+([0-9])\s+nodes online";
my $match="Ok:\s+([0-9]+)\s+nodes? online";
my $match="Ok: ([0-9]+) ";
# TODO: What, if cibFile must be used ...
open crm, "crm_mon -s |";
while (<crm>) {
if (/$match/) {
$rc=$1
}
}
close crm;
return $rc;
}
sub get_node_status($)
{
# typically returns online, standby or offline
my $result="offline";
my $node=shift;
open crm, "crm_mon -1 |";
#- case one offline/standby and one online
# Node fscs99: OFFLINE (standby)
# Online: [ fscs98 ]
#- case both standby
# Node fscs99: standby
# Node fscs98: standby
#- case one standby one online
# Node fscs99: standby
# Online: [ fscs98 ]
#- case both online
# Online: [ fscs98 fscs99 ]
while (<crm>) {
if ( /^Online:.*\s$node\s/ ) {
#printf("O: %s\n", $_);
$result="online";
} elsif ( /^Node\s+$node:\s+(\S+)/ ) {
#printf("N: %s: %s\n", $_, $1);
$result=tolower($1);
}
}
close crm;
return $result;
}
sub get_node_list()
{
# crm_node -l | awk '$3 == "member" { if ($2 != me) { print $2 }}'
my @nodes;
open crm, "crm_node -l |";
while (<crm>) {
if ( /\S+\s+(\S+)\s+member$/ ) {
push (@nodes, $1);
}
}
close crm;
return @nodes;
}
#
# works only, if ONE SAPinstance (here HANA) is installed on the cluster
#
sub get_sid_and_InstNr()
{
my $sid=""; my $Inr=""; my $noDAACount = 0; my $gotAnswer = 0;
my @sid_ino;
open ListInstances, "/usr/sap/hostctrl/exe/saphostctrl -function ListInstances|";
while (<ListInstances>) {
# try to catch: Inst Info : LNX - 42 - lv9041 - 740, patch 36, changelist 1444691
chomp;
if ( /^[^:]+:\s*(\w+)\s*-\s*(\w+)\s*-/ ) {
$gotAnswer = 1;
my $foundSID=$1;
my $foundINO=$2;
if ( $foundSID ne "DAA" ) {
$noDAACount++;
$sid=tolower($foundSID);
$Inr=$foundINO;
push @sid_ino, "$sid:$Inr";
}
}
# if ( $_ =~ /:\s+([A-Z][A-Z0-9][A-Z0-9])\s+-\s+([0-9][0-9])/ ) {
# $sid=tolower("$1");
# $Inr=$2;
}
close ListInstances;
#printf (" get_sid_and_InstNr: return (%s)\n", join(",", ( $sid, $Inr, $noDAACount, $gotAnswer )));
$sid=join(",", @sid_ino);
return ( $sid, $noDAACount, $gotAnswer );
}
my $table_title = "Host \\ Attr";
sub OLDget_hana_attributes($)
{
my $sid = shift;
open CIB, "cibadmin -Ql |";
while (<CIB>) {
chomp;
if ( $_ =~ /nvpair\s+id="status-([a-zA-Z0-9]+)-\w+"\s+name="(\w+_${sid}_\w+)"\s+value="([^"]+)"/ ) {
my ($host, $name, $value) = ( $1, $2, $3 );
#
# handle the hosts name and table-title
#
$Host{$host}->{$name}=${value};
if ( defined ($HName{_hosts}->{_length})) {
$HName{_hosts}->{_length} = max($HName{_hosts}->{_length}, length($host ));
} else {
$HName{_hosts}->{_length} = length($host );
}
$HName{_hosts}->{_length} = max($HName{_hosts}->{_length}, length( $table_title));
#
# now handle the attributes name and value
#
$HName{$name}->{$host}=${value};
if ( defined ($HName{$name}->{_length})) {
$HName{$name}->{_length} = max($HName{$name}->{_length}, length($value ));
} else {
$HName{$name}->{_length} = length($value );
}
if ( $name =~ /hana_${sid}_(.*)/ ) {
$HName{$name}->{_title} = $1;
} else {
$HName{$name}->{_title} = $name;
}
$HName{$name}->{_length} = max($HName{$name}->{_length}, length( $HName{$name}->{_title}));
}
}
close CIB;
return 0;
}
sub insertAttribute($$$$$$) {
my ($sid, $refHash, $refN, $object, $attribute, $value) = @_;
my $table_titleH="";
if ( $attribute =~ /hana_${sid}_(.*)/ ) {
$attribute = $1;
}
#
# handle the hosts name and table-title
#
$$refHash{$object}->{$attribute}=${value};
if ( defined ($$refN{_hosts}->{_length})) {
$$refN{_hosts}->{_length} = max($$refN{_hosts}->{_length}, length($object ));
} else {
$$refN{_hosts}->{_length} = length($object );
}
$$refN{_hosts}->{_length} = max($$refN{_hosts}->{_length}, length( $table_titleH));
#
# now handle the attributes name and value
#
$$refN{$attribute}->{$object}=${value};
# $$refN{$attribute}->{$object}=${value};
if ( defined ($$refN{$attribute}->{_length})) {
$$refN{$attribute}->{_length} = max($$refN{$attribute}->{_length}, length($value ));
} else {
$$refN{$attribute}->{_length} = length($value );
}
$$refN{$attribute}->{_title} = $attribute;
$$refN{$attribute}->{_length} = max($$refN{$attribute}->{_length}, length( $$refN{$attribute}->{_title}));
# printf "%-8s %-20s %-30s\n", $1, $2, $3;
}
################
sub get_hana_attributes($)
{
my $sid = shift;
my $SID = uc($sid);
if ( $cibFile eq "" ) {
open CIB, "cibadmin -Ql |";
} else {
open CIB, "<$cibFile";
}
while (<CIB>) {
chomp;
my ($host, $name, $site, $value);
if ( $_ =~ /nvpair.*name="([a-zA-Z0-9\_\-]+_${sid}_([a-zA-Z0-9\-\_]+))"/ ) {
$name=$1;
if ( $_ =~ /id=.(status|nodes)-([a-zA-Z0-9\_\-]+)-/ ) {
# found attribute in nodes forever and reboot store
$host=$2;
if ( $_ =~ /value="([^"]+)"/ ) {
$value=$1;
# printf "insert $sid HOST $host $name $value\n";
insertAttribute($sid, \%Host, \%HName, $host, $name, $value);
}
} elsif ( $_ =~ /id=.SAPHanaSR-[a-zA-Z0-9\_\-]+_site_[a-zA-Z0-9\-]+_([a-zA-Z0-9\_\-]+)/) {
# found a site attribute
$site=$1;
if ( $name =~ /[a-zA-Z0-9\_\-]+_site_([a-zA-Z0-9\-]+)/ ) {
$name = $1;
}
if ( $_ =~ /value="([^"]+)"/ ) {
$value=$1;
#printf "insert $sid SITE $site $name $value\n";
insertAttribute($sid, \%Site, \%SName, $site, $name, $value);
}
} elsif ( $_ =~ /id=.SAPHanaSR-[a-zA-Z0-9\_\-]+_glob_[a-zA-Z0-9\_\-]+/) {
# found a global attribute
$host="GLOBAL";
if ( $name =~ /([a-zA-Z0-9\_\-]+)_glob_([a-zA-Z0-9\_\-]+)/ ) {
$name = $2;
}
if ( $_ =~ /value="([^"]+)"/ ) {
$value=$1;
#printf "insert $sid GLOB global $name $value\n";
insertAttribute($sid, \%Global, \%GName, "global", $name, $value);
}
} elsif ( $_ =~ /nvpair.*name="master.([a-zA-Z0-9\_\-]+_${SID}_([a-zA-Z0-9\-\_]+))"/ ) {
printf("DBG:%s\n", $_);
# lines with master scores:
# <nvpair id="status-suse05-master-rsc_SAPHanaCon_HA1_HDB10" name="master-rsc_SAPHanaCon_HA1_HDB10" value="150"/>
$name="score";
if ( $_ =~ /id=.status-([a-zA-Z0-9\_\-]+)-master/ ) {
# found attribute in nodes forever and reboot store
$host=$1;
if ( $_ =~ /value="([^"]+)"/ ) {
$value=$1;
# printf "insert $sid HOST $host $name $value\n";
insertAttribute($sid, \%Host, \%HName, $host, $name, $value);
}
}
}
}
}
close CIB;
return 0;
}
################
sub get_hana_sync_state($)
{
my $sid=shift;
my $result="";
if ( $newAttributeModel == 1 ) {
$result = $GName{sync_state}->{"global"};
} else {
my $h;
foreach $h ( keys(%{$HName{sync_state}}) ) {
if ( $HName{sync_state}->{$h} =~ /(S.*)/ ) {
$result=$1;
}
}
}
return $result;
}
sub get_number_primary($ $)
{
my $sid=shift;
my $lss=shift;
my $rc=0;
if ( $newAttributeModel == 1 ) {
my $s;
foreach $s ( keys(%{$SName{"srr"}}) ) {
if ( ( $SName{"srr"}->{$s} =~ /P/ ) && ( $SName{"lss"}->{$s} =~ /[$lss]/ )) {
$rc++;
}
}
} else {
my $h;
foreach $h ( keys(%{$HName{"roles"}}) ) {
if ( $HName{"roles"}->{$h} =~ /[$lss]:P:/ ) {
$rc++;
}
}
}
return $rc;
}
sub get_number_HANA_standby($$)
{
my $sid=shift;
my $site=shift;
my $standby=0;
if ( $newAttributeModel == 1 ) {
my $h;
foreach $h ( keys(%{$HName{"roles"}}) ) {
my $hSite=$HName{"site"}->{$h};
if ( $hSite eq $site ) {
my $role=$HName{"roles"}->{$h};
if ( $role =~ /:standby/ ) {
$standby++;
}
}
}
}
return $standby;
}
sub get_HANA_nodes($$)
{
my $sid=shift;
my $site=shift;
my @nodes;
if ( $newAttributeModel == 1 ) {
my $h;
foreach $h ( keys(%{$HName{"site"}}) ) {
my $hSite=$HName{"site"}->{$h};
if ( $hSite eq $site ) {
push (@nodes, $h);
}
}
}
return @nodes;
}
sub check_node_status($$$)
{
my $sid=shift;
my $lss=shift;
my $h=shift;
if ( $newAttributeModel == 1 ) {
my $site1=${$HName{"site"}}{$h};
if ( ${$SName{"lss"}}{$site1} =~ /^[$lss]/ ) {
return 1
}
} else {
if ( $HName{"roles"}->{$h} =~ /^[$lss]:.:/ ) {
return 1;
}
}
return 0;
}
sub check_node_mode($$$)
{
my $sid=shift;
my $mode=shift;
my $h=shift;
if ( $newAttributeModel == 1 ) {
my $site1=${$HName{"site"}}{$h};
if ( ${$SName{"srr"}}{$site1} =~ /^$srr/ ) {
return 1
}
} else {
if ( $HName{"roles"}->{$h} =~ /[0-9]:$mode:/ ) {
return 1;
}
}
return 0;
}
sub get_number_secondary($ $)
{
my $sid=shift;
my $lss=shift;
my $rc=0;
if ( $newAttributeModel == 1 ) {
my $s;
foreach $s ( keys(%{$SName{"srr"}}) ) {
if ( ( $SName{"srr"}->{$s} =~ /S/ ) && ( $SName{"lss"}->{$s} =~ /[$lss]/ )) {
$rc++;
}
}
} else {
my $h;
foreach $h ( keys(%{$HName{"roles"}}) ) {
if ( $HName{"roles"}->{$h} =~ /[$lss]:S:/ ) {
$rc++;
}
}
}
return $rc;
}
sub get_host_primary($ $)
{
my $sid=shift;
my $lss=shift;
my $result="";
if ( $newAttributeModel == 1 ) {
my $s;
foreach $s ( keys(%{$SName{"srr"}}) ) {
if ( ( $SName{"srr"}->{$s} =~ /P/ ) && ( $SName{"lss"}->{$s} =~ /[$lss]/ )) {
$result=$SName{"mns"}->{$s};
}
}
} else {
my $h;
foreach $h ( keys(%{$HName{"roles"}}) ) {
if ( $HName{"roles"}->{$h} =~ /[$lss]:P:/ ) {
$result=$h;
}
}
}
return $result;
}
sub get_host_secondary($ $)
{
my $sid=shift;
my $lss=shift;
my $result="";
if ( $newAttributeModel == 1 ) {
my $s;
foreach $s ( keys(%{$SName{"srr"}}) ) {
if ( ( $SName{"srr"}->{$s} =~ /S/ ) && ( $SName{"lss"}->{$s} =~ /[$lss]/ )) {
$result=$SName{"mns"}->{$s};
}
}
} else {
my $h;
foreach $h ( keys(%{$HName{"roles"}}) ) {
if ( $HName{"roles"}->{$h} =~ /[$lss]:S:/ ) {
$result=$h;
}
}
}
return $result;
}
sub get_site_by_host($ $)
{
my $result="";
my $sid=shift;
my $h = shift;
# print "get_site_by_host($sid, $h)";
$result = $HName{"site"}->{$h};
$result = $Host{$h}->{"site"};
return $result;
}
sub get_lpa_by_host($$)
{
my $result="";
my $sid=shift;
my $h = shift;
# print "get_site_by_host($sid, $h)";
if ( $newAttributeModel == 1 ) {
my $site1=${$HName{"site"}}{$h};
$result = ${$SName{"lpt"}}{$site1};
} else {
$result = ${$HName{"lpa_${sid}_lpt"}}{$h};
}
return $result;
}
my $check_lpa_msg="";
my $check_lpa_col="";
sub check_lpa_status($$$)
{
my $sid=shift;
my $node1=shift;
my $node2=shift;
my $lpaGAP="7200"; # TODO: Value must be fetched from the cluster
my $lpa_node1;
my $lpa_node2;
if ( $newAttributeModel == 1 ) {
my $site1=${$HName{"site"}}{$node1};
my $site2=${$HName{"site"}}{$node2};
#printf "check_lpa_status: site1=$site1 site2=$site2\n";
$lpa_node1=${$SName{"lpt"}}{$site1};
$lpa_node2=${$SName{"lpt"}}{$site2};
} else {
$lpa_node1=${$HName{"lpa_${sid}_lpt"}}{$node1};
$lpa_node2=${$HName{"lpa_${sid}_lpt"}}{$node2};
}
#printf "check_lpa_status: TEST lpa_node1=$lpa_node1 lpa_node2=$lpa_node2\n";
my $lpa_delta=abs($lpa_node1 - $lpa_node2);
my $lpa_wait=($lpaGAP - $lpa_delta);
if ( (! defined $lpa_node1) || (! defined $lpa_node2)) {
$check_lpa_msg= "LPA GAP - WAIT because LPA status of one node is missing";
$check_lpa_col="red";
} elsif (($lpa_node1<1000) && ($lpa_node2<1000) && ($lpa_node1 != $lpa_node2)) {
$check_lpa_msg= "Both LPAs in 'special' number range";
$check_lpa_col="yellow";
} elsif (($lpa_node1<1000) && ($lpa_node2<1000) && ($lpa_node1 == $lpa_node2)) {
$check_lpa_msg= "Collision!! Both LPAs in 'special' number range";
$check_lpa_col="red";
} elsif (($lpa_node1>1000) && ($lpa_node2>1000) && ($lpa_delta < $lpaGAP)) {
$check_lpa_msg= "Collision!! LPA GAP - WAIT $lpa_wait seconds";
$check_lpa_col="red";
} elsif (($lpa_node1>1000) && ($lpa_node2>1000) && ($lpa_delta >= $lpaGAP)) {
$check_lpa_msg= "Collision!! LPA GAP PASSED - Check, if AUTOMATIC REGISTRATION is active or register crashed primary manually";
$check_lpa_col="yellow";
} else {
$check_lpa_msg= "LPA: GREEN";
$check_lpa_col="green";
}
return ( $check_lpa_col, $check_lpa_msg);
}
sub check_all_ok($$)
{
my $sid=shift;
my $ClusterNodes=shift;
my $rc=0;
my $failed="";
my $result;
$result=get_nodes_online;
if ( $result != $ClusterNodes ) {
$rc++;
$failed .= " #N=$result";
}
$result=get_hana_sync_state($sid);
#printf "get_hana_sync_state($sid): %s\n", get_hana_sync_state($sid);
if ( $result ne "SOK" ) {
$rc++;
$failed .= " sync=$result ";
}
$result=get_number_primary($sid, "34");
if ( $result != 1 ) {
$rc++;
$failed .= " #P=$result ";
}
$result=get_number_secondary($sid, "34");
if ( $result != 1 ) {
$rc++;
$failed .= " #S=$result ";
}
return ($rc, $failed);
}
sub host_attr2string()
{
my $string;
my ($AKey, $HKey, $len, $line_len, $hclen);
$hclen=$HName{_hosts}->{_length};
$line_len=$hclen+1;
$string .= sprintf "%-$hclen.${hclen}s ", "$table_title";
foreach $AKey (sort keys %HName) {
if ($AKey ne "_hosts") {
$len = $HName{$AKey}->{_length};
$line_len=$line_len+$len+1;
$string .= sprintf "%-$len.${len}s ", $HName{$AKey}->{_title};
}
}
$string .= sprintf "\n";
$string .= sprintf "%s\n", "-" x $line_len ;
foreach $HKey (sort keys %Host) {
$string .= sprintf "%-$hclen.${hclen}s ", $HKey;
foreach $AKey (sort keys %HName) {
if ($AKey ne "_hosts") {
$len = $HName{$AKey}->{_length};
$string .= sprintf "%-$len.${len}s ", $Host{$HKey} -> {$AKey};
}
}
$string .= sprintf "\n";
}
return $string;
}
sub print_attr_host()
{
my ($HKey, $AKey);
printf "%-22s", "Attribute \\ Host";
foreach $HKey (sort keys %Host) {
printf "%-16s ", $HKey;
}
printf "\n";
printf "%s\n", "-" x 120 ;
foreach $AKey (sort keys %HName) {
printf "%-22s", $AKey;
foreach $HKey (sort keys %Host) {
printf "%-16.16s ", $Host{$HKey} -> {$AKey};
}
printf "\n";
}
return 0;
}
sub OLD_print_host_attr()
{
my ($AKey, $HKey, $len, $line_len, $hclen);
$hclen=$HName{_hosts}->{_length};
$line_len=$hclen+1;
printf "%-$hclen.${hclen}s ", "$table_title";
foreach $AKey (sort keys %HName) {
if ($AKey ne "_hosts") {
$len = $HName{$AKey}->{_length};
$line_len=$line_len+$len+1;
printf "%-$len.${len}s ", $HName{$AKey}->{_title};
}
}
printf "\n";
printf "%s\n", "-" x $line_len ;
foreach $HKey (sort keys %Host) {
printf "%-$hclen.${hclen}s ", $HKey;
foreach $AKey (sort keys %HName) {
if ($AKey ne "_hosts") {
$len = $HName{$AKey}->{_length};
printf "%-$len.${len}s ", $Host{$HKey} -> {$AKey};
}
}
printf "\n";
}
return 0;
}
sub print_host_attr($$$$)
{
my ($refH, $refN, $title, $sort) = @_;
my ($AKey, $HKey, $len, $line_len, $hclen);
$hclen=$$refN{_hosts}->{_length};
$line_len=$hclen+1;
printf "%-$hclen.${hclen}s ", "$title";
#
# headline
#
foreach $AKey (sort keys %$refN) {
if ($AKey ne "_hosts") {
$len = $$refN{$AKey}->{_length};
$line_len=$line_len+$len+1;
if ( $AKey eq $sort ) {
printf "*%-$len.${len}s ", $$refN{$AKey}->{_title};
} else {
printf "%-$len.${len}s ", "$$refN{$AKey}->{_title}";
}
}
}
printf "\n";
printf "%s\n", "-" x $line_len ;
#
# object / name / value lines
#
if ( $sort eq "" ) {
foreach $HKey (sort keys %$refH) {
printf "%-$hclen.${hclen}s ", $HKey;
foreach $AKey (sort keys %$refN) {
if ($AKey ne "_hosts") {
$len = $$refN{$AKey}->{_length};
printf "%-$len.${len}s ", $$refH{$HKey} -> {$AKey};
}
}
printf "\n";
}
} else {
# try to sort by site (other attrs to follow)
# first try to get a ordered list of attribute values assigned host names
my $sortV;
my %GroupedHosts;
foreach $HKey (sort keys %$refH) {
$sortV = $$refH{$HKey} -> {$sort};
push(@{$GroupedHosts{$sortV}}, $HKey);
#printf "TST: <%s>\n", $sortV;
}
# not ready so far only print the grouped hosts
foreach $sortV (sort keys %GroupedHosts) {
#my $StrHosts;
#$StrHosts=join(":", @{$GroupedHosts{$sortV}});
my $Host;
foreach $Host (@{$GroupedHosts{$sortV}}) {
printf "%-$hclen.${hclen}s ", $Host;
foreach $AKey (sort keys %$refN) {
if ($AKey ne "_hosts") {
$len = $$refN{$AKey}->{_length};
printf "%-$len.${len}s ", $$refH{$Host} -> {$AKey};
}
}
printf "\n";
}
#printf "TST: <%s> -> <%s>\n", $sortV, $StrHosts;
}
}
printf "\n";
return 0;
}
#
################ END CUT - MOVE THAT TO AN PERL-LIBRARY LATER
#
1;