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

# This file contains the code to verify the connection to an IBM XIV Storage.
#
# @param : MARS Site name - MARS Site name
# @param : Storage IP - IBM XIV Storage IP Address
# @param : User Name - IBM XIV Storage User Name
# @param : Key - IBM XIV Storage Key
#
# @return : In case of success, returns 0. In case of failure, returns 1.
#
# Sample command: perl ibmxivStorageVerifier.pl <MARS Site name> <Storage IP> <User Name> <Key>

#!/usr/bin/perl -w

# It is used for strict compilation.
use strict;

# 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);

# It is used to indicate the path where common module is placed.
use lib "/usr/local/megha/lib/common/perl";

# It is required for logging information.
use commonLogModule;

# It is required for getting Key from probe specific property file.
use commonPerlUtil;

# It is required for getting runtime location of the xivGetConfData.sh file.
use commonPropFileModule;

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

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

# This variable is used to store the complete name of file where output from IBM XIV Storage will be dumped.
my $dumpFile = "";

# This variable is used to store the complete name of file which contain the output of this script.
my $verificationOutputFile = "";

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

# This variable is used to store the IBM XIV Storage Key.
my $xivKey = "";

# This variable is used to store the IBM XIV Storage IP Address.
my $xivIpAddress = "";

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

# This variable is used to store the MARS Site name.
my $marsSiteName = "";

# This variable is used to store error message which will be displayed in UI.
my $message = "";

# This variable stores the run time location of the xivGetConfData.sh file.
my $xivRuntimeLocation = "";

# This variable stores the probe type.
my $probeType = "IbmXiv";

# This variable stores the complete path of IBM XIV data collection utility.
my $cliUtility = "/opt/XIVGUI/CliConsole";

# It stores the commonPerlUtil instance.
my $perlUtilObj = "";

# This variable stores commonLogModule instance.
my $logObj = "";

# ----------------------------------------------------------------------------------------------------------------------------------------------------
# Error codes corresponding to ibmxivGetConfData.sh. Always keep it in sync with error codes in ibmxivGetConfData.sh.
# ----------------------------------------------------------------------------------------------------------------------------------------------------
my $ERROR_SUCCESS            = 0;
my $ERROR_INVALID_CRED       = 1;
my $ERROR_CONNECTION_FAILED  = 2;
my $ERROR_EXCEPTION_FOUND    = 3;

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

# Initialize the environment.
$status = init();
if (0 != $status)
{
    $logObj->error("Call to init() failed.");
    goto EXIT;
}

# Verify IBM XIV Storage credentials.
$status = verifyCredentials();
if (0 != $status)
{
    $logObj->error("Call to verifyCredentials() failed.");
    goto EXIT;
}

EXIT:

# If verification is successful then dump the "Success" as a message in a temporary file so that caller of this script can read the information and
# if verification succeed and then continue with Add probe flow. If verification fail then dump the respective error message in the temporary file.
$status = dumpVerificationInfo();
if (0 != $status)
{
    $logObj->error("Call to dumpVerificationInfo() failed.");
}

exit $status;

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

# This function is used to initialize the environment to run the Perl script correctly.
#
# @affected global variables :
#   $baseFolder
#   $marsSiteName
#   $xivIpAddress
#   $xivUserId
#   $xivKey
#   $verificationOutputFile
#   $dumpFile
#
# @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 complete path of probe specific folder in db/probe folder.
    my $probeFolder = "";

    # This variable stores encrypted Key.
    my $encryptedKey = "";

    # This variable stores Log folder path.
    my $logFolder = $baseFolder."/logs";

    # If log folder does not exist then create it.
    if (! (-e $logFolder))
    {
        mkpath($logFolder);
    }

    # Get commonLogModule instance.
    $logObj = commonLogModule->getInstance($logFolder, $probeType, $xivIpAddress);

    # If number of command line arguments are not correct then quit.
    if (4 != ($#ARGV + 1))
    {
        $logObj->error("Number of arguments to ibmxivStorageVerifier.pl are not correct. Input argument count = ".($#ARGV + 1));
        $retVal = 1;

        goto EXIT;
    }

    # Get the MARS Site name from command line argument.
    $marsSiteName = $ARGV[0];
    $logObj->info("Input Site name = [$marsSiteName]");

    # Get the XIV Storage IP Address from command line argument.
    $xivIpAddress = $ARGV[1];
    $logObj->info("Input IP Address = [$xivIpAddress]");

    # Update the final log message information with populated XIV probe id.
    $logObj->setProbeId($xivIpAddress);

    # Get the XIV User name from command line argument.
    $xivUserId = $ARGV[2];
    $logObj->info("Input User = [$xivUserId]");

    # Get the XIV Key from command line argument.
    $encryptedKey = $ARGV[3];

    # Set MARS probe folder path.
    $probeFolder = $baseFolder."/db/probe/".$marsSiteName."/IbmXiv_".$xivIpAddress;
    $logObj->info("Creating folder: [$probeFolder].");

    # Create the XIV Probe folder in the db/probe folder.
    unless (defined eval {mkpath($probeFolder)})
    {
        $logObj->error("Not able to create folder: [$probeFolder].");
        $retVal = 1;

        goto EXIT;
    }

    # Set the file name where output of this script will be stored.
    $verificationOutputFile = $probeFolder."/ibmxivVerificationOutput.txt";
    $logObj->info("Verification output file: [$verificationOutputFile].");

    # Set the file name where the output of "Control" command will be dumped.
    $dumpFile = $probeFolder."/ibmxivConnectionStatus.dump";
    $logObj->info("Dump file name: [$dumpFile].");

    # Check the existence of IBM XIV data collection utility.
    unless (-e $cliUtility)
    {
        $logObj->error("IBM XIV data collection utility is not present: [$cliUtility].");
        $message = "Error:IBM XIV data collection utility [CliConsole] is not present at: /opt/XIVGUI";

        $retVal = 1;

        goto EXIT;
    }

    # Get commonPerlUtil instance.
    $perlUtilObj = commonPerlUtil->getInstance($baseFolder, $probeType, $xivIpAddress, $logObj);

    # Decrypt the Key.
    $status = $perlUtilObj->getDataValue($encryptedKey, $xivKey);
    if (0 != $status)
    {
        $logObj->error("Call to getDataValue() failed.");
        $retVal = 1;

        goto EXIT;
    }

    # Get commonPropFileModule instance.
    my $propFileObj = commonPropFileModule->getInstance($baseFolder, $probeType, $xivIpAddress, $logObj);

    # Get the runtime location.
    $status = $propFileObj->getProbeProperty("runtime.location", $xivRuntimeLocation);
    if (0 != $status)
    {
        $logObj->error("Call to getProbeProperty() failed.");
        $retVal = 1;

        goto EXIT;
    }

    $logObj->info("Runtime loction = [$xivRuntimeLocation]");

EXIT:

    return $retVal;
}

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

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

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

    # Construct the command to get the IBM XIV Conf data.
    $cmd = $xivRuntimeLocation."/ibmxivGetConfData.sh Version $xivIpAddress $xivUserId $xivKey > $dumpFile 2>&1";
    my $cmdWithoutKey = $xivRuntimeLocation."/ibmxivGetConfData.sh Version $xivIpAddress $xivUserId <Key> > $dumpFile 2>&1";

    $logObj->info("Trying to get Configuration information from IBM XIV CLI. Running command: [$cmdWithoutKey].");

    $exitCode = $perlUtilObj->executeSystemCmd($cmd);
    if ($ERROR_SUCCESS == $exitCode)
    {
        # If successfully executed the command to get storage version then return with Success.
        $logObj->info("Succeded in getting XIV Configuration Data.");
        $message = "Success";

        $exitStatus = $exitCode;
        goto EXIT;
    }
    # If connection to Storage failed then exit with error.
    elsif ($ERROR_CONNECTION_FAILED == $exitCode)
    {
        $logObj->error("Connection to Storage failed.");
        $message = "Error:Unable to connect to storage system";

        $exitStatus = $exitCode;
        goto EXIT;
    }
    # If connection to Storage failed with "Invalid credential" error then exit with error.
    elsif ($ERROR_INVALID_CRED == $exitCode)
    {
        $logObj->error("Invalid storage system credentials.");
        $message = "Error:Invalid storage system credentials";

        $exitStatus = $exitCode;
        goto EXIT;
    }
    # If connection to Storage failed with some Exception then exit with error.
    elsif ($ERROR_EXCEPTION_FOUND == $exitCode)
    {
        $logObj->error("Exception found while invoking IBM XIV data collection utility.");
        $message = "Error:Unable to invoke IBM XIV data collection utility";

        $exitStatus = $exitCode;
        goto EXIT;
    }

EXIT:

    close(CONF_DUMP);

    return $exitStatus;
}

# This function is used to create a file at: db/probe/IbmXiv_<IP>/ibmxivVerificationOutput.txt
# It puts IBM XIV Storage connection status in this file. Caller of this script is responsible for deleting this file.
#
# @affected global variables :
#   None
#
# @return :
#   0 if Success
#   1 if Error
sub dumpVerificationInfo
{
    # This variable is used to store the return value of the function.
    my $retVal = 0;

    # Use the open() function to create the file.
    unless(open FILE, '>'.$verificationOutputFile)
    {
        # Die with error message if we can't open it.
        $logObj->error("Unable to open: [$verificationOutputFile].");

        $retVal = 1;
        goto EXIT;
    }

    if ("" eq $message)
    {
        $retVal = 1;
        goto EXIT;
    }
    else
    {
        # Write error message in this file.
        print FILE $message;
    }

    # Close the file.
    close(FILE);

EXIT:

    return $retVal;
}
# ----------------------------------------------------------------------------------------------------------------------------------------------------
