#!/usr/bin/perl
############################################################################
#
# sap_cluster_connector
# Authors:
#   Fabian Herschel
#   Frank Danapfel
#   Andrew Beekhof
#   David Vossel
#
# License: GPLv2 or later
#
# based on:
# sap_suse_cluster_connector
# Author:  fabian.herschel@suse.com
# (c) 2010-2014 SUSE Linux Products GmbH, Nuremberg, Germany
# (c) 2015      SUSE Linux GmbH, Nuremberg, Germany
#
############################################################################
#
# REMARKS:
#    we need record pending activated to be able to catch pending actions
#    op_defaults $id="op_defaults-options" record-pending="true"
#
# TODOs:
#    TODO: testing, testing, testing
#    TODO: long cmd names (like check_pending_action)
#    TODO: Could we check for the record-pending option?
#    TODO: database instances -> lsr --sid SID --dbhost HOST --dbtype TYPE
#    TODO: all syslog messages also to developer trace log file
#

use Getopt::Long;
use Sys::Hostname;
use Sys::Syslog;
use strict;
use File::Temp qw/ tempfile tempdir /;
use File::Basename;

my $DEBUG; my $filename;
my $nowstring;
#
# init some environment 
#
my $scriptname = basename($0);
my $cmd_cibadmin = "cibadmin";
my $cmd_crm_resource = "crm_resource";
my $cmd_ptest = "crm_simulate";
my $cmd_crm_attribute = "crm_attribute";
my $logident = "$scriptname";
my $logoptions = "pid";
my $logfacility = "LOG_USER";
my $sysconfig = "/etc/sysconfig/$scriptname";
my $hacheckcmd = "/usr/share/$scriptname/run_checks";
# define defaults here that can be overridden by sysconfig file below
my $protocolVersion=3;
my $version="3.0.1";

#
# open syslog
#
openlog($logident, $logoptions, $logfacility);
my @all_cmds = ($cmd_cibadmin, $cmd_crm_resource, $cmd_ptest);

#	printf "ARGV: %s\n", join(" ", @ARGV);
sub usage() {
printf "$0 --help
$0 cmd options
      where cmd could be:  
      help 
      init
      gvi --out FILE
      hcc --out FILE --sid SID --ino INO
      lsr --out FILE --sid SID --ino INO
      lsn --out FILE --res RES
      cpa --res RES --act ACT
      fra --res RES --act ACT  [ --node NODE ]
      smm --out FILE --sid SID --ino INSTNO --mod NMODE
";
}

sub paramproblem() {
	syslog("LOG_ERR", "called with wrong parameters");
	usage();
	exit(2);
}

sub checkavail(@) {
	my @CHECK = @_;
	my $chk;
	my $rc=1;
	for $chk ( @CHECK ) {
		if ( ! ( defined ( $chk )))  {
			$rc=0;
		}
	}
	return $rc;
}

sub initial_check() {
	my $rc=0;
	#
	# move old log file to *.old in cwd which is /usr/sap/<SID>/<INST>/work
	#
	rename("$logident" . ".log", "$logident" . ".old");
	#
	# open new log file in cwd which is /usr/sap/<SID>/<INST>/work
        #
	#($DEBUG, $filename) = tempfile("sap_redhat_cluster_conector.XXXXX", SUFFIX => '.log');
	open($DEBUG, ">>$logident" . ".log");
	*STDOUT=*$DEBUG;
	printf "\n---------------------------------------------------\n";
	printf "trc file: %s\n", $logident . ".log";
	printf "---------------------------------------------------\n";
	$nowstring = localtime;
	printf "%s : init()\n", $nowstring;
	return $rc;
}

sub fire_resource_action {
	my ($rsc, $act, $nod) = @_;
	my $rc=0;
	$nowstring = localtime;
	printf "%s : fra($rsc, $act, $nod)\n", $nowstring;
	if (-r $sysconfig) {
		open SYSCONF, "<$sysconfig" or syslog("LOG_INFO", "open %s failed", $sysconfig);
		while (<SYSCONF>) {
			chomp;
			my $line = $_;
			#printf "%s...\n",  $line;
			if ($line =~ /BLOCK_RESOURCES=.*$rsc/) {
                   	syslog("LOG_INFO", "BLOCK INFO: fra call %s for resource %s blocked as defined in %s", $act, $rsc, $sysconfig);
		   	return 0;
			}	
        	}
		close SYSCONF;
	}	
	if ( $act eq "stop" ) {
		syslog("LOG_INFO", "fire_resource_action stop %s\n", $rsc);
		if (system($cmd_crm_resource,"-r",$rsc,"-m","-p","target-role","-v","Stopped")) { $rc=1; }
	} elsif ( $act eq "start" ) {
		syslog("LOG_INFO","fire_resource_action start %s\n", $rsc);
		if (system($cmd_crm_resource,"-r",$rsc,"-m","-d","target-role") ) { $rc=1; }
	} elsif ( $act eq "migrate" ) {
		if ( (defined $nod) && !($nod eq '') ) {
			syslog("LOG_INFO", "fire_resource_action migrate %s to node %s\n", $rsc, $nod);
			if (system($cmd_crm_resource,"-r",$rsc,"-M","-N",$nod,"-u","PT5M","-f") ) { $rc=1; }
		} else {
			syslog("LOG_INFO", "fire_resource_action migrate %s\n", $rsc);
                        if (system($cmd_crm_resource,"-r",$rsc,"-M","-u","PT5M","-f") ) { $rc=1; }
                }
	}
	syslog("LOG_INFO"," rc=%i\n", $rc);
	return $rc;
}

sub check_pending_action {
	my ($res, $act, $sta) = @_;
	my $rc=0;
	my $found=0;
	$nowstring = localtime;
	printf "%s : cpa($res, $act, $sta)\n", $nowstring;
	#
	# rc:
	#     0: found
	#     1: not found
        #     2: internal error
	$rc=1;
	#    
	# rsc_ip_NA1_sapna1as     (ocf::heartbeat:IPaddr2) Started : rsc_ip_NA1_sapna1as_start_0 (node=node0101, call=16, rc=0): complete
        # rsc_sap_NA1_ASCS00_sapna1as:0   (ocf::heartbeat:SAPInstance) Stopped : rsc_sap_NA1_ASCS00_sapna1as:0_monitor_0 (node=node0102, call=11, rc=7): complete
        # rsc_sap_NA1_ASCS00_sapna1as:0   (ocf::heartbeat:SAPInstance) Slave : rsc_sap_NA1_ASCS00_sapna1as:0_start_0 (node=node0101, call=-1, rc=14): pending
        # rsc_sap_NA1_ASCS00_sapna1as:0   (ocf::heartbeat:SAPInstance) Master : rsc_sap_NA1_ASCS00_sapna1as:0_demote_0 (node=node0101, call=-1, rc=14): pending
        # rsc_sap_HA0_D02 (ocf::heartbeat:SAPInstance) Started  FAILED: rsc_sap_HA0_D02_start_0 (node=cl2n01, call=-1, rc=14): pending<---- FOUND!!
        #
	#    crm_resource -O -r $rsc | grep "${rsc}_${act}_.*: ${sta}"  && rc=0
	#open CRMOUT, "$cmd_crm_resource -O -r $res 2>/dev/null |" or $rc=2;
	open CRMOUT, "$cmd_crm_resource -O 2>/dev/null |" or $rc=2;
	#printf "<--------- cpa ------>\n";
	while (<CRMOUT>) {
		chomp;
		my $line = $_;
		#printf "%s", $line;
		# if ( $line =~ /${res}_${act}_.*: ${sta}/ ) { # FH 2012-01-05: Changed to find also clones and master-slaves
		#if ( $line =~ /${res}(:[0-9]+_|_)${act}_.*: ${sta}/ ) {
		#if ( $line =~ /${res}.*: ${sta}/ ) {
		my ${masteract};
		if ( ${act} eq "stop" ) {
			$masteract="demote";
		} elsif ( ${act} eq "start" ) {
                        $masteract="promote";
                }
		#if ( $line =~ /(${res}(:[0-9]+)?_(${act}|${masteract})_0.*: ${sta})/ ) {
		if ( $line =~ /(${res}(:[0-9]+)?_(${act}|demote|promote)_0.*: ${sta})/ ) {
			$rc=0;
			syslog("LOG_INFO","Pending action %s for %s found", $1, ${res});
			#printf "<---- FOUND!!";
		}
		#printf "\n";
	}
        close CRMOUT;
	if ( $rc != 0 ) {
           open CRMOUT, "$cmd_crm_resource --resource ${res} --get-parameter target-role --meta 2>/dev/null |" or $rc=2;
           while (<CRMOUT>) {
                chomp;
                my $line = $_;
                printf "%s", $line;
		if ( (${act} eq "stop") && ( $line =~ "Stopped" )) {
			syslog("LOG_INFO","target-role stopped for resource %s found", ${res});
			$rc=0;
		}
		if ( (${act} eq "start") && ( $line =~ "Started" )) {
			syslog("LOG_INFO","target-role started for resource %s found", ${res});
			$rc=0;
		}
	   }
        }
	close CRMOUT;
        #
        #### BY_PASS_CODE
        #if ( $rc != 0 ) { 
	#	syslog("LOG_INFO","SENDING PENDING ACTION FOUND TO DEBUG");
	#	$rc=0;
        #}
	#printf "</--------- cpa ------>\n";
	return $rc;
}

sub get_resource_from_sid_ino {
	#
	# --sid sid --ino ino
	#
	my ($sid, $ino) = @_;
	my $rc=2;
	$nowstring = localtime;
	printf "%s : get_resource_from_sid_ino($sid, $ino)\n", $nowstring;

	my ($sclass, $sprovider, $sra, $sparam, $sparam2 ) = ("ocf", "heartbeat", "SAPInstance", "InstanceName", "ERS_InstanceName");

	$ENV{'PATH'} = $ENV{'PATH'} . ":/usr/sbin:/sbin";

	my ($fclass, $fprovider, $fra, $fname, $fgname) = ("","","","","");
	my $foundRes = 0; # found correct Resource

	open CRMOUT, "$cmd_cibadmin --local -Q --xpath '//primitive[\@type=\"$sra\"]' --node-path 2>/dev/null |" || die "could not open cibadmin output";
	while (<CRMOUT>) {
		my $line = $_;
		if ($line =~ /primitive..id='([a-zA-Z0-9_-]+)'/) {
			($fname) = ($1);
		} else {
			next;
		}

		if ( $line =~ /[group|master|clone]..id='([a-zA-Z0-9_-]+)'/) {
			($fgname) = ($1);
		}
		# Check for InstanceName
		if ($foundRes==0) {
			open RESOURCE1_OUT, "$cmd_cibadmin -Q --xpath \"//primitive[\@id='$fname']//nvpair[\@name='$sparam']\"  2>/dev/null |" || die "could not open cibadmin output";
			while (<RESOURCE1_OUT>) {
				my $result = $_;
				if ($result =~ /value="([a-zA-Z0-9_-]+)"/) {
					my $finstance=$1;
					if ( $1 =~ /^${sid}_[a-zA-Z0-9]+${ino}_[a-zA-Z0-9_-]+$/ ) {
						$foundRes=1;
						syslog("LOG_DEBUG","Resource %s with %s=%s found\n", $fname, $sparam, $finstance);
					}
				}
			}
		}
		# Check for ERS_InstanceName
		if ($foundRes==0) {
			open RESOURCE2_OUT, "$cmd_cibadmin -Q --xpath \"//primitive[\@id='$fname']//nvpair[\@name='$sparam2']\"  2>/dev/null |" || die "could not open cibadmin output";
			while (<RESOURCE2_OUT>) {
				my $result = $_;
				if ($result =~ /value="([a-zA-Z0-9_-]+)"/) {
					my $finstance=$1;
					if ( $1 =~ /^${sid}_[a-zA-Z0-9]+${ino}_[a-zA-Z0-9_-]+$/ ) {
						$foundRes=1;
						syslog("LOG_DEBUG","Resource %s with %s=%s found\n", $fname, $sparam2, $finstance);
					}
				}
			}
		}

		if ($foundRes == 1) {
			last;
		}
	}

	if ($foundRes==1) {
		return ($fname, $fgname);
	} else {
		syslog("LOG_INFO","get_resource_from_sid_ino result: empty\n");
	}

}

sub check_maintanance_mode {
	my ($res) = @_;
	my $retcode;
	$nowstring = localtime;
	printf "%s : check_maintenance_mode($res)\n", $nowstring;

	my $retcode = system("$cmd_crm_resource | grep -E \"\[\[:space:\]\]$res\[\[:space:\]\]\" | grep -q unmanaged");
	$retcode=$retcode >> 8;
	if ( $retcode eq "0" ) {
		syslog("LOG_INFO", "resource %s is in maintanance mode\n", $res);
	} else {
		syslog("LOG_INFO", "resource %s is not in maintanance mode\n", $res);
	}
	return $retcode;
}

sub list_sap_resources {
	#
	# --out file --sid sid --ino ino
	#
	my ($out, $sid, $ino) = @_;
	my $rc=2;
	$nowstring = localtime;
	printf "%s : lsr($out, $sid, $ino)\n", $nowstring;
	#
	# TODO: If a query for SID+InstNR returns multiple row  fire a error message (syslog and developer trace log)

	my ($fname, $fgname) = get_resource_from_sid_ino($sid, $ino);

	if ($fname ne "") {

		my $status = check_maintanance_mode($fname);
        	syslog("LOG_INFO", "check_maintenance_mode call (retcode=%s)", $status); 

		if ( $status eq "0" ) {
			# maintenance mode is active for resource
			$rc=3;
		} elsif ( $status eq "1" ) {
			# maintenance mode is not active for resource
			$rc=0;
		} else {
			# maintenance mode is divergent for resource
			$rc=2;
		}

		if ($out eq "") {
			printf "%s:%s:%s\n", $fname, $fgname, "-";
		} else {
			unless (open(OUT, '>',$out)) {
				print STDERR "Can't open $out: $!\n";
			}
			syslog("LOG_INFO","lsr result: %s:%s:%s:%s:%s\n", $sid, $ino, $fname, $fgname, "-");
			printf OUT "%s:%s:%s:%s:%s\n", $sid, $ino, $fname, $fgname, "-";
			close OUT;
		}

	} else {
		syslog("LOG_INFO","lsr result: empty\n");
		$rc=1;
	}

	# TODO: scores and node names sorted by scores -> use crm_simulate
	#
	#ls3198:/usr/lib/ocf/resource.d/heartbeat # crm_simulate -Ls | grep ls3199 | egrep '(rsc_SAPInstance_NA0_ASCS00_sapna0as|grp_sap_NA0)'
	#group_color: grp_sap_NA0 allocation score on ls3199: 0
	#group_color: rsc_SAPInstance_NA0_ASCS00_sapna0as allocation score on ls3199: 0
	#native_color: rsc_SAPInstance_NA0_ASCS00_sapna0as allocation score on ls3199: -INFINITY
	return $rc;
}

sub list_sap_nodes { 
	#
        # --out file --res RES
	#
	###########################################
	# return codes
	#   0: everything worked fine
	#   1:
	#   2: internal error
	#
	my ($outfile, $resource) = @_;
	my $rc=0;
	$nowstring = localtime;
	printf "%s : lsn($outfile, $resource)\n", $nowstring;
	# TODO: check implemented action
	###############################################################################################
	#
	# 1. GET HOSTNAME WHERE FUNCTION WAS CALLED
	#
	my $myhostname = hostname;
	#
	##########################
	#
	# 2. GET NODE NAME, WHERE RESOURCE IS CURRENTLY RUNNING
	#
	# to get the current location of the resource in the cluster, lets ask the cluster itself ;-)
	# we assume to get an answer in the following format:
	#
	# resource RES is running on: NODE
	#
	open CRMRES, "$cmd_crm_resource -W -r $resource|";
	my $crm_res_location_in = <CRMRES>;
	chomp $crm_res_location_in;
	#printf "DBG: where-result: %s\n", $crm_res_location_in;
	my $current_node="";
	if ( $crm_res_location_in =~ /^resource\s+(\w)+\sis running on:\s+(\w+)\W*/ ) {
		#printf "DBG: where-result: match\n";
		$current_node = $2;
	}
	close CRMRES;
	#
	##########################
	#
	# 3. GET ORDERED LIST OF CLUSTER NODES WHICH COULD RUN THE RESOURCE
	#
	my $node_list="";
	my %resource;
	open PTEST, "$cmd_ptest -Ls |" || return 2;
	#
	# we rely on the following format:
	#
	#   ...
	#   group_color: RSC allocation score on NODE: VALUE
	#   ...
	#   native_color: RSC allocation score on NODE: VALUE
	#
	while (<PTEST>) {
		chomp;
		# printf "%s\n", $_;
		if ( /^group_color:\s*(\w+)\s+allocation score on\s+(\w+):\s+(.*)$/ ) {
			# printf "DBG: group 1: %s, 2: %s, 3: %s\n", $1, $2, $3;
			$resource{$1}->{nodes}->{$2}->{gc}=$3;
			push(@{$resource{$1}->{priorities}->{$3}}, $2);
		}
		if ( /^native_color:\s*(\w+)\s+allocation score on\s+(\w+):\s+(.*)$/ ) {
			# printf "DBG: native 1: %s, 2: %s, 3: %s\n", $1, $2, $3;
			$resource{$1}->{nodes}->{$2}->{nc}=$3;
			push(@{$resource{$1}->{priorities}->{$3}}, $2);
		}
	}
	close PTEST;
	#
	# get sorted list of scores (excluding -INFINITY)
	#
	my @filtered_prios=grep (!/-INFINITY/, keys (%{$resource{$resource}->{priorities}}));
	@filtered_prios=sort {$b <=> $a} @filtered_prios; # reverse order
	#
	# figure out node list sorted by prios (scores)
	#
	my $prio;
	my $node;
	my @nodes;
	my %node_mark;
	for $prio ( @filtered_prios ) {
		#printf "for prio %s checking nodes %s\n", $prio, join " ",@{$resource{$resource}->{priorities}->{$prio}};
		for $node ( @{$resource{$resource}->{priorities}->{$prio}} ) {
			if ( ! defined ( $node_mark{$node} )) {
				#printf "DBG: for prio %s adding node %s\n", $prio, $node;
				$node_mark{$node}=1;
				push(@nodes, $node);
			} 
		}
	}
	$node_list = join ",", @nodes;
	#
	# SOME MORE DBG
	#
	#my @allnodes=keys(%{$resource{$resource}->{nodes}});
	#printf "DBG: %s all nodes: %s\n", $resource, join(",", @allnodes);
	#printf "DBG: %s prios: %s\n", $resource, join(" ", @filtered_prios);
	#printf "DBG: %s ordered nodes %s\n", $resource, join(" ", @nodes);
	#
	# RESULT
	# 
	if ( $outfile ne "" ) {
		open OUTFILE, ">$outfile";
		syslog("LOG_INFO","lsn result: %s:%s:%s:%s\n",  $resource, $myhostname, $current_node, $node_list);
		printf OUTFILE "%s:%s:%s:%s\n",  $resource, $myhostname, $current_node, $node_list;
		close OUTFILE;
	} else {
		printf "%s:%s:%s:%s\n",  $resource, $myhostname, $current_node, $node_list;
	}
	return $rc;
}

sub get_version_info {
	my ($outfile) = @_;
	my $rc=0;
	my $haProd="Pacemaker";
	my $haProdSAP= "$scriptname";
	my $haProdSAPCon= "$scriptname";
	my $haProdDoc="https://github.com/ClusterLabs/sap_cluster_connector";

	$nowstring = localtime;
	printf "%s : gvi($outfile)\n", $nowstring;

	# read config file
	open(CONFIGFILE, $sysconfig) or syslog("LOG_INFO", "Warning: unable to to open config file $sysconfig");
	my $config = join "", <CONFIGFILE>;
	close CONFIGFILE;
	eval $config;
	die "Couldn't interpret the configuration file ($sysconfig) that was given.\nError details follow: $@\n" if $@;

	if ( $outfile ne "" ) {
		open OUTFILE, ">$outfile";
		syslog("LOG_INFO", "gvi result: %s\n%s\n%s\n%s\n", $protocolVersion, $haProd, $haProdSAP, $haProdDoc);
		printf OUTFILE "%s\n%s\n%s\n%s\n", $protocolVersion, $haProd, $haProdSAP, $haProdDoc;
		close OUTFILE;
	} else {
		printf "%s\n%s\n%s\n%s\n", $protocolVersion, $haProd, $haProdSAP, $haProdDoc;
	}
	return $rc;
}

sub ha_config_check {
    # output-multiple lines, each line formatted as: CHK-STATE:CHK-CATEGORY:CHK-DESCRIPTION:CHK-COMMENT
    #
    my $rc=0;
    my ($out, $sid, $ino) = @_;
    $nowstring = localtime;
    printf "%s : hcc($out, $sid, $ino)\n", $nowstring;
    if ( $out ne "" ) {
        syslog("LOG_INFO", "hcc run_checks");
        if (system("$hacheckcmd","$out","$sid", "$ino") ) { $rc=1; }
    } else {
        syslog("LOG_INFO", "hcc run_checks stdout");
        if (system("$hacheckcmd","$out","$sid", "$ino") ) { $rc=1; }
        $rc=0;
    }
    return $rc;
}

sub set_maintenance_mode {
	my $rc=0;
	my $mm=0;
	my ($out, $sid, $ino, $nmode) = @_;
	$nowstring = localtime;
	printf "%s : smm($out, $sid, $ino, $nmode)\n", $nowstring;

	my ($res, $grp) = get_resource_from_sid_ino($sid, $ino);

	if ($res ne "") {

		my $status = check_maintanance_mode($res);
		if ( $status eq "0" ) {
			# maintenance mode is active for resource
			$mm=1;
		} elsif ( $status eq "1" ) {
			# maintenance mode is not active for resource
			$mm=0;
		} else {
			# maintenance mode is divergent for resource
			$mm=2;
		}

		if ( $out ne "" ) {
			open OUTFILE, ">$out";
			printf OUTFILE "%s\n", $mm ;
			close OUTFILE;
		} else {
			printf "DEBUG-MODE $mm\n" ;
		}

		if ( $nmode eq "1" ) {
			syslog("LOG_INFO", "Activate maintenance mode for resource %s\n",$res);
			#if (system($cmd_crm_resource, "-r", $grp, "--meta", "--set-parameter=is-managed", "--parameter-value", "false") ) { $rc=1; }
			if (system($cmd_crm_attribute, "--name", "maintenance-mode", "--update", "true") ) { $rc=1; }
		} elsif ( $nmode eq "0" ) {
			syslog("LOG_INFO", "Deactivate maintenance mode for resource %s\n",$res);
			#if (system($cmd_crm_resource, "-r", $grp, "--meta", "--delete-parameter=is-managed") ) { $rc=1; }
			if (system($cmd_crm_attribute, "--name", "maintenance-mode", "--delete") ) { $rc=1; }
		} else {
			syslog("LOG_INFO", "Check maintenance mode for resource %s\n",$res);
			$rc=0;
		}
	} else {
		$rc=3;
	}
	return $rc;
}

#
# "main"
#
my ($cmd) = @ARGV; shift;
my $result=2;
my ($sid, $ino, $act, $out, $res, $nod, $sta, $nmode);
my $return_code=2;
$nod="";
$ENV{'PATH'} = $ENV{'PATH'} . ":/usr/sbin:/sbin";

if ( $cmd eq "h" || $cmd eq "help" ||  $cmd eq "-h" || $cmd eq "--help" ||  $cmd eq "-?" ) {
	 usage();
	 exit 0;
}
if  ($cmd eq "init")  {
	syslog("LOG_INFO", "init call");
	$return_code=initial_check();
} elsif ( $cmd eq "cpa" ) {
	open($DEBUG, ">>$logident" . ".log");
	*STDOUT=*$DEBUG;
	$result = GetOptions ("res=s" => \$res,    
	                   "act=s" => \$act,
		 ) &&
	checkavail(($res, $act)) || paramproblem();
	syslog("LOG_INFO", "cpa call (res=%s,act=%s)", $res, $act);
	$return_code=check_pending_action($res, $act, "pending");


 } elsif ( $cmd eq "lsr" ) {
	open($DEBUG, ">>$logident" . ".log");
	*STDOUT=*$DEBUG;
	$result = GetOptions ("sid=s" => \$sid,    
	                   "ino=s" => \$ino,
	                   "out=s" => \$out,
		 ) &&
	checkavail(($sid, $ino, $out)) || paramproblem();
	syslog("LOG_INFO", "lsr call (sid=%s,ino=%s,out=%s)", $sid, $ino, $out);
	$return_code=list_sap_resources($out, $sid, $ino);
	
 } elsif ( $cmd eq "fra" ) {
	open($DEBUG, ">>$logident" . ".log");
	*STDOUT=*$DEBUG;
	$nod = "";
	 #
	 # remark: don't check if nod is set - as it is optional
	 #
	$result = GetOptions ("res=s" => \$res,    
	                   "act=s" => \$act,
	                   "node:s" => \$nod,
		 ) && 
	checkavail(($res, $act)) || paramproblem();
	syslog("LOG_INFO", "fra call (res=%s,act=%s,nod=%s)", $res, $act, $nod);
	$return_code=fire_resource_action($res, $act, $nod);

 } elsif ( $cmd eq "lsn" ) {
	open($DEBUG, ">>$logident" . ".log");
	*STDOUT=*$DEBUG;
	$result = GetOptions ("out=s" => \$out,    
	                   "res=s" => \$res,
		 ) &&
	checkavail(($res, $out)) || paramproblem();
	syslog("LOG_INFO", "lsn call (out=%s,res=%s)", $out, $res);
	$return_code=list_sap_nodes($out, $res);

 } elsif ( $cmd eq "gvi" ) {
	open($DEBUG, ">>$logident" . ".log");
	*STDOUT=*$DEBUG;
	$result = GetOptions ("out=s" => \$out,
		) &&
	checkavail(($out)) || paramproblem();
	syslog("LOG_INFO", "gvi call (out=%s)", $out);
	$return_code=get_version_info($out);

} elsif ( $cmd eq "hcc" ) {
        open($DEBUG, ">>$logident" . ".log");
        *STDOUT=*$DEBUG;
        $result = GetOptions ("sid=s" => \$sid,
                           "ino=s" => \$ino,
                           "out=s" => \$out,
                 ) &&
        checkavail(($sid, $ino, $out)) || paramproblem();
        syslog("LOG_INFO", "hcc call (sid=%s,ino=%s,out=%s)", $sid, $ino, $out);
        $return_code=ha_config_check($out,$sid,$ino);

} elsif ( $cmd eq "smm" ) {
        open($DEBUG, ">>$logident" . ".log");
        *STDOUT=*$DEBUG;
        $result = GetOptions ("sid=s" => \$sid,    
                           "ino=s" => \$ino,
                           "out=s" => \$out,
                           "mod=s" => \$nmode,
                 ) &&
        checkavail(($sid, $ino, $out)) || paramproblem();
        syslog("LOG_INFO", "smm call (sid=%s,ino=%s,out=%s,mod=%s)", $sid, $ino, $out, $nmode);
        $return_code=set_maintenance_mode($out, $sid, $ino, $nmode);

} else  {
	open($DEBUG, ">>$logident" . ".log");
	*STDOUT=*$DEBUG;
	 #
	 # remark: found no or unknown cmd
	 #
	$nowstring = localtime;
	printf "%s : unkown function %s\n", $nowstring, $cmd;
 	paramproblem()
}

closelog();
exit $return_code;
