#!/usr/bin/perl
#Calculate the memory or  that's available for partition activation and dynamic logical partition. 
#First to determine the unassign resources + 
#                       resourceds assigned to Not Activated partition and not in workload management group


#Main
#extract the parameters
$SERVER = "";
$LPAR = "";
$LPAR_NAME = "";
$DEBUG = "";

for ( $i=0; $i <= $#ARGV; $i++ ) {
    #Managed system name
    if ( $ARGV[$i] eq '-m' && $#ARGV > $i) {
        $SERVER = $ARGV[$i+1];
        $i++;
    }
    #lpar id
    elsif ( $ARGV[$i] eq '--id' && $#ARGV > $i) {
        $LPAR = $ARGV[$i+1];
        $i++;
    }
    #lpar name
    elsif ( $ARGV[$i] eq '-n' && $#ARGV > $i) {
        $LPAR_NAME = $ARGV[$i+1];
        $i++;
    }
    elsif ( $ARGV[$i] eq '-d') {
        $DEBUG = TRUE;
    }
        
}

#pring out help message
if ($#ARGV < 0 || $ARGV[0] eq '-h') {
    &showUsage;
    exit;
}

#parameter check
if ( $LPAR ne "" && $LPAR_NAME ne "" ) {
    print "The -n and --id parameters are mutually exclusive.  Please remove one of the parameter and retry the command.\n";
    exit;
}


#make sure the system is in the correct state
chomp($SysState=`lssyscfg -m $SERVER -r sys -F state`);
if ( $DEBUG ) {
        print "SysState = $SysState\n";
}
if ( ($SysState ne "Operating")  &&
     ($SysState ne "Standby") ) {
    print "The managed system is not in Standby or Operating state. We are unable to calculate the memory and processors information\n";
    exit;
}


#extract system memory information and LMB size
chomp($SysMem=`lshwres -r mem --level sys -m $SERVER -F configurable_sys_mem:pend_avail_sys_mem:sys_firmware_mem:mem_region_size`);
if ( $DEBUG) {
        print "SysMem = $SysMem\n";
}

@MemInfo = split(/:/, $SysMem);
$ConfigMem=$MemInfo[0];
$PendAvailMem=$MemInfo[1];
$HypMem=$MemInfo[2];
$LMBMem=$MemInfo[3];
if ( $DEBUG ) {
        print "ConfigMem = $ConfigMem PendAvailMem = $PendAvailMem  HypMem =  $HypMem LMBMem = $LMBMem\n";
}
$StealableMem=0;

#extract system processor information
chomp($SysCPU=`lshwres -r proc --level sys -m $SERVER -F configurable_sys_proc_units:pend_avail_sys_proc_units`);
if ( $DEBUG ) {
        print "SysCPU = $SysCPU\n";
}
@CPUInfo = split(/:/, $SysCPU);
$ConfigCPU=$CPUInfo[0];
$PendAvailCPU=$CPUInfo[1];
if ( $DEBUG ) {
        print "ConfigCPU = $ConfigCPU PendAvailCPU = $PendAvailCPU\n";
}
$StealableCPU=0;

#make sure the lpar passed in is valid, otherwise set it to empty string
if ( $LPAR ne "" ) {
    #make sure the lpar id is valid
    chomp($LparId=`lssyscfg -m $SERVER --filter lpar_ids=$LPAR -F lpar_id`);
    
    #cannot find the lpar id with specific value
    #check for lpar name instead
    if ( $? ne 0 ) {
	$LPAR="";
    }
}
elsif ( $LPAR_NAME ne "" ) {
    #make sure the lpar name is valid
    chomp($LparId=`lssyscfg -m $SERVER --filter lpar_names=$LPAR_NAME -F lpar_id`);
    if ( $? ne 0 ) {
	$LPAR="";
    }
    else {
	$LPAR=$LparId;
    }
}
            
#extract the work group id of the lpar specified

if ( $LPAR ne "" ) {
    chomp($WorkGroupId=`lssyscfg -m $SERVER -F work_group_id --filter lpar_ids=$LPAR`);
}
else {
    $WorkGroupId="none";
}

if ( $DEBUG) {
        print "WorkGroupId = $WorkGroupId\n";
}

#Get the partition information from the ones that are in Not Activated State
$cmd="lssyscfg -r lpar -m $SERVER -F name,state,work_group_id | awk -F, \'(\$2==\"Not Activated\") {print \$1\":\"\$3}\' | ";
open(LPAR_LIST, $cmd);
@lpars=<LPAR_LIST>;
foreach $i (@lpars) {
    

    #extract each Not Activate partition's name and work_group_id
    @loopLparInfo = split(/:/, $i);
    if ( $DEBUG ) {
            foreach $t (@loopLparInfo) {
                print "loopLparInfo $t\n";
            }
    }
    $loopLparName= $loopLparInfo[0];
    chomp $loopLparName;
    $loopWlmId= $loopLparInfo[1];
    chomp $loopWlmId;
    if ( $DEBUG ) {
            print "loopLparName = $loopLparName loopWlmId = $loopWlmId\n";
    }

    #extract the memory information
    $memCmd="lshwres -r mem -m $SERVER --level lpar --filter lpar_names=$loopLparName  -F pend_mem:pend_max_mem:pend_min_mem | ";
    open(LPAR_MEM_INFO, $memCmd);
    @memOutput=<LPAR_MEM_INFO>;
    chomp $memOutput[0];
    if ( $DEBUG ) {
            print "memoutput = $memOutput[0]\n";
    }
    @loopLparMem= split(/:/, $memOutput[0]);
    close(LPAR_MEM_INFO);
    if ( $DEBUG ) {
            foreach $t (@loopLparMem) {
                print "loopLparMem = $t\n";
            }
    }
    $loopLparPendMem= $loopLparMem[0];
    $loopLparPendMaxMem= $loopLparMem[1];
    $loopLparPendMinMem= $loopLparMem[2];
    $loopLparHPT = 0;
    if ( $loopLparPendMaxMem != 0) {
        $loopLparHPT=&HardwarePageMem($loopLparPendMaxMem/64, $LMBMem);
    }
    if ( $DEBUG ) {
        print "loopLparHPT = $loopLparHPT\n";
    }
    
  
    #extract the cpu information
    $cpuCmd="lshwres -r proc -m $SERVER --level lpar --filter lpar_names=$loopLparName -F pend_proc_mode:pend_proc_units:pend_procs:pend_min_proc_units:pend_min_procs | ";
    open(LPAR_CPU_INFO, $cpuCmd);
    @cpuOutput=<LPAR_CPU_INFO>;
    chomp $cpuOutput[0];
    if ( $DEBUG ) {
            print "cpuOutput = $cpuOutput[0]\n";
    }
    @loopLparCPU= split(/:/, $cpuOutput[0]);
    close(LPAR_CPU_INFO);
    if ( $DEBUG ) {
            foreach $t (@loopLparCPU) {
                print "loopLparCPU = $t\n";
            }
    }

    #shared processors
    if ( $loopLparCPU[0] eq "shared" ) {
        $loopLparPendProc=$loopLparCPU[1];
        $loopLparPendMinProc=$loopLparCPU[3];
    }
    else {
        $loopLparPendProc=$loopLparCPU[2];
        $loopLparPendMinProc=$loopLparCPU[4];
    }
    if ( $DEBUG ) {
            print "loopLparPendProc = $loopLparPendProc\n";
            print "loopLparPendMinProc = $loopLparPendMinProc\n";
    }
  

    #if the partition specified work_group_id not none
    #   we can take resources from the same work_group_id to minimum setting
    if ( $WorkGroupId ne "none" ) {
        if ( $WorkGroupId eq $loopWlmId ) {
            $StealableCPU= $StealableCPU + ($loopLparPendProc - $loopLparPendMinProc);
            $StealableMem= $StealableMem + ($loopLparPendMem - $loopLparPendMinMem);
        }
        elsif ( $loopWlmId eq "none" ) {
            $StealableCPU= $StealableCPU + $loopLparPendProc;
            $StealableMem= $StealableMem + $loopLparPendMem + $loopLparHPT;
        }
    }
    else {
        if ( $loopWlmId eq "none" ) {
            $StealableCPU= $StealableCPU + $loopLparPendProc;
            $StealableMem= $StealableMem + $loopLparPendMem + $loopLparHPT;
        }
    }
    if ( $DEBUG ) {
            print "StealableCPU = $StealableCPU\n";
            print "StealableMem = $StealableMem\n";
    }
}
close(LPAR_LIST);
#print "PendAvailMem = $PendAvailMem\n";
#print "StealableMem = $StealableMem\n";
#print "PendAvailCPU = $PendAvailCPU\n";
#print "StealableCPU = $StealableCPU\n";
$UsableMem=$PendAvailMem + $StealableMem;
$UsableCPU=$PendAvailCPU + $StealableCPU;
print "avail_mem_for_lpars=$UsableMem,avail_proc_units_for_lpars=$UsableCPU\n";
exit;


#Usage for this script
# If user does not pass in the lpar id or name, it returns available memory and processor for all partition.
# Otherwise, it would take the workload management group of the partition specified into account
#   calAvailRes -m <manage system name> [--id <lpar_id> | -n <lpar_name>]
sub showUsage {
    print  "Usage: \n";
    print  "  lsavailres -m <managed system name>\n";
    print  "  lsavailres -m <managed system name> --id <lpar_id> | -n <lpar_name>\n";
}


#Function HardwarePagMem, calculated the Page Memory of Not Activated partition with the following criteria:
#The memory overhead is determined by taking 1/64 of maximum memory assigned to the partition and rounding up to a power of 2 
sub HardwarePageMem () {

    $PageMemory=$_[0];
    $power=1;
    while ( $power < $PageMemory ) {
        $power=2*$power;
    }
    if ( $DEBUG ) {
            print "power = $power\n";
    }
    if ( $power < $_[1] ) {
        $power=0;
    }
    else {
        $roundup=($power/$_[1]);
        $power= $roundup * $_[1];
    }
    if ( $DEBUG ) {
            print "power = $power\n";
            print "roundup = $roundup\n";
    }
    $power;
}
