#!/bin/perl

# File        : mon_tskbalance.pl
#
# Objective   : Monitor the balance of tasks for a specific component
#               over a group of servers 
#
# Argument(s) : 0  component name, e.g. "fins%" 
#               1  deviation in percent, e.g. "5"
#               2  List of hosts in group, e.g. "mangaan,chroom,kobalt"
#
# Returns     : Positive integer     number of active concurrent users
#
# Date (yyyymmdd)   Who              What
# ---------------   --------------   -------------------------------------------------
# 2006 10 19        Peter van Nes    Initial release

# Include libraries
use Socket;
use Net::Domain ;

# Restrict unsafe constructs
use strict ;

# Declare lexical variables
my($port) = "3456" ;                # siebcmdserver portnumber
my($sk) = "AF13BAA8A078E4CF" ;      # siebcmdserver sessionkey
my($line) = "" ; 
my($siebsvr) = "" ;
my(%svrtsk) = () ;
my($sumtsk) = 0 ;
my($totaltsk) = 0 ;
my($threshold) = 0 ;
my($baseline) = 0 ;
my($objmgr) = $ARGV[0] ;
my($maxdev) = $ARGV[1] ; 
my($group) = $ARGV[2] ;

if ($#ARGV == 2) {

  # Get (FQDN) hostname, siebcmdserver is considered to be on the same host
  my($fqnode) = Net::Domain::hostfqdn() ;
  my($node) = Net::Domain::hostname() ;
$node = "bismut" ;  
  if ($group !~ m/$node/i) {
    $group .= ",$node" ;
  }
  
  
  foreach $siebsvr (split(/,/,$group)) {
    # submit srvrmgr command through siebcmdserver
    my($svroutput) = mysrvrmgr($fqnode,$port,$sk,"list comp \"$objmgr\" for server \"$siebsvr\" show SV_NAME, CC_ALIAS, CP_NUM_RUN_TASKS") ;
    $sumtsk = 0 ;
    # Check if session with siebcmdserver failed
    if ($svroutput !~ m/^FAILED/) {
      # Session OK, parse rows with hostname in column SV_NAME 
      # and add values in column CC_NUM_RUN_TASKS
      foreach $line (split(/\n/,$svroutput)) {
        if ($line =~ m/^${siebsvr}\s*(\S*)\s*(\d*)/i) {
          $sumtsk += scalar($2) ;
        }
      }
      # Store the sum of tasks per siebel server
      $svrtsk{$siebsvr} = $sumtsk ;
      $totaltsk += $sumtsk ;
    }
    else {
      # monitoring error
      print "ERROR\n" ;
      print "$svroutput" ;
      exit ;
    }
  }
  
  $threshold = int((($totaltsk / 100) * $maxdev) / keys(%svrtsk)) ;
  $baseline = int( $totaltsk / keys(%svrtsk) ) ;
  
  if ( ($svrtsk{$node} > $baseline+$threshold) || ($svrtsk{$node} < $baseline-$threshold) ) {
    print "ERROR\n" ;
  }
  else {
    print "GOOD\n" ;
  }
  
  print "#tasks [$svrtsk{$node}] ; #baseline [$baseline] ; #maxdev [$threshold]\n" ;
}
else {
  # Print error
  print "-1\n" ;
  print "Specify component name, deviation and serverlist as arguments\n" ;
}



exit ;

## Subroutine mysrvrmgr
##
## Compatible with siebcmdserver 1.24 based on mysrvrmgr.pl 1.22
##
sub mysrvrmgr {

  my($remote,$port,$sk,$cmd) = (@_) ;

  # Declare variables
  my ($iaddr, $paddr, $proto);
  my ($dread) = "" ;
  my ($eod) = "" ; 
  my ($soutput) = "" ;

  # Get protocol number
  $proto   = scalar(getprotobyname('tcp')) ;

  ## Open port and attempt to connect
  if ($iaddr = inet_aton($remote)) {
    $paddr = sockaddr_in($port, $iaddr);
    ## Create a TCP socket
    if (socket(SOCK, PF_INET, SOCK_STREAM, $proto)) {
      ## Connect to the server
      if (connect(SOCK, $paddr)) {
        ## send the supplied srvrmgr command 
        send(SOCK,"$sk $cmd",0) ;
        ## wait for response for 60 seconds
        eval {
          local $SIG{ALRM} = sub { die "Timed Out!\n" };
           # save the previous alarm value
           my $previous_alarm = alarm(60);
           my $buffer = "" ;
           while (($eod ne "1") && ($dread !~ m/$sk\sFAILED/)) {
             ## If data is received
             if ( defined (recv(SOCK, $dread, 240, 0)) ) { 
               ## Put data in buffer
               $buffer .= $dread ;
               ## Check buffer for EOD marker and remove marker if found
               $eod = ($buffer =~ s/(.*)$sk END/$1/) || ($buffer =~ m/$sk\sFAILED/) ;
               ## Display complete received lines  and remove them from the buffer 
               while ($buffer =~ s/^(.*)\n(.*)/$2/g) {
                 $soutput .= "$1\n" ;
               }
             } ;
           }
          alarm($previous_alarm) ;
        } ;
  
        if (! $eod) { 
          $soutput = "FAILED Timeout with siebscmdserver occured\n" ;
         } ;
       
      }
      else {
        $soutput = "FAILED Failed to connect to $remote ($!)\n" ;
      }
    }
    else {
      $soutput = "FAILED Failed to create socket ($!)\n" ;
    }
  }
  else {
    $soutput = "FAILED Failed to find host for IP address \"$remote\"\n" ;
  }
  
  close (SOCK) ;
 
  return ($soutput) ;
 
}

