#!/usr/bin/perl -w
###################################################################
# (C) Copyright 2017 Hewlett Packard Enterprise Development LP.
# (C) Copyright 2013-2015 Hewlett-Packard Enterprise Development, 
#     L.P.
# @(#) Serviceguard Upgradation Script
# @(#) Product Name    : HP Serviceguard
# @(#) Product Version : A.12.10.00
# @(#) Patch Name      : 
#
#  *** Note: This file MUST NOT be edited. *****
#
# Changing this file may lead to issues in the upgradation of
# Serviceguard and its components.
# 
###################################################################

use strict;
use warnings;
use English;
use Getopt::Long qw(GetOptions HelpMessage :config bundling no_ignore_case);
use Pod::Usage;
use File::Copy;

########################################################################
# Serviceguard Upgradation Automation Script 
# Description: This script eases the upgradation process
# for Serviceguard A.12.00.xx and its components and management 
# tools from version A.11.20.xx to A.12.00.xx
########################################################################

########################################################################
# * User must download the CD image to the system 
#   where the script is run
# * This script does only the installation of products.
# * This script does not prepare(Stopping the cluster services
#   and moving workload to another node) the node for rolling
#   upgrade.
# * This script is interactive and the user is expected to
#   type "yes" to continue or "no" to abort.
# * This script runs on one node at a time.
# * Some of the rpm files are required to be installed from
#   the distribution CD or web. The user can open another 
#   terminal window for installing the required rpm files. 
########################################################################

# SG_Products contains one or more Product objects.
package SG_Products;

sub new {
    my $self = { };
    $self->{product}=[];
    bless $self;
    return $self;
}

sub addProduct {
    my ($self, $product) = @_;
    push(@{$self->{product}}, $product);
}

# Product object has information abbout name of the product,
# location of the product rpm in the iso directory, whether
# to install/upgrade the product and if there is any suffix
# needed to be added for the product upgrade.
 
package Product;

sub new {
    my $self = { };
    $self->{name}="";
    $self->{location}="";
    $self->{option}="";
    $self->{suffix}=""; 
    $self->{former_text}="";
    $self->{installed_ver}="";
    $self->{ver_on_cd}="";
    $self->{action}="";
    $self->{action_str}=""; 
    $self->{yum_cmd}="";
    $self->{yum_cmd_suffix}="";
    bless $self;
    return $self;
}

package main;

#Global variables

#Vairables to parse Arguments
my $flag = '';
my $top_dir = "";
my $automatic_ins = 0;

#Variables for YUM commands
my $YUM_CLEAN_ALL = "/usr/bin/yum clean all";
my $YUM_INSTALL = "/usr/bin/yum install -y ";
my $YUM_UPGRADE = "/usr/bin/yum upgrade -y ";
my $YUM_LIST = "/usr/bin/yum  list all";
my $repo_config_file = "/etc/yum.repos.d/";
my $CAT = "/bin/cat";
my $RM = "/bin/rm";
my $yumretval = 0;
my @failed_yum_dep_rpms = ();

#Store Execution Node Name to differentiate from all the node names provided as input 
my $execution_node;

# $EXIT to abort and $SUCCESS to continue
my $EXIT = 1;
my $SUCCESS = 0;

#products that are in the Serviguard distribution CD
#The order decides the order in which products will be 
#installed. So order must be proper.

my @sg_products = ("serviceguard-license", "serviceguard", "serviceguard-snmp",
                   "serviceguard-providers", "serviceguard-xdc", "serviceguard-analytics",
                   "serviceguard-manager", "serviceguard-sybase-toolkit",
                   "serviceguard-oracle-toolkit",  "serviceguard-dataguard-toolkit", 
                   "serviceguard-kvm-toolkit", "serviceguard-ppas-toolkit", 
                   "serviceguard-metrocluster-3parrc", "serviceguard-metrocluster-caxpp9000", 
                   "serviceguard-metrocluster-caevap6000", "serviceguard-metrocluster-emcsrdf", 
                   "serviceguard-metrocluster-addons", "serviceguard-extension-for-sap");

# Hash which contains mapping of product names to A.11.20.xx form A.12.00.00
my %sg_product_map = (
    "serviceguard-license" => "new",
    "serviceguard" => "serviceguard",
    "serviceguard-snmp" => "cmsnmpd",
    "serviceguard-providers" => "sgproviders",
    "serviceguard-xdc" => "serviceguard-xdc",
    "serviceguard-analytics" => "new",
    "serviceguard-manager" => "serviceguard-manager",
    "serviceguard-sybase-toolkit" => "serviceguard-sybase-toolkit",
    "serviceguard-oracle-toolkit" => "serviceguard-oracle-toolkit",
    "serviceguard-dataguard-toolkit" => "serviceguard-dataguard-toolkit",
    "serviceguard-kvm-toolkit" => "serviceguard-kvm-toolkit",
    "serviceguard-ppas-toolkit" => "serviceguard-ppas-toolkit",
    "serviceguard-metrocluster-addons" => "serviceguard-metrocluster-addons",
    "serviceguard-metrocluster-3parrc" => "serviceguard-metrocluster-3parrc",
    "serviceguard-metrocluster-caxpp9000" => "serviceguard-metrocluster-caxpp9000",
    "serviceguard-metrocluster-caevap6000" => "serviceguard-metrocluster-caevap6000",
    "serviceguard-metrocluster-emcsrdf" => "serviceguard-metrocluster-emcsrdf",
    "serviceguard-extension-for-sap" => "serviceguard-extension-for-sap",
);

#Password for sgmgr user
my $sgmgr_password = undef;

# time stamp
my $timestamp = localtime time;

# text
my $text, my $final_text, my $doc_text;
my $yum_prod_text, my $yummsgtxt;
my $sgmgr_usr_text = "";
 
my $isEnterprise = 0;
my $isAdvancedInstalled = 0;
my $isEnterpriseInstalled = 0;

#distro and architecture
my ($distro, $distro_dir, $arch); 

my $SGCONF;

# Pre-requisite rpms in sles11, sles12, rh5, rh6 and rh7
my @sg_all_distro_pre_requisites = qw(xinetd sg3_utils net-snmp net-tools); 

my @sg_sles11_pre_requisites = qw( bash  pidentd libblkid1
 sblim-indication_helper sblim-sfcb sblim-sfcc sblim-cmpi-base udev libnl
 pmtools); 
 
my @sg_sles12_pre_requisites = qw( bash  pidentd libblkid1
 sblim-indication_helper sblim-sfcb sblim-sfcc sblim-cmpi-base udev libnl1
 dmidecode); 

my @sg_rhel5_pre_requisites = qw(sg3_utils-libs lm_sensors
 tog-pegasus authd  krb5-libs zlib e2fsprogs-libs udev libnl dmidecode);

my @sg_rhel6_pre_requisites = qw(sg3_utils-libs lm_sensors
 tog-pegasus authd libblkid krb5-libs zlib udev libnl dmidecode);
 
my @sg_rhel7_pre_requisites = qw(sg3_utils-libs lm_sensors
 tog-pegasus authd libblkid krb5-libs zlib libnl dmidecode perl-Sys-Syslog);

my @drs_pre_requisites = qw(lsscsi tog-pegasus);

my @xdc_pre_requisites = qw(mdadm);

my @oracle_dataguard_pre_requisites = qw(serviceguard-oracle-toolkit);

my $drs_pre_req_failed = 0;
my $drs_optional_pre_req_failed = 0;
my $xdc_pre_req_failed = 0;
my $oracle_dataguard_pre_req_failed = 0;
my $java_err = 0;
my $dependency_check_for_oracle_tkt = 0;

# Adding the help option for the script
# Script doesn't need any arguments to run.
my $optForExecution = $#ARGV + 1;

#Get the SG version installed on the node
my $sgversion; 

#variable to store local node status
my $node_status;

#variable to validate if the user is root
my $user_cred_sg;

#variable to check directory existence
my $direxists;

#Array to store the rpms which are installed but not present in CD
my @rpms_not_present;

#store user input in a variable
my $input;

#To keep track how many rpms are installed but not present
#in DVD/CD
my $num_not_present;

#Variables to store messages
my $msgtext, my $success_dir_msgtext;
my $failure_txt = "";
my $success_txt = "";
my $distro_text = "";
my $cd_level_txt = "";

#To store rpm command to be run
my $cmd;

#To store output of rpm commands and the errors
my @out;
my $out_error;

#Failure related variables
my $global_failure = 0;
my $fail;
my $is_prod_installed;

#To check if cluster exists
my $isCluster;

#To check if Legacy pkg is configured on the cluster
my $legacyPkgFound = 0;

#Whether a patch or rolling upgrade
my $isPatch = 0;
my $isUpgrade = 0;
#isBundleUpgrade flag is used to allow upgrade 
#from one bundle patch to another bundle MR. 
#For example: 
# Base(Patch)bundle     -> Advanced/Enterprise(MR)
# Advanced(Patch)bundle -> Enterprise(MR)
my $isBundleUpgrade = 0;
my $isSameVer;

#Current Major/minor Version represents major 
#and minor version of all product in MR.
#For RHEL5, RHEL6 & SLES11 major version of
#all product was 1200 and minor version was 00.
#For RHEL7 and SLES12 major version of 
#all product was 1200 and minor version was 30.
my $current_major_version = "12";
my $current_minor_version = "1000";

#Use this Major version array later for printing purposes
my @major_version = $current_major_version =~ /(..?)/g;

#Count of the number of steps
my $count_steps_gbl = 1;

#Set Execution node
$execution_node = `/bin/hostname -s`;
chomp $execution_node;

#Parse Inputs
if ($optForExecution > 0) {
    parse_inputs();
}
else {
    displayUsage();
} #end of if $optForExecution > 0

#Set up various paths for different log files created during installation
my $log_file = "/tmp/cmupgrade.log";

my $SG_Product = SG_Products->new();

my $product;

# If serviceguard is not installed, exit out.
$is_prod_installed = isProdInstalled("serviceguard");
if (($is_prod_installed =~ /^\s*$/) && ($is_prod_installed !~ /incompatible/)) {
    $text = "\tERROR: Serviceguard is not installed on the node. \n";
    $text .= "\tPlease execute cmeasyinstall to install serviceguard on the node.\n";
    print STDOUT $text;
    exit $EXIT;
}

($distro, $distro_dir) = getDistro();


if (($distro =~ /sles12/) || ($distro =~ /rhel7/)) {
    $current_minor_version = "30";
} 

if ($distro =~ /sles/) {
    $SGCONF = "/opt/cmcluster/conf";
    $log_file = "/opt/cmcluster/log/cmupgrade.log";
} elsif ($distro =~ /rhel/) {
    $SGCONF = "/usr/local/cmcluster/conf";
    $log_file = "/usr/local/cmcluster/log/cmupgrade.log";
}

#Upgradation/installation 
if ($distro =~ /rhel5/) {
       $distro_text = "Red Hat Enterprise Linux 5";
       print "HPE Serviceguard for Linux patch 12.10.00 or later are not supported on Red Hat Enterprise Linux 5.\n";
       exit $EXIT;
}
elsif ($distro =~ /rhel6/) {
       $distro_text = "Red Hat Enterprise Linux 6";
}
elsif ($distro =~ /rhel7/) {
       $distro_text = "Red Hat Enterprise Linux 7";
}
elsif ($distro =~ /sles11/) {
       $distro_text = "SuSE Linux Enterprise Server 11";
}
elsif ($distro =~ /sles12/) {
       $distro_text = "SuSE Linux Enterprise Server 12";
}



# Open all requied log files, depending on inputs provided
# One log file is opened, and a summary log file. 

open(LOG_FILE, ">>$log_file") || die "Cannot open the log file for updating 
status of the script.\n";
	
$arch = getArch();
if ($arch !~ /x86_64/) {
    printOnConsole ("\t\tERROR: Serviceguard A.$major_version[0].$major_version[1].$current_minor_version is only supported on x86_64\n");
    close(LOG_FILE);
    exit $EXIT;
}

if ($distro =~ /not_supported/) {
    $text = "\t\tERROR: Serviceguard A.$major_version[0].$major_version[1].$current_minor_version is supported on Red Hat "; 
    $text .= "Enterprise Linux 5.7 and later,\n";
    $text .= "\t\tRed Hat Enterprise Linux 6.1 and later, SuSE Enterprise Linux 11 SP2 and later.\n";
    printOnConsole($text);
    close(LOG_FILE);
    exit $EXIT;
}

$sgversion = getSGVersion();
if ($sgversion < 112000) {
    $text = "\t\tERROR: cmupgrade script can only be used to upgrade from ";
    $text .= "serviceguard version A.11.20.00 or later\n"; 
    printOnConsole($text); 
    close(LOG_FILE);
    exit $EXIT;
}

$isCluster = check_if_cluster_exists();
if ($isCluster == 1) {
    $node_status = getnodestatus();
    if ($node_status !~ /down/) {
        $text = "\t\tERROR: Cluster is not halted on $execution_node. "; 
        $text .= "Before running cmupgrade script on this node,\n";
        $text .= "\t\tmake sure that cluster is halted on $execution_node.\n"; 
        printOnConsole($text);
        close(LOG_FILE);
        exit $EXIT;
    }
    $legacyPkgFound = check_if_legacy_pkg_configured();
    if ($legacyPkgFound == 1) {
        $text = "\t\tERROR: Legacy packages are not supported with ";
        $text .= "Serviceguard version A.12.00.00 or later. \n";
        $text .= "\t\t       Migrate legacy pacakges to modular before ";
        $text .= "upgrading to Serviceguard version A.12.00.00 or later.\n";
        $text .= "\t\t       For more information, refer to cmmigratepkg(1m).\n"; 
        printOnConsole($text);
        close(LOG_FILE);
        exit $EXIT;
    }
}

$user_cred_sg = validateLogin();
if ($user_cred_sg) {
    exit $EXIT;
}

if ($distro =~ /sles/) {
    if ($automatic_ins != 0) {
        $text = "\tERROR: -a option is not supported ";
        $text .= "on SuSE Linux Enterprise Server.\n";
        print STDOUT $text;
        exit $EXIT;
    }
}

$direxists = dirExist($top_dir);
#if no value is entered or directory doesn't exist
if (($top_dir =~ /^\s*$/) || ($direxists)) {
    $text = "\tERROR:  The directory path specified in ".$top_dir." is ";
    $text .= "not valid. \n"; 
    printOnConsole($text);
    exit $EXIT;
}

if ($automatic_ins == 1) {
    if (! -e "/usr/bin/yum") {
        print STDOUT "\n\t\tERROR: Yum is not present on this system.";
        print STDOUT "\n\t\tAutomatic upgrade cannot go through without yum.\n";
        exit $EXIT;
    }    
}

#call to start the installation process
#build hash map for each SG portfolio product.
#hashmap contains information about name, location of rpm, whether to upgrade or install
#and any special option needed to be added.
create_product_hash();

#If Patch, -a not supported
if ($isPatch == 1) {
    if ($automatic_ins == 1) {
        print STDOUT "\tERROR: The -a option is not supported during patch upgrade.\n";
        exit $EXIT;
    }
}

$text = "\n\t-------------------------------------------------------------";
$text .= "-------\n";
$text .= "\tcmupgrade script execution started on node " .$execution_node. " [ ".$timestamp." ]\n";
$text .= "\t------------------------------------------------------------------";
$text .= "------\n";
printOnConsole($text);

#Pre-requisite checks
if ($automatic_ins == 1) {
    printOnConsole("\n\t$count_steps_gbl. Checking for the pre-requisite softwares that are required to be \n");
    printOnConsole("\t   installed from yum repositories. \n");
    $count_steps_gbl++; 
    ($yumretval, $java_err, @failed_yum_dep_rpms)  = doYumPreCheck();
    if ($yumretval != 0) {
        if (scalar(@failed_yum_dep_rpms) != 0) { 
            print STDOUT "\n\t\tFollowing rpms are not present in any yum repositories";
            print STDOUT "\n\t\tEnsure that they are installed before installing";
            print STDOUT "Serviceguard \n";
            foreach my $rpm_name (@failed_yum_dep_rpms) {
                    print STDOUT "\t\t$rpm_name \n";
            }
        } 
        if ($java_err == 1) {
            $yummsgtxt = "\t\t Java version should be higher than Java 1.7.0\n";
            $yummsgtxt .= "\t\t Upgrade your java version and make sure the output\n";
            $yummsgtxt .= "\t\t of the command \"which java\" is pointing to JDK >= 1.7\n";
        }  elsif ($java_err == 3) {
            $yummsgtxt = "\t\t The command \"java -d64 -version\" does not give expected output.\n";
            $yummsgtxt .= "\t\t Make sure 64 bit Java is installed.\n";
            $yummsgtxt .= "\t\t Make sure JDK(Java SDK) version 1.7 or greater is installed.\n";
        }
        print STDOUT $yummsgtxt; 
        exit $yumretval;
    } else {
        if (scalar(@failed_yum_dep_rpms) != 0) {
            if ($drs_pre_req_failed == 1) {
                $yum_prod_text = "serviceguard-metrocluster and related rpms"; 
            } elsif ($xdc_pre_req_failed == 1) {
                $yum_prod_text = "serviceguard-xdc";
            }
            $yummsgtxt = "\n\t\t".$yum_prod_text." will not be upgraded/installed \n";
            $yummsgtxt .= "\t\tas ". $yum_prod_text." are dependent on the following RPM(s) ";
            $yummsgtxt .= "and those RPM(s) are not present in yum repositories \n";
            print STDOUT $yummsgtxt;
            foreach my $rpm_name (@failed_yum_dep_rpms) {
                    print STDOUT "\t\t$rpm_name \n";
            }       
        }
    }
} else {
   (my $prereq_text, my $ret) = verify_pre_requisites();
   printOnConsole($prereq_text);
   if ($ret == 1) {
       $msgtext = "\t\tNOTE: Aborting installation as the pre-requisites are not met.\n";
       printOnConsole($msgtext); 
       exit $EXIT;
   }
}


#Creating an array which contains all the rpms that is installed but not present on CD/DVD.
#If there are such rpms, ask for user's inpur whether to proceed with the installation.
#No need to ask if bundle is patch bundle.
if ($isUpgrade == 1 ) {
    foreach my $my_product (@{$SG_Product->{product}}) {
            if ($my_product->{name} ne "serviceguard-metrocluster-emcsrdf") { 
                if (($my_product->{location} eq "notfound") && ($my_product->{option} eq "-Uvh")) {
                    push(@rpms_not_present, $my_product->{name});
                    if ($my_product->{name} =~ /toolkit/i) {
                        $isAdvancedInstalled = 1;
                    } elsif (($my_product->{name} =~ /metro/i) || ($my_product->{name} =~ /xdc/i)) {
                        $isEnterpriseInstalled = 1;
                    } 
                }
            } 
    }

    if ($isBundleUpgrade == 0) {
        $num_not_present = scalar @rpms_not_present;
        if ($num_not_present > 0) {
            printOnConsole("\t\tThe CD/DVD doesn't contain the following rpms which are installed on the system:\n");
            foreach my $element(@rpms_not_present) {
                printOnConsole("\t\t$element\n");
            }
            if ($isEnterpriseInstalled == 1) {
                $cd_level_txt = "HPE Serviceguard for Linux Enterprise";
            } elsif ($isAdvancedInstalled == 1) {
                $cd_level_txt = "HPE Serviceguard for Linux Advanced or HPE Serviceguard for Linux Enterprise";
            } 
            $msgtext = "\t\tDepending on the serviceguard related products installed on the node,\n";
            $msgtext .= "\t\tyou may have to order ".$cd_level_txt." CD/DVD. For more information,\n";
            $msgtext .= "\t\trefer to HPE Serviceguard A.12.10.00 for Linux Release Notes.\n"; 
            printOnConsole($msgtext); 
            exit $EXIT; 
        }
    }
}

if ($automatic_ins == 1) {
    createSGRepoFile();
}

printOnConsole("\n\t$count_steps_gbl. Upgrade process for Serviceguard and its components for");
printOnConsole(" $distro_text has started:\n\n");
$count_steps_gbl++;

install_sg_products();

if ($automatic_ins == 1) {
    removeSGRepoFile();
}

# printing summary
if ($success_txt !~ /^\s*$/) {
    $msgtext = "\n\t\t##########################################";
    $msgtext .= "##########################################\n";
    $msgtext .="\t\t\t\t\t             SUMMARY                     \n";
    $msgtext .= "\t\t##########################################";
    $msgtext .= "##########################################\n";
    printLog($msgtext); 
    $msgtext = "\t\tUpgrade of the following components completed successfully: \n"; 
    $msgtext .= "\t\t-------------------------------------------------------------\n";
    $msgtext .= $success_txt."\n";
    printOnConsole($msgtext);
}

if ($failure_txt !~ /^\s*$/) {
    $msgtext = "\t\tUpgrade of the following components failed: \n";
    $msgtext .= "\t\t-------------------------------------------------------------\n";
    $msgtext .= $failure_txt."\n";
    printOnConsole($msgtext);
} 

if ($sgmgr_usr_text !~ /^\s*$/) {
    $msgtext = "\t\tNOTE: ".$sgmgr_usr_text."\n"; 
    printOnConsole($msgtext);
}

$msgtext = "\t\t##########################################";
$msgtext .= "##########################################\n";
printLog($msgtext);

if ($global_failure == 1) {
    printOnConsole("\n\t\t***************ERROR: The upgrade procedure failed.*************** \n");
    $text = "with the above errors";
} elsif ($global_failure == 0 ) {
    printOnConsole("\n\n\t\t***************The upgrade procedure succeeded completely.***************\n");
    $text = "successfully";
}

$doc_text = displayDocInfo();
$doc_text .= "\n";
printLog($doc_text);
print STDOUT "\n\tThe logfile can be found at $log_file\n";
print STDOUT "\tLook for the latest logs appended to the file with timestamp.\n";
$timestamp = localtime time;
$final_text = "\n\t-----------------------------------------------------------"; 
$final_text .= "------------------------------\n";
$final_text .= "\tUpdate script execution completed $text [ ".$timestamp." ].\n";
$final_text .= "\t------------------------------------------------------------";
$final_text .= "-----------------------------\n";
printOnConsole($final_text);
if ($isCluster) {
    printProgress();
}
close(LOG_FILE); 
exit $global_failure;

#Subroutines
#####################################################################
#
# Subroutine     : printLog
# Calls          : none
# Called by      : main part of script and all other subroutines
# Globals        : $SUCCESS
# Input Params   : the message to be printed to the logfile
# Return value   : 0 to continue
#
# This subroutine is for logging all messages to the logfile only.
####################################################################

sub printLog
{
    my ($msg) = @_;
    print LOG_FILE $msg;
    return $SUCCESS;
}#end of printLog function

#####################################################################
#
# Subroutine     : printOnConsole
# Calls          : none
# Called by      : main part of script and all other subroutines
# Globals        : $SUCCESS
# Input Params   : the message to be printed to the logfile
# Return value   : 0 to continue
#
# This subroutine is for logging messages on console as well as logfile.
####################################################################

sub printOnConsole
{
    my ($msg) = @_;
    print STDOUT $msg;
    print LOG_FILE $msg;
    return $SUCCESS;
}#end of printOnConsole function

#####################################################################
#
# Subroutine     : printProgress
# Calls          : none
# Called by      : main part of script
# Globals        : $SUCCESS
# Input Params   : None
# Return value   : 0 to continue
#
# This subroutine prints overall status of rolling upgrade procedure. 
####################################################################

sub printProgress
{
    my @nodelist;
    my @nodever_unknown;
    my $version;
    my $nodename;
    my $nodecnt = 0;
    my $nodever = `cmviewcl -vf line | grep -w $execution_node | grep "sg_version" | awk -F. '{print \$2\$3\$4}'`;
    my @output = `cmviewcl -vf line | grep "sg_version"`;
    chomp($nodever);
    foreach my $line (@output) {
            chomp($line);
            (my $nodestr, my $versionstr) = split(/\|/, $line);
            # if a node is unreachable then the version will be "unknown"
            # throw a warning that node needs to be upgraded.
            if ($versionstr =~ /unknown/) {
                $nodename = (split(/:/, $nodestr))[1];
                push(@nodever_unknown, $nodename);
                $nodecnt++;
            }
            else {
                $version = join('',split(/\./,(split(/A./, $versionstr))[1]));
                $nodename = (split(/:/, $nodestr))[1];
                if ($version lt $nodever) {
                    push(@nodelist, $nodename);
                    $nodecnt++;
                }
            }
    }
   
    # Print progress summary only when Upgrade was succesfully completed. 
    if ($global_failure == 0) {    
        if ($nodecnt == 0) {
            printOnConsole("\tUpgrade procedure completed.\n");
        } else {
            printOnConsole("\tTo complete the upgrade of the entire cluster, ");
            printOnConsole("execute cmupgrade on the following nodes:\n");
            foreach $nodename (@nodelist) {
                printOnConsole("\t$nodename\n");
            }
            if (@nodever_unknown) {
                printOnConsole(" Following nodes version cannot be determined.\n");
                foreach $nodename (@nodever_unknown) {
                    printOnConsole("\t$nodename\n");
                }
                printOnConsole(" Execute cmupgrade on these nodes post bringing them up\n");
            }  
        } 
    }
    return $SUCCESS;
}#end of printProgress

#####################################################################
#
# Subroutine     : create_product_hash
# Calls          : checkIfBundleIsPatch, getDirPath, isProdInstalled
#                  getSuffix 
# Called by      : main part of script
# Globals        : sg_products, SG_Product, sg_product_map 
# Input Params   : None 
# Return value   : None 
#
# This subroutine creates SG_Product package object
####################################################################

sub create_product_hash
{
    my $earlier_name; 
    foreach my $name (@sg_products) {
            # variable to check if same version is already installed on the system. 
            $isSameVer = 0;
            $product = Product->new();
            $product->{name} = $name;
            $product->{location} = getDirPath($name);
            $product->{ver_on_cd} = "";            
            if (($product->{location} ne "notfound") && ($name !~ /serviceguard-extension-for-sap/)) {
               ($isSameVer) = checkIfBundleIsPatch($product->{location}, $name);
            } 
            # Keeping it in different location as we may reset the location to notfound  
            if ($product->{location} ne "notfound") {
                $product->{ver_on_cd} = getVersionOnCD($product->{location});
            }
            if (($name =~ /metrocluster/) || ($name =~ /xdc/)) {
                if ($product->{location} ne "notfound") {
                    $isEnterprise = 1;
                }
            }
            # Add only when pkg needs to be updated
            if ($isSameVer == 0) { 
                # If bundle is a patch bundle, pkgs follow same name
                # convention
                if ($isUpgrade == 1) {
                    $earlier_name = $sg_product_map{$name};
                } else {
                    $earlier_name = $name;
                }
                if ($earlier_name eq "new") {
                    $product->{option} = "-ivh";
                    $product->{suffix} = "";
                    $product->{action} = "installed";
                    $product->{action_str} = "installation"; 
                    $product->{installed_ver} = "";
                    $product->{former_text} = ""; 
                    if ($automatic_ins == 1) {
                        $product->{yum_cmd} = $YUM_INSTALL;
                        $product->{yum_cmd_suffix} = "";
                    }
                } else {
                    $is_prod_installed = isProdInstalled($earlier_name);

                    if (($is_prod_installed =~ /^\s*$/) && ($is_prod_installed !~ /incompatible/)) {
                        $product->{option} = "-ivh";
                        $product->{suffix} = "";
                        $product->{action} = "installed";
                        $product->{action_str} = "installation"; 
                        if ($automatic_ins == 1) {
                            $product->{yum_cmd} = $YUM_INSTALL;
                            $product->{yum_cmd_suffix} = "";
                        }
                    } else {
                        $product->{option} = "-Uvh";
                        $product->{suffix} = getSuffix($name);
                        $product->{action} = "upgraded";
                        $product->{action_str} = "upgrade"; 
                        if ($automatic_ins == 1) {
                            $product->{yum_cmd} = $YUM_UPGRADE;
                            $product->{yum_cmd_suffix} = getYumSuffix($name);
                        }
                    }
                    $product->{installed_ver} = `rpm -q --queryformat '%{Version}' $earlier_name`; 
                    if ($earlier_name ne $name) { 
                        $product->{former_text} = "(formerly known as ".$earlier_name.")";
                    } else {
                        $product->{former_text} = "";
                    } 
                }
                $SG_Product->addProduct($product);
            }
    }
}

#####################################################################
#
# Subroutine     : install_sg_products 
# Calls          : printLog 
# Called by      : main part of script
# Globals        : SG_Product
# Input Params   : None
# Return value   : None
#
# This subroutine installs/upgrades Serviceguard products. 
####################################################################

sub install_sg_products
{
    my $cmd_conf = "";
    my $out_line = ""; 
    my $drs_install_error = 0;
    foreach my $prod (@{$SG_Product->{product}}) {
            if ($prod->{location} ne "notfound") {
                # If metrocluster rpms are not upgraded properly, don't try to upgrade
                # metrocluster-addons rpm. 
                if (($prod->{name} =~ /addons/) && ($drs_install_error == 1)) {
                   next;
                }
                # If drs pre-requisites are not met, skip metrocluster insatllation. 
                if (($prod->{name} =~ /metrocluster/) && ($drs_pre_req_failed == 1)) {
                   next;
                }
                # If tog-pegasus is not installed on SLES, don't insatll metrocluster-caevap6000. 
                # On RHEL, There is no optinal DRS rpm. 
                if (($prod->{name} =~ /metrocluster-caevap6000/) && ($drs_optional_pre_req_failed == 1)) {
                   next;
                }
                # If oracle dataguard pre-requisites are not met, don't install
                # serviceguard-dataguard-toolkit rpm.
                if (($prod->{name} =~ /serviceguard-dataguard-toolkit/) &&
                    ($oracle_dataguard_pre_req_failed == 1)) {
                    next;
                }
                # If distro is other than RHEL5 or SLES11 then only 
                # install serviceguard-kvm-toolkit.
                if (($prod->{name} =~ /serviceguard-kvm-toolkit/) &&
                    (($distro =~ /rhel5/i) || ($distro =~ /sles11/i))) {
                    next;
                }
                # If xdc pre-requisites are not met, don't install xdc rpm. 
                if (($prod->{name} =~ /xdc/) && ($xdc_pre_req_failed == 1)) {
                   next;
                }
                
                if ($automatic_ins == 0) {
                    $cmd = "/bin/rpm ".$prod->{option}." ".$prod->{suffix}." ".$prod->{location};
                } else {
                    $cmd = $prod->{yum_cmd}." ".$prod->{yum_cmd_suffix}." ".$prod->{name};
                }
                if ($prod->{name} =~ /serviceguard-manager$/) {
                    $sgmgr_password = $ENV{SGMGR_ENV}; 
                    if ($sgmgr_password) {
                        $cmd = "export SGMGR_ENV=$sgmgr_password;" . $cmd;
                    }
                }
                @out = `$cmd 2>&1`;
                $fail = $? >> 8;
                $out_error = join("\t\t", @out);
                if ($fail || $out_error =~ /error/i) {
                    if ($out_error !~ /already installed/) {
                        $global_failure = $global_failure || $fail;
                        $msgtext = "\t\tERROR: Installation of\n\t$prod->{name}\n\tfailed with: \n\t";
                        $msgtext .= $out_error;
                        printLog($msgtext);
                        $failure_txt .= "\t\t".$prod->{name}.$prod->{former_text}." ".$prod->{action_str}." to ";
                        $failure_txt .= $prod->{ver_on_cd}." failed due to: \n\t\t";
                        $failure_txt .= $out_error; 
                        if (($prod->{name} =~ /serviceguard$/) || ($prod->{name} =~ /serviceguard-license$/))  {
                            last;
                        }
                        if (($prod->{name} =~ /metrocluster/) && ($prod->{name} !~ /addons/)) {
                            $drs_install_error = 1; 
                        }
                    } else {
                            $msgtext = "\t\t".$out_error;
                            printLog($msgtext);
                            
                            if ($prod->{name} !~ /serviceguard-extension-for-sap/) {
                                $failure_txt .= "\t\t".$prod->{name}.$prod->{former_text}." ".$prod->{action_str}." to ";
                                $failure_txt .= $prod->{ver_on_cd}." failed due to: \n\t\t";
                                $failure_txt .= $out_error; 
                            }
                    }
                } else {
                    if ($prod->{name} =~ /serviceguard-manager$/) {
                        if ($out_error =~ /Warning/ || $out_error =~ /WARNING/) {
                            $msgtext = "\t\t".$out_error;
                            print STDOUT $msgtext;
                        }
                    }
                    $success_dir_msgtext = "was ".$prod->{action}." in the system to ".$prod->{ver_on_cd}."\n";
                    $msgtext = "\t\t     $prod->{name} $success_dir_msgtext";
                    printLog($msgtext);
                    if ($prod->{option} =~ /U/) {                    
                        $success_txt .= "\t\t".$prod->{name}.$prod->{former_text}." ".$prod->{action}." from ";
                        $success_txt .= $prod->{installed_ver}." to ".$prod->{ver_on_cd}."\n"; 
                    } else {
                        $success_txt .= "\t\t".$prod->{name}.$prod->{former_text}." ".$prod->{ver_on_cd}." is ".$prod->{action}."\n";
                    } 
                }
        }
    }
}

#####################################################################
#
# Subroutine     : checkIfBundleIsPatch 
# Calls          : none
# Called by      : main part of script
# Globals        : isPatch, isUpgrade and isSameVer 
# Input Params   : Location and name of the package 
# Return value   : isPatch, isUpgrade and isSameVer 
#
# This subroutine compares the minor number of the pkg which is installed 
# and the which is shipped in a bundle. If major number is same and 
# minor number changes, the bundle is a patch. 
####################################################################

sub checkIfBundleIsPatch
{
   (my $loc, my $pkgname) = @_;
   
   my $installed_major_ver = qx(rpm -q --queryformat '%{Version}.%{Release}' $pkgname | awk -F. '{print \$2}');
   chomp($installed_major_ver);
   my $installed_minor_ver = qx(rpm -q --queryformat '%{Version}.%{Release}' $pkgname | awk -F. '{print \$3\$4}');
   chomp($installed_minor_ver);
   my $bundle_verstr = (split(/\-/, $loc))[-2];
   chomp($bundle_verstr);
   my $bundle_major_ver = qx(echo $bundle_verstr | awk -F. '{print \$2}');
   chomp($bundle_major_ver);
   my $bundle_minor_ver = qx(echo $bundle_verstr | awk -F. '{print \$3\$4}');
   chomp($bundle_minor_ver);
   

   if (($installed_major_ver =~ /^\s*$/) && ($bundle_major_ver eq $current_major_version) && 
      (scalar($bundle_minor_ver) ge 50)) {
      if ($pkgname eq "serviceguard-dataguard-toolkit") {
          #"dependency_check_for_oracle_tkt" flag will be set
          #to do dependency check of oracle-tkt rpm for 
          #oracle-dataguard
          $dependency_check_for_oracle_tkt = 1;
      } 
   }

   if (($installed_major_ver =~ /^\s*$/)) {
       if ($bundle_major_ver eq $current_major_version) {
            if ($bundle_minor_ver eq $current_minor_version)  
            {
                if ($bundle_major_ver eq "12") {
                    $isPatch = 1;
                } else {
                    $isUpgrade = 1;
                }
            } 
       } else {
           #To disallow user to install any RPM from incorrect location other than any bundle MR 
           #ISO or any bundle patch (12.00.xx) location.
           printOnConsole("\t\t Aborting upgradation since either mount path where ISO image\n"); 
           printOnConsole("\t\t is mounted or patch location is incorrect.\n"); 
           exit $EXIT;
       }
   } else {
       if ($bundle_major_ver lt $installed_major_ver) {
           printOnConsole("\t\t Aborting upgradation since higher version of $pkgname\n");
           printOnConsole("\t\t is already installed on the node.\n");
           exit $EXIT;
       } elsif ($bundle_major_ver gt $installed_major_ver) {
              $isUpgrade = 1;
       } else {
          if ($bundle_minor_ver lt $installed_minor_ver) {
              $isBundleUpgrade = 1;
              $product->{location} = "notfound";
          } elsif ($bundle_minor_ver gt $installed_minor_ver) {
              $isPatch = 1;
          } else {
              $isSameVer = 1;
          }
      }
   }
   return($isSameVer);
}

###################################################################
#
# Subroutine     : getDirPath
# Called by      : main
# Globals        : $top_dir, $distro
# Input Params   : the name of the rpm 
# Return value   : returns the directory path where the rpm files
#                  are located.
#
# This subroutine is to get the directory path for all the
# rpm files from the CD image.
####################################################################

sub getDirPath
{
    my $prod_dir_type = shift; 
    my $searchstr;
    my $dir_path;
    my $str;
  
    if ($prod_dir_type =~ /serviceguard-manager/) {
        $str = "linux"; 
    } elsif ($prod_dir_type =~ /toolkit/i) {
        if ($distro =~ /sles/) {
            $str = "sles";
        } else {
            $str = "redhat";
        }
    } else {
        if ($distro =~ /sles11/) {
            $str = "sles11";
        } elsif ($distro =~ /sles12/) {
            $str = "sles12";
        } elsif ($distro =~ /rhel5/i) {
            $str = "rhel5";
        } elsif ($distro =~ /rhel6/i) {
            $str = "rhel6";
        } elsif ($distro =~ /rhel7/i) {
            $str = "rhel7";
        }
    }
    
    if (($prod_dir_type =~ /serviceguard-manager/) || ($prod_dir_type =~ /metrocluster/) || ($prod_dir_type =~ /serviceguard-extension-for-sap/)) {
       $searchstr = $prod_dir_type."-B*".$str."*.rpm";
    } else {
       $searchstr = $prod_dir_type."-A*".$str."*.rpm";
    } 
    my @location = qx(find $top_dir -name "$searchstr" | grep $prod_dir_type);
    my $failure = $?;
    if ($failure) {
       $dir_path = "notfound";
    } else {
       foreach my $path (@location) {
               chomp($path);
               my $loc = `readlink $path`;
               if ($? != 0) {
                   $dir_path = $path;
                   last;
               }
       }
    }
    return $dir_path
} #end getDirPath

####################################################################
#
# Subroutine     : runandCaptureCommand
# Calls          : none
# Called by      : main part of the script 
# Globals        : None 
# Input Params   : the command to be executed
# Return value   : command status and output of the command executed
#
# This subroutine is for executing perl and shell commands.
####################################################################

sub runandCaptureCommand {

    my ($myCmd) = @_;
    my @lines = ();
    my @output = ();

    open(CMD, "$myCmd |") or return (1 , @output);
    while (<CMD>) {
        push(@output, $_);
        last if eof(CMD);
    }
    close(CMD);
    my $exitcode = ($? >> 8);
    return($exitcode, @output);
}

########################################################################
#
# Subroutine     : validateLogin
# Calls          : none
# Called by      : main
# Globals        : $SUCCESS, $EXIT
# Input Params   : none
# Return value   : returns 0 for success, 1 for failure
#
# This subroutine validates whether the script is run as root.
########################################################################

sub validateLogin
{
    #Check whether the user is root
    #if not, exit the script
    my $user = $ENV{'LOGNAME'};
    if ($user ne "root") {
        printOnConsole("\t\tERROR: Non-root users are not authorized to run cmupgrade.\n");
        return $EXIT;
    }
    return $SUCCESS;
}#end of validateLogin

########################################################################
#
# Subroutine     : getArch
# Calls          : none
# Called by      : script
# Globals        : none
# Input Params   : none
# Return value   : returns arch value for success, "" for failure
#
# This subroutine gets the arch value from the system whether its
# x86_64 and change it to the value its in the CD
# directory path as x86_64
########################################################################

sub getArch
{
    #getting the arch name
    my $arch = qx(uname -m);
    my $failure = $?;
    if ($failure) {
        print STDOUT "\t\t cmupgrade: Unable to get the system architecture\n.";
        exit $EXIT;
        return "";
    }
    chomp($arch);
    if( $arch =~ /x86_64/i ) { 
        $arch = lc($arch)
    }
    return $arch;
} #end of getArch

########################################################################
#
# Subroutine     : getSGVersion
# Calls          : none
# Called by      : script
# Globals        : none
# Input Params   : none
# Return value   : returns SG version value for success, "" for failure
#
########################################################################

sub getSGVersion
{
    #getting the arch name
    my $version = qx(rpm -q --queryformat '%{Version}.%{Release}' serviceguard);
    my $failure = $? >> 8;
    if ($failure) {
        print STDOUT "\t\t cmupgrade: Unable to get the serviceguard version\n.";
        exit $EXIT;
        return "";
    }
    $version = qx(echo "$version" |  awk -F. '{print \$2\$3\$4}'); 
    chomp($version);
    return $version;
} #end of getSGVersion

########################################################################
#
# Subroutine     : getnodestatus
# Calls          : none
# Called by      : script
# Globals        : none
# Input Params   : none
# Return value   : returns execution_node status value for success, "" for failure
#
########################################################################

sub getnodestatus
{
    #getting the arch name
    my $stat = `cmviewcl -f line -n $execution_node | grep status | cut -f 2 -d =`;
    my $failure = $? >> 8;
    if ($failure) {
        print STDOUT "\t\t cmupgrade: Unable to get the node status\n.";
        exit $EXIT;
        return "";
    }
    chomp($stat);
    return $stat;
} #end of getnodestatus

########################################################################
#
# Subroutine     : getVersionOnCD 
# Calls          : none
# Called by      : script
# Globals        : none
# Input Params   : location of the product
# Return value   : returns version on the CD 
#
# This subroutine gets the version on the CD given the  product location. 
########################################################################

sub getVersionOnCD 
{
    #getting the arch name
    my $prod_loc = shift;
    my $ver_cd = (split(/\-/, $prod_loc))[-2];
    return $ver_cd;
} #end of getVersionOnCD 

########################################################################
#
# Subroutine     : getSuffix
# Calls          : none
# Called by      : script
# Globals        : none
# Input Params   : name of the product 
# Return value   : returns suffix value
#
# This subroutine gets the suffix to be added during rpm installation. 
########################################################################

sub getSuffix
{
    #getting the arch name
    my $prod = shift;
    my $suffix;
    
    if ($prod =~ /xdc/) {
       $suffix = "--nopreun";
    } elsif ($prod =~ /toolkit/) { 
       $suffix = "--nopostun";
    } else {
       $suffix = "";
    } 
    return $suffix;
} #end of getSuffix 

########################################################################
#
# Subroutine     : getYumSuffix
# Calls          : none
# Called by      : script
# Globals        : none
# Input Params   : name of the product 
# Return value   : returns suffix value
#
# This subroutine gets the suffix to be added during yum installation. 
########################################################################

sub getYumSuffix
{
    #getting the arch name
    my $prod = shift;
    my $suffix;
    
    if (($prod =~ /xdc/) || ($prod =~ /toolkit/)) {
       $suffix = "--setopt=tsflags=noscripts";
    } else {
       $suffix = "";
    } 
    return $suffix;
} #end of getYumSuffix 

########################################################################
#
# Subroutine     : check_if_cluster_exists 
# Calls          : none
# Called by      : script
# Globals        : none
# Input Params   : none
# Return value   : returns 0 for success, 1 for failure
#
########################################################################

sub check_if_cluster_exists
{
    my $file_val = "$SGCONF/cmclconfig";
    if (-f $file_val && -s $file_val) {
        return(1);
    }
    return (0);
}

########################################################################
#
# Subroutine     : check_if_legacy_pkg_configured 
# Calls          : none
# Called by      : script
# Globals        : none
# Input Params   : none
# Return value   : returns 1 if legacy pkg in found else returns 0
#
########################################################################

sub check_if_legacy_pkg_configured
{
   my $legacyfound = `cmviewcl -f line -s config | grep "style=legacy"`;
   my $ret = $? >> 8;
   if ($ret == 0) {
       return (1);
   }
   return (0);
}
 
################################################################################
#
# Subroutine     : verify_pre_requisites
# Calls          : isProdInstalled
# Called by      : main part of the script 
# Globals        : @sg_rhel5_pre_requisites, @sg_rhel6_pre_requisites,
#                  @sg_sles11_pre_requisites, @sg_all_distro_pre_requisites, 
#                  @drs_pre_requisites, @xdc_pre_requisites
# Input Params   : none
# Return value   : "" if nothing to be installed or
#                  message text which have the products
#                  to be installed and return value.
#
# This subroutine verifies the pre-requisites that need to be
# installed before product installation are installed on the system
# or not. If there are pre-requisites not installed, then it returns
# the message text with the pre-requisites to be installed from
# the distribution CD.
################################################################################

sub verify_pre_requisites
{

    my $install_failure = "";
    my $ret_val = 0, my $java_error = 0;
    my $java_ret = 0; 
    my ($sg_required_rpm, $drs_optional_rpm);
    $sg_required_rpm = "";
    $drs_optional_rpm = "";
    my $drs_required_rpm = "";
    my $xdc_required_rpm = ""; 
    my $oracle_dataguard_required_rpm = "";
    my @install_sg_pre_req;
    my $dash = "\t\t-----------------------------------------------------------";
    $dash .= "-----------\n";
    my $msgtxt = "", my $txt = "";

    #software required for SG install
    printOnConsole("\n\t$count_steps_gbl. Checking for the pre-requisite softwares that are required to be \n");
    printOnConsole("\t   installed from the Linux Distribution CD/web. \n");
    $count_steps_gbl++;
    if ($distro =~ /sles11/) {
        @install_sg_pre_req = @sg_sles11_pre_requisites;
        $txt = "SuSE Linux Enterprise Server";
    } elsif ($distro =~ /sles12/) {
        @install_sg_pre_req = @sg_sles12_pre_requisites;
        $txt = "SuSE Linux Enterprise Server";        
    } elsif ($distro =~ /rhel5/i) {
         @install_sg_pre_req = @sg_rhel5_pre_requisites;
         $txt = "Red Hat Enterprise Linux";
    } elsif ($distro =~ /rhel6/i) {
        @install_sg_pre_req = @sg_rhel6_pre_requisites;
        $txt = "Red Hat Enterprise Linux";
    } elsif ($distro =~ /rhel7/i) {
        @install_sg_pre_req = @sg_rhel7_pre_requisites;
        $txt = "Red Hat Enterprise Linux";
    }

    push (@install_sg_pre_req, @sg_all_distro_pre_requisites);
    
    foreach(@install_sg_pre_req) {
        $install_failure = isProdInstalled($_);
        if ($install_failure =~ /incompatible/) {
            $sg_required_rpm .= $_."(x86_64), ";
        } elsif ($install_failure =~ /^\s*$/) { 
            $sg_required_rpm .= $_.", ";
            printOnConsole("\t\t$_ does not exist on the system\n");
        } else {
            printLog("\t\t $_ exists in the system\n");
        }
    } #end of foreach

    # Check for Java dependency
    my $java_version = qx(java -d64 -version 2>&1); 
    ($java_ret, $java_error) = checkJava(); 
    if (!$java_error) {
        printLog("\t\t Java exists in the system\n");
    }

    if ($java_error == 1) {
        $msgtxt .= "\t\t Java version is $java_version\n";
        $msgtxt .= "\t\t Java version should be higher than Java 1.7.0\n";
        $msgtxt .= "\t\t Upgrade your java version and make sure the output\n";
        $msgtxt .= "\t\t of the command \"which java\" is pointing to JDK >= 1.7\n";
        $ret_val = 1;
    }  elsif ($java_error == 3) {
        $msgtxt .= "\t\t The command \"java -d64 -version\" does not give expected output.\n";
        $msgtxt .= "\t\t Make sure 64 bit Java is installed.\n";
        $msgtxt .= "\t\t Make sure JDK(Java SDK) version 1.7 or greater is installed\n";
        $ret_val = 1;
    }

    if ($isEnterprise == 1) {
        foreach(@drs_pre_requisites) {
                $install_failure = isProdInstalled($_);
                if ($install_failure =~ /incompatible/) {
                    if ($_ ne "tog-pegasus") {
                        $drs_required_rpm .= $_."(x86_64), ";
                    } else {
                        if ($distro =~ /sles/i) { 
                            $drs_optional_rpm .= $_."(x86_64), ";
                        } else {
                             $drs_required_rpm .= $_."(x86_64), ";
                        } 
                    }
                } elsif ($install_failure =~ /^\s*$/ ) {
                       if ($_ ne "tog-pegasus") {
                           $drs_required_rpm .= $_.", ";
                           printOnConsole("\t\t$_ does not exist on the system\n");
                       } else {
                           if ($distro =~ /sles/i) { 
                               $drs_optional_rpm .= $_.", ";
                           } else {
                               $drs_required_rpm .= $_.", ";
                           } 
                           printOnConsole("\t\t$_ does not exist on the system\n"); 
                       }
                } else {
                       printLog("\t\t $_ exists in the system\n");
                }
        }#end of foreach

        foreach(@xdc_pre_requisites) {
                $install_failure = isProdInstalled($_);
                if ($install_failure =~ /incompatible/) {
                        $xdc_required_rpm .= $_."(x86_64), ";
                } elsif ($install_failure =~ /^\s*$/ ) {
                           $xdc_required_rpm .= $_.", ";
                           printOnConsole("\t\t$_ does not exist on the system\n");
                } else {
                       printLog("\t\t $_ exists in the system\n");
                }
        }#end of foreach

        if ($xdc_required_rpm) {
            $xdc_required_rpm =~ s/,\s*$//;
            $xdc_pre_req_failed = 1;
            $msgtxt .= "\n\t\tServiceguard-xdc will not be upgraded/installed \n";
            $msgtxt .= "\t\tas $arch version of the following RPM is not installed \n";
            $msgtxt .= "\t\t".$xdc_required_rpm."\n".$dash;
            $msgtxt .= "\n";
        }

        if ($dependency_check_for_oracle_tkt) {
            foreach(@oracle_dataguard_pre_requisites) {
                $install_failure = isProdInstalled($_);
                if ($install_failure =~ /incompatible/) {
                    $oracle_dataguard_required_rpm .= $_."(x86_64), ";
                } elsif ($install_failure =~ /^\s*$/ ) {
                    $oracle_dataguard_required_rpm .= $_.", ";
                    printOnConsole("\t\t$_ does not exist on the system\n");
                } else {
                    printLog("\t\t $_ exists in the system\n");
                }
            }

            if ($oracle_dataguard_required_rpm) {
                $oracle_dataguard_required_rpm =~ s/,\s*$//;
                $oracle_dataguard_pre_req_failed = 1;
                $msgtxt .= "\n\t\tServiceguard-dataguard-toolkit will not be upgraded/installed \n";
                $msgtxt .= "\t\tas $arch version of the following RPM is not installed \n";
                $msgtxt .= "\t\t".$oracle_dataguard_required_rpm."\n".$dash;
                $msgtxt .= "\n";
            }
        }

        if ($drs_required_rpm) {
            $drs_required_rpm =~ s/,\s*$//;
            $drs_pre_req_failed = 1; 
            $msgtxt .= "\n\t\tServiceguard-metrocluster and related rpms will not be upgraded/installed \n";
            $msgtxt .= "\t\tas $arch version of the following RPM is not installed \n";
            $msgtxt .= "\t\t".$drs_required_rpm."\n".$dash;
            $msgtxt .= "\n";
        } else {   
            if ($drs_optional_rpm) {
                $drs_optional_rpm =~ s/,\s*$//;
                $drs_optional_pre_req_failed = 1; 
                $msgtxt .= "\n\t\tServiceguard-metrocluster-caevap6000 will not be upgraded/installed \n";
                $msgtxt .= "\t\tas $arch version of the following RPM is not installed \n";
                $msgtxt .= "\t\t".$drs_optional_rpm."\n".$dash;
                $msgtxt .= "\n";
            }
        } 
    }

    if ($sg_required_rpm) { 
    #removing the "," at the end
        $sg_required_rpm =~ s/,\s*$//;
        $sg_required_rpm = $dash."\t\t".$sg_required_rpm;
        $msgtxt .= "\n\t\tServiceguard requires $arch version of the following RPMs from the \n";
        $msgtxt .= "\t\t".$txt." Distribution CD.\n";
        $msgtxt .= $sg_required_rpm."\n".$dash;
        $msgtxt .= "\n"; 
        $msgtxt .= "NOTE: Aborting installation as the pre-requisites are not met \n";
        $ret_val = 1; 
   } 

   return ($msgtxt, $ret_val);
} #end of function verify_pre_requisites 
    
############################################################################
#
# Subroutine     : dirExist
# Calls          : None
# Called by      : main part of the script
# Globals        : $SUCCESS, $EXIT
# Input Params   : none
# Return value   : 0 for success, 1 for failure
#
# This subroutine verifies whether the directory exists or not.
############################################################################

sub dirExist
{
    my $dir = shift;
    if ( -d $dir ) {
        return $SUCCESS;
    }
    printLog("\tERROR:  The directory path $dir does not exist.\n");
    return $EXIT;
} #end of function dirExist

#####################################################################
#
# Subroutine     : get_distro_version 
# Calls          : none
# Called by      : getDistro 
# Globals        : none 
# Input Params   : OS release 
# Return value   : Returns distro and the Directory path of rpms in CD 
#
# This subroutine sets the order of installation for SGManager
# and its components.
######################################################################

sub get_distro_version 
{
    my $distro = shift;
    my (@distro_out, my @split_again) = ();
    my ($distro_ver, $distro_dir, $not_supported, $distro_minorver);
    my @rhversion = (5, 6, 7);
    my @suversion = (11, 12);
   
    if (-f '/etc/' . $distro) {
        @distro_out = qx(cat /etc/$distro);
        chomp($distro_out[0]);
        $distro_out[0] =~  /(\d+\.?\d+)/ ;
        $not_supported = "$1";
        @split_again = split(/\./, $not_supported);
        $distro_ver = $split_again[0];
        if ($distro eq "redhat-release") {
            if ($not_supported !~ /6.0/) {
                if ($not_supported =~ /5./) { 
                    $distro_minorver = $split_again[1];
                    if ($distro_minorver < 7) {	
                        return ("not_supported","") ;				
                    }
                }
                if (grep {$_ eq $distro_ver} @rhversion) {
                    @split_again = split(/\./, $distro_ver);
                    $distro_ver = $split_again[0]; 
                    $distro = "rhel$distro_ver";
                    $distro_dir = "RedHat$distro_ver";
                    return($distro, $distro_dir);
                }
            }
        }
        elsif ($distro eq "SuSE-release" ) {
            if (grep {$_ eq $distro_ver} @suversion) {
                $distro = "sles$distro_ver" . "update";
                my @patchout = grep(/PATCHLEVEL/, @distro_out);
                chomp($patchout[0]);
                my @split_patch = split(/=/,$patchout[0]);
                chomp($split_patch[1]); 
                $split_patch[1] =~ s/^\s+// ;
                if ($split_patch[1] < 2 && ($distro_ver == '11')) {
                    return ("not_supported","") ;
                }				
                $distro = $distro . $split_patch[1]; 
                $distro_dir = "SLES$distro_ver"; 
                return($distro, $distro_dir);
            }
        }
    }
    elsif ( -f('/etc/os-release')) {
        my ($major_ver, $minor_ver);
        open (OS_RELEASE, '/etc/os-release') || die "Cannot open /etc/os-release\n";
        my @contents = <OS_RELEASE>;
        close OS_RELEASE;

        foreach my $line(@contents) {
            if($line =~ /^ID\b/) {
                my ($lh, $rh) = split /=/, $line;
                chomp($rh);
                $rh =~ s/"//g;
                if ($rh =~ /sles/i) {
                    $distro = "sles";
                    $distro_dir = "SLES";
                } elsif ($rh =~ /rhel/i) {
                    $distro = "rhel";
                    $distro_dir = "RedHat";
                }
            }
            if ($line =~ /^PRETTY_NAME\b/) {
                my ($lh, $rh) = split /=/, $line;
                $rh =~ s/[^\d+\.?\d*]//g;
                ($major_ver, $minor_ver) = split /\./, $rh;
            }
        }
        $distro = $distro . $major_ver;
        $distro_dir = $distro_dir . $major_ver;
        return($distro, $distro_dir);
    }

    return ("not_supported","") ;
}
   
###################################################################
#
# Subroutine     : getDistro
# Calls          : get_distro_version
# Called by      : script
# Globals        : none
# Input Params   : none
# Return value   : distro, distro directory as in the
#                  CD image for success, "", "" for failure
#
# This subroutine gets the distro type like rhel5/rhel6
# and depending on the distro value, sets the distro directory
# (RedHat5/RedHat6) that exists in the CD image path.
###################################################################

sub getDistro
{
    my ($distro, $distro_dir) = "";
    my @supported_release = ('red hat', 'SuSE');
    my $failure = 0;

    my $distro_info = `cat /proc/version 2>&1`;
    foreach (@supported_release) {
        if ($distro_info =~ /$_/i) {
            $_ =~ s/\s*//g ;
            qx(/usr/bin/test -f "/etc/$_-release" || /usr/bin/test -f "/etc/os-release");
            $failure = $? ;
            if (!$failure) {
                ($distro, $distro_dir) = get_distro_version("$_-release");
                return($distro, $distro_dir) ;
            } else {
                printOnConsole("\t\tUnable to identify Linux distribution information.\n");
                exit $EXIT;
            }
        }
    }
    $distro = "not_supported";
    return($distro, $distro_dir) ;
} # getDistro 

#################################################################
#
# Subroutine     : isProdInstalled
# Calls          : none
# Called by      : main part of the script and verify_pre_requisites
# Globals        : none
# Input Params   : rpm file name pattern(eg. "serviceguard") 
# Return value   : rpm name for success, "" for failure
#
# This subroutine verifies whether the product is installed or not.
################################################################

sub isProdInstalled
{
    my $prod = shift;
    my $rpm_file = "";
    my @rpm_file_names = ();
    my $failure;

    #check for the installed product
    my $op = `/bin/rpm -q --qf '%{arch}' $prod 2>&1`;
    if ($? eq 0 ) { 
        if ($op =~ /x86_64/i || $op =~ /noarch/) {
            @rpm_file_names = `/bin/rpm -q $prod 2>&1`;
            $failure = $?;
            if(!$failure) {
                foreach(@rpm_file_names) {
                    chomp($_);
                    if ($_ =~ /\Q$prod\E/) {
                        $rpm_file = $_ ;
                        last;
                   }
                } #end of foreach
            } #end of else if prod installed
        } else {
                &printOnConsole("\t\t ERROR: Architecture mismatch of $prod RPM\n");
                &printOnConsole("\t\t        $op RPM $prod is installed on $arch system\n");
                &printOnConsole("\t\t        Remove and install a $arch version of $prod\n");
			
                $rpm_file = "incompatible";
                return $rpm_file;
        }
    }
    return $rpm_file;
} #end of isProdInstalled function

###################################################################
#
# Subroutine     : displayUsage
# Calls          : none
# Called by      : main part of the script and parse_inputs
# Globals        : none
# Input Params   : none
# Return value   : none
#
# This subroutine gives the details of the usage of the script. 
###################################################################

sub displayUsage
{
    print "\tUsage:       cmupgrade [OPTION] \n".
          "\t{-d <mount path where ISO image is mounted | my-patch-location>} ".
          "\t[-a <automatic installation of pre-requisites if yum is configured>] ".
          "{-d <mount path where ISO image is mounted>}\n". 
          "\t[-h help] [--help] \n\n".         
          "\tDescription: This script is for easy upgrade of\n".
          "\t             Serviceguard portfolio products and required components.\n\n".
          "\tRequirement: This script requires the user to download the Serviceguard\n".
          "\t             CD/DVD image and mount the CD/DVD path or download the\n".
          "\t             Serviceguard patch and extract the patch. During the course\n". 
          "\t             of upgrade, there may be files required from Linux Distribution\n".
          "\t             CD or web. If -a option is specified, pre-requisites will be \n".
          "\t             installed automatically using yum. The -a option is only supported \n".
          "\t             on RedHat Enterprise Server. The -a option is not supported \n".
          "\t             with patch upgrade. This script needs to be run as root.\n";
    		  
    exit;
} #end of function displayUsage

#########################################################################
#
# Subroutine     : parse_inputs
# Calls          : none
# Called by      : main part of the script
# Globals        : none
# Input Params   : none
# Return value   : none
#
# This subroutine gives the details of the usage of the script.
#########################################################################
sub parse_inputs {
    GetOptions (
                "d=s" => \$top_dir, 
                "a" => \$automatic_ins,
                "h" => \$flag,
                "--help" => \$flag
               )or die displayUsage();

    #If no inputs is provided displays usage message and exits
    if ($#ARGV == 0) {
        print STDOUT "\tInvalid Options\n\n";
        displayUsage();
    }

    #if help or -h is provided then it exits again displaying help
    if ($flag eq 1) {
        displayUsage();
    }

    # Either update or installation mount directory path has to be specified
    if ($top_dir eq "") {
           print STDOUT "\tSpecify the mount directory path. \n" ;
           displayUsage();
    }
 
}

################################################################################
#
# Subroutine     : displayDocInfo
# Calls          : none
# Called by      : Main part of the script
# Globals        : none
# Input Params   : none
# Return value   : message text
#
# This subroutine gives the url of the referral doc
################################################################################

sub displayDocInfo
{
    $msgtext = "\n\t\tFor more information, refer the User Guide at:\n";
    $msgtext .= "\t\twww.hpe.com/info/linux-serviceguard-docs\n";
    $msgtext .= "\t\t HPE Serviceguard for Linux Version A.12.10.00 Deployment Guide.\n";
    return $msgtext;
} #end of function displayDocInfo

################################################################################
#
# Subroutine     : removeSGRepoFile
# Calls          : none
# Called by      : main
# Globals        : $repo_config_file
# Input Params   : none
# Return value   : $SUCCESS, $EXIT
#
# This subroutine removes repo directory.
################################################################################
sub removeSGRepoFile
{
    my $remove_repo_file_cmd = "$RM -f $repo_config_file";
    my ($retval, @rmcmdOutput) = runandCaptureCommand($remove_repo_file_cmd);
    return($SUCCESS); 
}

################################################################################
#
# Subroutine     : createSGRepoFile
# Calls          : none
# Called by      : main
# Globals        : $distro
# Input Params   : none
# Return value   : $SUCCESS, $EXIT
#
# This subroutine handles installing automatically dependent rpms by creating a
# serviceguard repo file
################################################################################
sub createSGRepoFile
{
    my $cmd_conf;
   
    my @yumCmdOutput = ();
    my $filehandle;    
    my $retval;
    #Build serviceguard repo lines
    my $sg_repo_lines = "[SGRPMS]\n";
    $sg_repo_lines .= "name=ServiceguardRPMS\n";
    $sg_repo_lines .= "baseurl=file://" . $top_dir."/RedHat/".$distro_dir."/"."\n";
    $sg_repo_lines .= "enabled=1\n";
    $sg_repo_lines .= "gpgcheck=0\n";
        
    #Search for repos directory
   
    my $cat_cmd = "$CAT /etc/yum.conf|grep reposdir=";
    ($retval, @yumCmdOutput) = runandCaptureCommand($cat_cmd);	
    my @reposdir_line_values = (); 
    if (scalar(@yumCmdOutput) != 0) {
        chomp($yumCmdOutput[0]);
        @reposdir_line_values = split(/=/,$yumCmdOutput[0]);
        chomp($reposdir_line_values[1]);
    }
    if (@reposdir_line_values) { 
        $repo_config_file = $reposdir_line_values[1] . "/";  
    }
		
    $repo_config_file .= "serviceguard.repo";
    open($filehandle, ">".$repo_config_file);
    print $filehandle $sg_repo_lines;
    close($filehandle);
	
    my $yum_cmd = "$YUM_CLEAN_ALL";
    ($retval, @yumCmdOutput) = runandCaptureCommand($yum_cmd);
    if ($retval != 0) {
        print STDOUT "\n$yum_cmd failed with following error:\n @yumCmdOutput";
        print STDOUT "\nCorrect the above error(s) before installaling again.\n";
        return($retval);
    }
}

################################################################################
#
# Subroutine     : checkJava 
# Calls          : none
# Called by      : doYumPreCheck, verify_pre_requisites 
# Globals        : None 
# Input Params   : None 
# Return value   : Returns 1 if java dependency is not met, also sets java_error 
#
# This subroutine checks if java dependency is satisfied. 
################################################################################
sub checkJava
{
    # Check for Java dependency
    my $ret_val = 0;
    my $java_error = 0; 
    my $java_version = qx(java  -d64 -version 2>&1);
    if ($? eq 0) {
        my $op = qx(java -d64 -version 2>&1 |head -1 | awk '{print \$NF}'| cut -d '"' -f 2 | cut -d '_' -f 1);
        $java_version = $op;
        $op =~ s/\.//g;
        if ($op < 170) {
            $java_error = 1;
            $ret_val = 1; 
        }
    } else {
        $java_error = 3;
        $ret_val = 1; 
    }
    
   return($ret_val, $java_error); 
}
################################################################################
#
# Subroutine     : doYumPreCheck
# Calls          : none
# Called by      : doAutomaticInstallation_RHEL
# Globals        : $YUM_LIST, $distro
# Input Params   : distro
# Return value   : returns list of failed depenedent rpms on the node along with status. 
#
# This subroutine verifies if pre-requisites are met   
################################################################################
sub doYumPreCheck
{
    my $ret=0;
    my $java_ret = 0;
    my $java_error_val = 0; 
    my @yumCmdOutput = ();
    my $yum_cmd = "$YUM_LIST";
    my @failed_dep_arr =();
    my @sgdep_pre_req = ();
    my $dep_check_ret = 0;

    ($ret, @yumCmdOutput) = runandCaptureCommand($yum_cmd);
    if ($ret !=0) {
        return($ret);
    }
	
	if ($distro =~ /rhel6/) {
        @sgdep_pre_req = @sg_rhel6_pre_requisites;
    } elsif ( $distro =~ /rhel5/ ) {
        @sgdep_pre_req = @sg_rhel5_pre_requisites;
    } elsif ( $distro =~ /rhel7/ ) {
        @sgdep_pre_req = @sg_rhel7_pre_requisites;
    }

    push(@sgdep_pre_req, @sg_all_distro_pre_requisites);
    foreach my $rpm_name (@sgdep_pre_req) {
        if (!grep(/$rpm_name/, @yumCmdOutput)) {
            push(@failed_dep_arr, $rpm_name); 
            $dep_check_ret = 1;
        } 
    }

    ($java_ret, $java_error_val) = checkJava();
    if ($java_ret != 0) {
        $dep_check_ret = 1;
    }
 
    if ($isEnterprise == 1) {
        foreach my $rpm_name (@drs_pre_requisites) {
                if (!grep(/$rpm_name/, @yumCmdOutput)) {
                    push(@failed_dep_arr, $rpm_name); 
                    $drs_pre_req_failed = 1;
                } 
        }

        foreach my $rpm_name (@xdc_pre_requisites) {
                if (!grep(/$rpm_name/, @yumCmdOutput)) {
                    push(@failed_dep_arr, $rpm_name); 
                    $xdc_pre_req_failed = 1; 
                } 
        }
    } 
   
    return ($dep_check_ret, $java_error_val, @failed_dep_arr);
}
