#!/usr/bin/perl
# IBM_PROLOG_BEGIN_TAG 
# This is an automatically generated prolog. 
#  
# bos720 src/bos/usr/lpp/bosinst/samples/AE/AE/ActivateVM.pl 1.1 
#  
# Licensed Materials - Property of IBM 
#  
# COPYRIGHT International Business Machines Corp. 2008,2009 
# All Rights Reserved 
#  
# US Government Users Restricted Rights - Use, duplication or 
# disclosure restricted by GSA ADP Schedule Contract with IBM Corp. 
#  
# IBM_PROLOG_END_TAG 

# @(#)23        1.1  src/bos/usr/lpp/bosinst/samples/AE/AE/ActivateVM.pl, bosinst, bos720 3/29/09 15:19:55

#----------------------include--------------------#
use XML::LibXML;
use File::Basename;
#----------------------include--------------------#
#
## This script - ActiveVM is executed by AE service
## and reads parameters from ovf-env.xml or *.ap.
## This script is called with three command line 
## arguments. The first is the AE path, the second
## is the resource name, and the third is the 
## config name. For example, a valid call to this
## would be:
##   perl ActivateVM /opt/IBM/AE SUSE_V10 ConfigNET
#
#-------------------main process------------------#

# get parameters
$AEPATH = $ARGV[0];
$RESOURCENAME = $ARGV[1];
$CONFNAME = $ARGV[2];
$LOCKFILE = "/var/lock/ActiveVM";

# AE's subdirectories
$APPATH="${AEPATH}/AP";
$ALPATH="${AEPATH}/AL";
$ARPATH="${AEPATH}/AR";
$AL="${AEPATH}/AL/master.al";

my $NS_URI = 'http://schemas.dmtf.org/ovf/environment/1';

if ((! -e '/var/lock') && (-e '/var/locks'))
{
  $LOCKFILE = "/var/locks/ActiveVM";
}
while ( -e $LOCKFILE )
{
    sleep 1;
}
system("touch $LOCKFILE"); #Create a lockfile to prevent another process read and write the same file.

my $APNAME;
# find the ovf-env.xml or the *.ap file
if( ($APNAME=findAPFile($APPATH )) ne "")# First find the AP file in the AP directory
{
    print("found $APNAME in directory $APPATH \n");
}

elsif(($APNAME=findAPFile("/media/floppy")) ne "")# If not found the AP file, try the floppy
{
    print("found $APNAME on sencondary slave /media/floppy \n");
}

elsif(($APNAME=findAPFile("/dev/hdd")) ne "")# If not found , try /dev/hdd
{
    print("found $APNAME on sencondary slave /dev/hdd \n");
}

elsif(($APNAME=findAPFile("/dev/hdc")) ne "")# If not found, try /dev/hdc
{
    print("found $APNAME on second master /dev/hdc \n");
}

elsif(($APNAME=findAPFile("/dev/hdb")) ne "")# If not found, try /dev/hdb
{
    print("found $APNAME on primary slave /dev/hdb \n");
}

elsif(($APNAME=findAPFile("/dev/hdb1")) ne "")# Check /dev/hdb1, if still no AP file found
{
    print("found $APNAME on partition /dev/hdb1 \n");
}
elsif(($APNAME=findAPFile("/dev/hda")) ne "")# Check /dev/hdb1, if still no AP file found
{
    print("found $APNAME on partition /dev/hdb1 \n");
}
elsif(($APNAME=findAPFile("/dev/cdrom")) ne "")# Check cdrom, if still no AP file found
{
    print("found $APNAME in /dev/cdrom \n");
}
elsif(($APNAME=findAPFileInScsiDevice()) ne "")# Check scsi devices for .ibm directory
{
    print("found $APNAME scsi disk \n");
}

my $AP="$APPATH" ."/" ."$APNAME";

unlink($LOCKFILE); # Remove the lockfile

if ( ! -f "$AP")
{
# No ap file found, exit.
    die "AP file is not found.  \n";
}


#  The following code processes the first AL file found
#$AL=`find $ALPATH -name "*.al" -print`;
#$AL=~s/\n$//;
if ( ! -e "$AL" )
{
    die "AL file ($AL) is not found.  \n";
}

# Create AR file - this is the activation result log
$vmInstance = &getVMInstance();
$AR=$ARPATH."/".$vmInstance.".ar";
if( ! -e "$AR")
{
    &createARFile();
}
%alParam = &getScriptFromAL();
$RESOURCE = $alParam{"resource"};
$CONFIG = $alParam{"config"};
$SCRIPT = $alParam{"script"};
if ( $RESOURCE eq "" or $CONFIG eq "" or $SCRIPT eq "" )
{
    die "cannot find resource \"$RESOURCE\" or config class \"$CONFIG\" or script \"$SCRIPT\" in $AL";
}
# Read parameters from ovf-env.xml and if not found ofv-xnv.xml try the *.ap file
if( $AP=~/ovf-env.xml/)
{
    $apParam = &getParamFromOVFAP();
}
else
{
    $apParam = &getParamFromAP();
}

$arStatus = &getStatusFromAR(); #get the status of *.ar file

if ( $apParam ne "" and $arStatus eq "NO" )
{
    $logFile = &executeScript($SCRIPT, $apParam);
    if($CONFNAME eq "ConfigDisk" && $RESOURCENAME eq "VirtualDisk")
    {
	&createARFile();
    }
    &updateARStatus($logFile);
}
else
{
    print "$RESOURCENAME $CONFNAME: Skip Activation\n";
}
###################################

#-------------------main process------------------#

#--------------subfunction definition-------------#

# If find ovf-env.xml,get vmInstance from the id attribute of the root Environment element
# else get vmInstance from the name attribute
sub getVMInstance
{
    my $vmInstance = "";
    if($AP=~/ovf-env.xml/)
    {
    my $envDoc = openXMLFile($AP);
    my $rootElement = $envDoc->getDocumentElement();
    $vmInstance = $rootElement->getAttributeNode("id")->getValue();
    }
    else
    {
	# my $tmpStr=`cat $AP|grep -P 'virtual-image\\s+name'`; # -P option not supported on AIX
	my $tmpStr=`cat $AP|grep 'virtual-image[ \t][ \t]*name'`;
	$tmpStr=~s|name=\"(.*?)\"||;
	$vmInstance=$1;
    }

    if(not defined($vmInstance))
    {
	exit -1;
    }
    return $vmInstance;
}

# get AS file's scriptType
sub getScriptType
{
    my ($scriptpath) = @_;

    my $rc = '';
    my @types = `grep '#!/' $scriptpath`;

    if ($#types >= 0)
    {
        if ($types[0] =~ m/\/perl/)
        {
            $rc = 'pl';
        }
        elsif (($types[0] =~ m/\/sh/) || ($types[0] =~ m/\/ksh/))
        {
            $rc = 'sh';
        }
    }
    return $rc;
}

# get AS file's prefixName
sub getPrefixName
{
    my($scriptpath)=@_;
    my ($filename, $dirs, $suffix) = fileparse($scriptpath);
    return $filename;
}

sub createARFile
{
    open(RAL, "<$AL") || die "cannot open $AL";
    open(WAR, ">$AR") || die "cannot open $AR";

    while ($line = <RAL>)
    {
	if ( $line =~ m/<service/ )
	{
	    my $tmp = "\t\t\t<execution status=\"NO\" \/>\n";
	    print WAR $tmp;
	}
	elsif ( $line =~ m/<runlevel/ or $line =~ m/<dependency/ or $line =~ m/<\/service>/)
	{
	    next;
	}
	else
	{
	    print WAR $line;
	}
    }

    close(RAL);
    close(WAR);
}

sub openXMLFile
{
    my($fpath)=@_;
    my $parser=new XML::LibXML();
    my $ldoc;
    chomp($fpath);

    $ldoc=eval
    {
	$parser->parse_file($fpath);
    };

    $ldoc || die "can not open the file  ".$fpath."\n";
    return $ldoc;
}

# get resource name, configuration name and script path from AL file
sub getScriptFromAL
{
    my $alDoc = openXMLFile($AL);
    my %alParam = ();

    my $resrcName = "";
    my $confName = "";
    my $scriptPath = "";

    my @resourceNodes = $alDoc->getElementsByTagName("software-resource");
    foreach my $resourceNode (@resourceNodes)
    {
	$resrcName = $resourceNode->getAttributeNode("name")->getValue();
	if ( $resrcName eq $RESOURCENAME )
	{
	    my @configNodes = $resourceNode->childNodes();
	    foreach my $configNode (@configNodes)
	    {
		if ($configNode->nodeName() ne "configuration")
		{
		    next;
		}

		$confName = $configNode->getAttributeNode("name")->getValue();
		if( $confName eq $CONFNAME )
		{
		    my @paramNodes = $configNode->childNodes();
		    foreach my $paramNode (@paramNodes)
		    {
		      my $name = $paramNode->nodeName();
		      if ($name eq 'script')
		      {
			$scriptPath = $paramNode->getAttributeNode("file")->getValue();
		      }
		    }
		    %alParam = ("resource", "$resrcName", "config", "$confName", "script", "$scriptPath");
		    last;
		}
	    }
	}
    }

    return %alParam;
}

# If exists ovf-env.xml file, get parameters using this method
sub getParamFromOVFAP
{
    my $apDoc = openXMLFile($AP);
    my $paramStr = "";

    my $resrcName = "";
    my $confName = "";
    my $scriptPath = "";

    my $rootElement = $apDoc->getDocumentElement();
    $rootElement->setNamespace($NS_URI, 'default_ns', 1);
    $rootElement->setNamespace($NS_URI, 'ovfenv_ns', 1);

    # xpath = //PropertySection/Property[@ovfenv:key='ConfigWAS.password'][@ovfenv:value]
    my $xpath_expression = "//default_ns:PropertySection/default_ns:Property[\@ovfenv_ns:key][\@ovfenv_ns:value]";

    my @nodes = $rootElement->findnodes($xpath_expression);
    # log_printf("\tchecking %d nodes\n", $#nodes + 1);

    foreach my $node (@nodes)
    {
      my $key_attr_node = $node->getAttributeNodeNS($NS_URI, 'key');
      if ($key_attr_node)
      {
	my $key = $key_attr_node->getValue();
	if($key =~ m/\.$CONFNAME\./)			
	{
	  $key = substr($key, rindex($key, ".") + 1);

	  my $value_attr_node = $node->getAttributeNodeNS($NS_URI, 'value');
	  my $value = '';
	  if ($value_attr_node)
	  {
	    $value = $value_attr_node->getValue();
	  }

	  print "Property Key is \" $key\". \n";
	  print "Property Value is \" $value\". \n";
	  $paramStr = "$paramStr -$key \"$value\"";
	}
      }
    }  
    return $paramStr;	
}
# If not found the ovf-env.xml, get parameters from *AP file using this method
sub getParamFromAP
{
    my $apDoc = openXMLFile($AP);
    my $paramStr = "";

    my $resrcName = "";
    my $confName = "";
    my $scriptPath = "";

    my @resourceNodes = $apDoc->getElementsByTagName("software-resource");
    foreach my $resourceNode (@resourceNodes)
    {
	$resrcName = $resourceNode->getAttributeNode("name")->getValue();
	if ( $resrcName eq $RESOURCENAME )
	{
	    my @configNodes = $resourceNode->childNodes();
	    foreach my $configNode (@configNodes)
	    {
		if ($configNode->nodeName() ne "configuration")
		{
		    next;
		}

		$confName = $configNode->getAttributeNode("name")->getValue();
		if( $confName eq $CONFNAME )
		{
		    my @paramNodes = $configNode->childNodes();
		    foreach my $paramNode (@paramNodes)
		    {
		      my $name = $paramNode->nodeName();
		      if ($name ne "parameter")
		      {
			next;
		      }
		      $paramName = $paramNode->getAttributeNode("name")->getValue();
		      $paramValue = $paramNode->getAttributeNode("value")->getValue();
		      $paramStr = "$paramStr -$paramName \"$paramValue\"";
		    }
		    last;
		}
	    }
	}
    }

    return $paramStr;	
}

# get scripts execution status. if scripts wasn't executed yet, status should be "NO" 
sub getStatusFromAR
{
    my $arDoc = openXMLFile($AR);

    my $status = "NO";
    my $nodeName = "";

    my @resourceNodes = $arDoc->getElementsByTagName("software-resource");
    foreach my $resourceNode (@resourceNodes)
    {
	$resrcName = $resourceNode->getAttributeNode("name")->getValue();
	if ( $resrcName eq $RESOURCENAME )
	{
	    my @configNodes = $resourceNode->childNodes();
	    foreach my $configNode (@configNodes)
	    {
		if ($configNode->nodeName() ne "configuration")
		{
		    next;
		}

		$confName = $configNode->getAttributeNode("name")->getValue();
		if( $confName eq $CONFNAME )
		{
		    my @paramNodes = $configNode->childNodes();
		    foreach my $paramNode (@paramNodes)
		    {
		      my $name = $paramNode->nodeName();
		      if ($name eq 'execution')
		      {
			$status = $paramNode->getAttributeNode("status")->getValue();
		      }
		    }
		    last;
		}
	    }
	}
    }

    return $status;
}

# execute script with parameters, stderr and stdout are being captured
# and redirected into an activation results log file in the AR directory
sub executeScript
{
    my($script, $param) = @_;

    my $prefixName = getPrefixName($script);
    my $scriptType = &getScriptType($script);
    my $logFile = "${ARPATH}/${prefixName}.log";
    my $fullScriptPath="";
    chomp($prefixName);
    chomp($scriptType);
    chomp($script);
# find whether $script stands for an absolute path or not
    if($script=~/^\s*(\/.*)$/)
    {
	$fullScriptPath=$1;
    }
    else
    {
	$fullScriptPath="$AEPATH/$script";
    }


#determine the kind of the executable script--shell or perl
    if ($scriptType eq "pl")
    {
    print "perl $fullScriptPath $param\n";
	system "perl $fullScriptPath $param 1>${ARPATH}/${prefixName}.log 2>&1";
    }
    elsif ($scriptType eq "sh")
    {
    print "sh $fullScriptPath $param\n";
	system "sh $fullScriptPath $param 1>${ARPATH}/${prefixName}.log 2>&1";
    }
    else
    {
    print "$scriptType is not supported. \n";
    }
    return $logFile;
}

# update execution status in AR
sub updateARStatus
{
    my ($logFile)=@_;
    my $flag = 0;

    open(RAR, "<$AR") || die "cannot open $AR";
    open(WTMP, ">${AR}.tmp") || die "cannot open ${AR}.tmp";

    while ($line = <RAR>)
    {
	if ( $line =~ m/$SCRIPT/ )
	{
	    my $tmp_status = "\t\t\t<execution status=\"YES\" \/>\n"; #Change the status of the AR file.
	    my $tmp_log = "\t\t\t<log file=\"$logFile\" \/>\n";
	    print WTMP $line;
	    print WTMP $tmp_status;
	    print WTMP $tmp_log;
	    $flag = 1;
	}
	elsif ( $line =~ m/<execution/  and  $flag == 1)
	{
	    $flag = 0;
	    next;
	}
	else
	{
	    print WTMP $line;
	}
    }
    close(RAR);
    close(WTMP);

    system("mv -f ${AR}.tmp $AR");
}
# The methods used to find the ovf-env.xml or *.ap file
sub findAPFile
{
    my $location=shift @_;
    my $localAP;
    if ( "$location" eq "/media/floppy" ) # The route parameter is a directory
    {
	system("mount  $location");
	$localAP=`find $location -name "ovf-env.xml" -print`;
	chomp($localAP);
	if(! -e "$localAP" )#if not found ovf-env.xml, try the *.ap file
	{
	    $localAP=`find $location -name "*.ap" -print`;
	}
	chomp($localAP);
	if( -e "$localAP" && "$location" ne "$APPATH" )
	{
	    print `cp $localAP $APPATH`;
	}
    }
    elsif ( -d "$location" ) # The route parameter is a directory
    {
	$localAP=`find $location -name "ovf-env.xml" -print`;
	chomp($localAP);
	if(! -e "$localAP" )#if not found ovf-env.xml, try the *.ap file
	{
	    $localAP=`find $location -name "*.ap" -print`;
	}
	if( -e "$localAP" && "$location" ne "$APPATH" )
	{
	    print `cp $localAP $APPATH`;
	}
    }
    elsif( -b "$location" ) # The route parameter is a block device
    {
	if( ! -d "/media/activation" )
	{
		    system("rm -rf /media/activation");
		    system("mkdir /media/activation");
	}
	else
	{
		system("rmdir /media/activation");
                if($? == 0)
                {
	        	system("mkdir /media/activation");
		}
	}
	system("mount  -t iso9660 -o ro,nosuid,nodev $location /media/activation");
	$localAP=`find /media/activation -name "ovf-env.xml" -print`;
	chomp($localAP);
	if(! -e "$localAP" )#if not found ovf-env.xml, try *.ap file
	{
	    $localAP=`find /media/activation -name "*.ap" -print`;
	}
	chomp($localAP);
	if(-e $localAP)
	{
	    print `cp -v $localAP $APPATH `;
	}
	system("umount /media/activation");
        if($? == 0)
        {
		system("rmdir /media/activation");
        }
    }
    $localAP=substr($localAP,rindex($localAP,"/")+1);
    chomp($localAP);
    return $localAP;
}


sub findAPFileInScsiDevice
{

    my $location;
    my $localAP="";
    my $found=0;
    
    $_= `ls -r /dev/sd*1`;
    
    if( -e "/tmp/activation" )
    {
        system("rm -rf /tmp/activation");
    }
    #my @deviceArray=();
    foreach $location (split){
		chomp($location);
                if( ! -e "/tmp/activation")
                {
			system("mkdir /tmp/activation");
                }
		system("mount  $location /tmp/activation");
		if($? == 0){
			if(-e "/tmp/activation/.ibm")
			{
				$localAP=`find /tmp/activation/.ibm -name "ovf-env.xml" -print`;
				chomp($localAP);
				if(! -e "$localAP" )#if not found ovf-env.xml, try *.ap file
				{
				    $localAP=`find /tmp/activation/.ibm -name "*.ap" -print`;
				    chomp($localAP);

				}
				
				if(-e $localAP)
				{
print( "$localAP\n");
				    print `cp -v $localAP $APPATH `;
				    $found=1;
				}
			}
			system("umount /tmp/activation");
			if($? == 0)
			{
				system("rmdir /tmp/activation");
			}
		}
		if($found == 1){
			last;
		}
    }

    $localAP=substr($localAP,rindex($localAP,"/")+1);
    chomp($localAP);
    return $localAP;
}

