# Copyright 2008-2012 Cumulus Systems Incorporated.
# All Rights Reserved.

# This file contains the code to verify the connection to an HNAS.
#
# @param : IP Address - HNAS SMU IP Address
#
# @return : In case of Success, returns 0. In case of Failure, returns 1.
# output file will have this sample output written in case of success
# <?xml version="1.0" encoding="UTF-8"?>
# <SMU> <Result> <status>SUCCESS</status> </Result>
# <Server> <ip-address>192.0.2.2</ip-address>
#	   <Node> <id>1</id> <ip-address>192.0.2.199</ip-address> </Node>
#	   <Node> <id>2</id> <ip-address>192.0.2.201</ip-address> </Node>
# </Server>
# </SMU>
#
#
# Sample command: perl hnasConnectionVerifier.pl <IP Address> <SMU UserId> <SMU Password> <Output File>

#!/usr/bin/perl -w

# It is used for strict compilation.
use strict;

# It is used to get base file name from the complete file name.
use File::Basename;

# These are used to get the current date and time.
use Time::HiRes qw(gettimeofday);
use POSIX "strftime";

# This is used to create folder recursively.
use File::Path qw(mkpath);

use IO::File;

use POSIX qw(tmpnam);


$| = 1; #Auto flush on for writing to log file

# ----------------------------------------------------------------------------------------------------------------------------------------------------
# GLOBAL Variables
# ----------------------------------------------------------------------------------------------------------------------------------------------------

#megha default location
#use constant APP_HOME => "F://Megha//HNAS//work//megha//server//deploy";
use constant APP_HOME => "/usr/local/megha";
#use constant APP_HOME => "/usr/local/megha";

# This variable is used to store the complete name of log file.
my $logFile = "";

# This variable is used to store the complete name of file where data from HNAS will be dumped.
my $verificationDumpFile = "";

# This variable is used to store the HNAS User-Id which is used to get the Storage Configuration data.
my $hnasSMUUserId = "";

# This variable is used to store the HNAS Password corresponding to $hnasConfUserId.
my $hnasSMUPassword = "";

# This variable is used to store the HNAS IP Address.
my $hnasSMUIpAddress = "";

# This variable is used to store the return status of function calls.
my $status = 0;

# This variable is used to store the file handle of log file.
my $LOG_HANDLE;

#This varaible will hold the temporary file created, which holds the output of the expect script
my $cmdOutputFile = "";

# This variable is used to store the status of HNASConfiguration credential verification.
my $hnasCredentialVerified = 0;

# This variable is used to store the location of HNASruntime files.
my $hnasRunTimeLocation = "";

# This variable is used to store the complete path of MARS app.properties file.
my $appPropertiesFilePath = "";

# ----------------------------------------------------------------------------------------------------------------------------------------------------
# Main function
# ----------------------------------------------------------------------------------------------------------------------------------------------------

# Initialize the environment.
$status = init();
if (0 != $status)
{
    logMsg("Error: Call to init() failed.");
    goto EXIT;
}

# Verify HNAS credentials.
$status = verifyHNASCredential();
if (0 != $status)
{
    logMsg("Error: Call to verifyConfCredential() failed.");
    goto EXIT;
}

EXIT:

# Do any cleanup tasks before exiting the program.
deInit();

exit $status;

# ----------------------------------------------------------------------------------------------------------------------------------------------------
# Sub-routines
# ----------------------------------------------------------------------------------------------------------------------------------------------------

# This function is used to verify HNASConfiguration credentials.
#
# @affected global variables :
#   $hnasCredentialVerified
#
# @return :
#   0 if Success
#   1 if Error
sub verifyHNASCredential
{
    # This variable is used to store the return value of function calls.
    my $retVal = 0;

    # Connect to the HNAS and fetch some configuration data.
    $retVal = getConfData();
    if (0 != $retVal)
    {
        logMsg("Error: Call to getConfData() failed.");
        return 1;
    }

    verifyConfData();
    
    
    $hnasCredentialVerified = 1;

    return 0;
}



# This function is used to initialize the environment to run the Perl script correctly.
#
# @affected global variables :
#   $logFile
#   $LOG_HANDLE
#   $hnasIpAddress
#   $appPropertiesFilePath
#
# @return :
#   0 if Success
#   1 if Error
sub init
{
    # This variable is used to store the return value of function calls.
    my $retVal = 0;

    # This variable is used to store the base folder path on the MARS probe.
    my $baseFolder = "";

    # Set MARS base folder.
    $baseFolder = APP_HOME;

    #for appending current date to our log file
    my ($seconds, $microseconds) = gettimeofday;
    my $currentTime = strftime("%Y-%m-%d %H:%M:%S", localtime($seconds));
    my($date,$time)=split(' ',$currentTime,2);
    
    $logFile = $baseFolder."/logs/hnasPerlScript.".$date.".log";

    # Open the log file.
    open($LOG_HANDLE, ">>", $logFile) or die "Not able to open the file: [$logFile].";

   # If number of command line arguments are not correct then quit.
    my $args = $#ARGV + 1;
    if (4!= $args)
    {
        print "perl hnasConnectioVerifier.pl <SMU IP Address>  <UserName> <Password> <Output File>";
        logMsg("Error: Number of arguments to hnasConnectioVerifier.pl are not correct.");
        logMsg("Input arguments = ".$args);
        $retVal = 1;
        goto EXIT;
    }

    # Get the HNAS IP Addrss from command line argument.
    $hnasSMUIpAddress = $ARGV[0];
    logMsg("Info: Input IP Address = [$hnasSMUIpAddress]");

    # Get the HNAS SMU User name from command line argument.
    $hnasSMUUserId = $ARGV[1];
    logMsg("Info: Input SMU User = [$hnasSMUUserId]");

    # Get the HNASConf password from command line argument.
    $hnasSMUPassword = $ARGV[2];
    #logMsg("Info: Input Conf Password = [<Password>]");

    # Set the file name where the HNAS data will be dumped.
    $verificationDumpFile = $ARGV[3];

    
    
    if ("" eq $hnasSMUIpAddress)
    {
        logMsg("Error: HNAS SMU IP Address not present in the properties file.");
        $retVal = 1;

        goto EXIT;
    }
    
    
    if ("" eq $hnasSMUUserId)
    {
        logMsg("Error: HNAS SMU User-Id not present in the properties file.");
        $retVal = 1;

        goto EXIT;
    }

    if ("" eq $hnasSMUPassword)
    {
        logMsg("Error: HNAS SMU Password not present in the properties file.");
        $retVal = 1;

        goto EXIT;
    }

    if ("" eq $verificationDumpFile)
    {
        logMsg("Error: Temp file not specified in hnasConnectionVerifier.");
        $retVal = 1;

        goto EXIT;
    }
    
    #holds the command output
    $cmdOutputFile = "";

    # try new temporary filenames until we get one that didn't already exist
    do { $cmdOutputFile = tmpnam() }
        until my $fh = IO::File->new($cmdOutputFile, O_RDWR|O_CREAT|O_EXCL);

    # install atexit-style handler so that when we exit or die,
    # we automatically delete this temporary file
    END { unlink($cmdOutputFile) or die "Couldn't unlink $cmdOutputFile : $!" }
    
    # Set the complete path of MARS app.properties file.
    $appPropertiesFilePath = $baseFolder."/conf/app.properties";
    logMsg("Info: app.properties file path: [$appPropertiesFilePath].");

    # Read the content of app.properties file.
    $retVal = readAppPropertyFile();
    if (0 != $retVal)
    {
        logMsg("Error: Call to readAppPropertyFile() failed.");
        $retVal = 1;

        goto EXIT;
    }

EXIT:

    return $retVal;
}

# This function is used to run a shell script which connects to the HNAS and dump some configuration data in a file.
#
# @affected global variables :
#   None
#
# @return :
#   0 if Success
#   1 if Error
sub getConfData
{
    # This variable is used to store the exit status of "system" command.
    my $exitCode = 0;

    # This variable is used to store the command to get the HNASconf data.
    my $cmd = "";

    # Construct the command to get the HNASConf data.
    $cmd = "'".$hnasRunTimeLocation."/hnasGetConfData.sh' Verification $hnasSMUIpAddress $hnasSMUUserId $hnasSMUPassword > $cmdOutputFile";
    
    logMsg("Info: Running command: [$hnasRunTimeLocation/hnasGetConfData.sh Verification $hnasSMUIpAddress $hnasSMUUserId <Password> > $cmdOutputFile].");

    # Run the command to get the HNASConf data.
    $exitCode = system($cmd);
    if (0 != $exitCode)
    {
        logMsg("Error: Failed to execute: [hnasGetConfData.sh].");
        return 1;
    }

    logMsg("Info: Executed Shell script for connecting to HNAS.");

    return 0;
}

# This function is used to verify the data retrieved from the HNAS.
#
# @affected global variables :
#   None
#
# @return :
#   0 if Storage connection is successful.
#   1 if Storage connection failed.
sub verifyConfData
{
    # This variable is used to store the return value of the function.
    my $retVal = 0;

    # It is used to check whether we found correct information in the Verification dump file.
    my $found = 0;
    
    # Count  no of occurences of "?assword".
    my $cnt=0;
    
    logMsg("Info: Opening HNAS verification dump file. File = [$cmdOutputFile].");

    open(CONF_DUMP, $cmdOutputFile) or die logMsg("Error: Not able to open the file: [$cmdOutputFile].");
    open(CONF_DUMP_PASS, $cmdOutputFile) or die logMsg("Error: Not able to open the file: [$cmdOutputFile].");
    open(IP_LIST_FILE, ">", $verificationDumpFile) or die "Not able to open the file: [$verificationDumpFile].";
    print IP_LIST_FILE '<?xml version="1.0" encoding="UTF-8"?>'."\r\n";
    print IP_LIST_FILE "<SMU>\r\n";
    print IP_LIST_FILE "<Result>\r\n";
    
    # Checking for password correct or not

    my @contents=<CONF_DUMP_PASS>;
    my @filtered=grep(/Password:/,@contents);
    close(CONF_DUMP_PASS);
    $cnt=@filtered;
    if($cnt>1)
    {
            print IP_LIST_FILE "<status>FAILED</status>\r\n";
            print IP_LIST_FILE "<Result>\r\n";
            print IP_LIST_FILE "</SMU>\r\n";
            $retVal=1;
            return $retVal;
            
    } else {
         print IP_LIST_FILE "<status>SUCCESS</status>\r\n";
    }
    
    #print IP_LIST_FILE "<status>SUCCESS</status>\r\n";
    print IP_LIST_FILE "</Result>\r\n";
	
	# Loop through the content of Verification dump file.
    while (my $line = <CONF_DUMP>)
    { 
        # Remove the new line character.
		chomp($line);
        #$line =~ s/\R//g;
	
        if ($line =~ /^\s*\d*\)\s*(\d{1,3}\.\d{1,3}\.\d{1,3}\.\d{1,3})/)
        {
	    my  %nodeList = ();
	    #If we found server IP , will check if we can connect to that server, then we will use it.
	    #If we successfully connect to that server then will also fetch the Node list on that server
	    if(0 == isServerConnected($1,\%nodeList)) {
	        #Creating server element
	        print IP_LIST_FILE "<Server>\n";
	        print IP_LIST_FILE "<ip-address>".$1."</ip-address>\n";
		foreach my $nodeId ( keys(%nodeList) ){
		    print IP_LIST_FILE "<Node>\n";
		    print IP_LIST_FILE "<id>".$nodeId."</id>\n";
		    print IP_LIST_FILE "<ip-address>".$nodeList{$nodeId}."</ip-address>\n";
		    print IP_LIST_FILE "</Node>\n";
		}		
	        print IP_LIST_FILE "</Server>\r\n";
	        $found = 1;
	    }
        }
    }
    print IP_LIST_FILE "</SMU>\r\n";
    if (0 == $found)
    {
        $retVal = 1;
    }
    
    close(CONF_DUMP);
    close(IP_LIST_FILE);
    
    return $retVal;
}


#
# @return :
#   0 if Success
#   1 if Error
sub isServerConnected
{    
    my ($hnasServerIpAddress, $nodeList) = (@_);
    
   

    # It is used to indicate the beginning of HNAS Configuration data in the raw configuration data file.
    my $confDataStart = 0;
    
    my $rawConfFile = "";
    
    # try new temporary filenames until we get one that didn't already exist
    do { $rawConfFile = tmpnam() }
        until my $fh = IO::File->new($rawConfFile, O_RDWR|O_CREAT|O_EXCL);

    # This variable is used to store the command to get the HNAS conf data.
    my $cmd = $hnasRunTimeLocation."/hnasGetConfData.sh Node $hnasSMUIpAddress $hnasSMUUserId $hnasSMUPassword $hnasServerIpAddress > ".$rawConfFile;
    logMsg("Info: Running command: [$hnasRunTimeLocation/hnasGetConfData.sh Node $hnasSMUIpAddress $hnasSMUUserId <Password> $hnasServerIpAddress > $rawConfFile].");

    # Run the command to get the HNAS Conf data.
    system($cmd);

    logMsg("Info: Reading raw configuration data for System resource.");
    
    open(my $FILE_HANDLE, $rawConfFile) or die logMsg("Error: Not able to open the file: [$rawConfFile].");

    # Loop through the content of "hnasSystem.dump" file.
    while (<$FILE_HANDLE>)
    {
        # Remove the new line character.
        chomp;

        # Look for ":$ ver" string in the file. This string is the start indicator of HNAS Configuration data.
        if ($_ =~ /:\$\s*cluster-show -v/)
        {
	    	if( 0 == isServerClustered($hnasServerIpAddress)) {
				$nodeList->{1} = $hnasServerIpAddress;
				return 0 ;
	    	}	    
            $confDataStart = 1;
            next;
        }

        # Process the current line only if reached at Configuration data part in the file.
        if (1 == $confDataStart)
        {
            if (/^\s+(\d+)\s+(Cluster)\s+([\w-]+)\s+(\w+)\s+(\w+)\s+(\d{1,3}\.\d{1,3}\.\d{1,3}\.\d{1,3})\s+(\w+)/)
            {
		# here $1 is nodeID and $6 is IP
		$nodeList->{$1} = $6;
            }
            else
            {
                # Current line is of no use. So ignore it.
            }
        }
    }
    close ($FILE_HANDLE);
    
    unlink($rawConfFile) or die "Couldn't unlink $rawConfFile : $!" ;    
    
    #if we receive the conf data then return 0 as a success
    if (1 == $confDataStart )
    {
        return 0;
    }
    
    #returning 1 as we have not received proper configuration data
    return 1;
}


#
# @return :
#   0 if Success
#   1 if Error
sub isServerClustered
{    
    my ($hnasServerIpAddress) = (@_);

    # It is used to indicate the beginning of HNAS Configuration data in the raw configuration data file.
    my $confDataStart = 0;
    my $clusterMode = "";
    my $rawConfFile = "";
    
    # try new temporary filenames until we get one that didn't already exist
    do { $rawConfFile = tmpnam() }
        until my $fh = IO::File->new($rawConfFile, O_RDWR|O_CREAT|O_EXCL);

    # This variable is used to store the command to get the HNAS conf data.
    my $cmd = $hnasRunTimeLocation."/hnasGetConfData.sh System $hnasSMUIpAddress $hnasSMUUserId $hnasSMUPassword $hnasServerIpAddress > ".$rawConfFile;
    logMsg("Info: Running command: [$hnasRunTimeLocation/hnasGetConfData.sh System $hnasSMUIpAddress $hnasSMUUserId <Password> $hnasServerIpAddress > $rawConfFile].");

    # Run the command to get the HNAS Conf data.
    system($cmd);

    logMsg("Info: Reading raw configuration data for System resource.");
    
    open(my $FILE_HANDLE, $rawConfFile) or die logMsg("Error: Not able to open the file: [$rawConfFile].");

    # Loop through the content of "hnasSystem.dump" file.
    while (<$FILE_HANDLE>)
    {
        # Remove the new line character.
        chomp;

        # Look for ":$ cluster-show" string in the file. This string is the start indicator of HNAS Configuration data.
        if ($_ =~ /:\$\s*cluster-show/)
        {
            
            $confDataStart = 1;
            next;
        }
        
        if ( 1 == $confDataStart) {            
            
           if (/^\s*Cluster Mode =\s*(.+)/)
            {
                $clusterMode = $1;
                $clusterMode =~s/[\r\n]+//g;
            }            
        }
    }
    close ($FILE_HANDLE);
    
    unlink($rawConfFile) or die "Couldn't unlink $rawConfFile : $!" ;    
    
    #if we receive the conf data then return 0 as a success
    if (1 == $confDataStart )
    {
	if($clusterMode =~/Not clustered/ ) {
            return 0;
        }    
    }    
    
    return 1;
}


# This function is used to read HNAS related information from the MARS app.properties file.
#
# @affected global variables :
#   $hnasRunTimeLocation
#
# @return :
#   0 if found correct information.
#   1 if not found correct information.
sub readAppPropertyFile
{
    # This variable is used to store the return value of function calls.
    my $retVal = 0;

    logMsg("Info: Reading file: [$appPropertiesFilePath].");

    open(my $PROP_FILE, $appPropertiesFilePath) or die logMsg("Error: Not able to open the file: [$appPropertiesFilePath].");

    # Loop through the content of app.properties file.
    while (<$PROP_FILE>)
    {
        # Remove the new line character.
        chomp;

        # Look for "HNAS.runtime.location" property.
        if ($_ =~ /^(\s*)HNAS.runtime.location=(\s*)(.+)(\s*)$/)
        {
            $hnasRunTimeLocation = $3;
	    $hnasRunTimeLocation =~s/[\r\n]+//g;
        }
        else
        {
            # Current line is of no use. So ignore it.
        }
    }

    #my $baseFolder = "";
    # Set MARS base folder.
    #$baseFolder = APP_HOME;    
    #$hnasRunTimeLocation = $baseFolder."/hnas";
    
    if ("" eq $hnasRunTimeLocation)
    {
        logMsg("Error: HNAS.runtime.location property not found in app.properties file.");
        $retVal = 1;

        goto EXIT;
    }

EXIT:

    close($PROP_FILE);

    return $retVal;
}

# This function is used to perform all cleanup tasks before exiting the script.
#
# @affected global variables :
#   $LOG_HANDLE
#
# @return :
#   Nothing
sub deInit
{
    # Close the log handle.
    close($LOG_HANDLE);
}

# This function is used to log a message in the log file. It logs the message in the following format:
# [YYYY-MM-DD HH:MM:ss,SSS]  [HNAS-<IP Address>] [Verifier|Conf|Perf] <Log message>
#
# @param :
#   $_[0] - Log message.
#
# @affected global variables :
#   None
#
# @return :
#   Nothing
sub logMsg
{
    # This variable store the current date and time in a specific format as: [YYYY-MM-DD HH:MM:ss,SSS]
    my $currentTime = "";

    # Read input parameter.
    (my $logMsg) = @_;

    # Get the current date and time.
    my ($seconds, $microseconds) = gettimeofday;
    
    $currentTime = strftime("%Y-%m-%d %H:%M:%S", localtime($seconds));
    $currentTime = "[".$currentTime.",".$microseconds."]";

    # Construct the final log message.
    my $finalMsg = $currentTime." [HNAS-".$hnasSMUIpAddress."] [Verifier] ".$logMsg."\n";

    # Dump the final log message in log file.
    print $LOG_HANDLE $finalMsg;
}

# ----------------------------------------------------------------------------------------------------------------------------------------------------
