#!/usr/local/bin/perl
# 
# $Header: crs11g_upgrade.pl 08-dec-2007.05:46:57 ajdsouza Exp $
#
# crs11g_upgrade.pl
# 
# Copyright (c) 2007, 2008, Oracle. All rights reserved.  
#
#    NAME
#      crs11g_upgrade.pl - <one-line expansion of the name>
#         Usage: crs11g_upgrade.pl [-tgt_home] <home> 
#
#    DESCRIPTION
#      upgrade the targets discover metadata file targets.xml
#       from lower versions to crs 11g
#
#    NOTES
#      <other useful comments, qualifications, etc.>
#
#    MODIFIED   (MM/DD/YY)
#    dchakumk    03/10/08 - XbranchMerge dchakumk_6752_xbmsrc from
#                           st_emdbsa_11.1
#    ajdsouza    01/31/07 - Creation
#

use strict;
use warnings;
use Data::Dumper;
use has::Common;
require "semd_common.pl";

# name : has_handle_error
# desc : called to handle error messages
#
# arg  :
# error message
#
sub has_handle_error(@)
{ 
   my ( $message ) = @_; 

   chomp $message; 

   $message =~ s/^\s+|\s+$//
    if $message;

   return 1 unless $message and $message =~ /^(ERROR|WARN)\s*:/i;

   # log the message to the log file
   EMD_PERL_WARN("HAS:crs11g_upgrade.pl:$message") and return 1
    if $message =~/^WARN/i;
   EMD_PERL_ERROR("HAS:crs11g_upgrade.pl:$message") and return 1
    if $message =~/^ERROR/i;

   die "HAS:crs11g_upgrade.pl:$message" if $message =~/^ERROR/i;

   return 1;

}


# name : has_target_fn
# desc : for each element passed it filters our the enity element of interest
#
# arg  :
#  ref to xml element to be filtered
#  ref to xml ref to be returned back
#  metric_name being processed
# 
sub has_target_fn(\%\%$)
{
  my ( $elref, $rsref, $metric_name ) = @_;

  # we upgrade only one host and cluster in targets.xml
  # the first one top down
  return 1 if $rsref->{cluster} and $rsref->{host};

  # check if this represents a element of interest - Target
  return 1 
   unless $elref->{element} and $elref->{element} =~ /^target$/i;

  # interested in only cluster and host targets
  return 1 unless $elref->{attrs};

  # we check for both type= and TYPE=
  my $type;
  map { $type = $_ if $_ =~/^type$/ic } keys %{$elref->{attrs}};

  return 1 unless 
   $elref->{attrs}{$type} and $elref->{attrs}{$type} =~ /cluster|host/i;

  #keep the list of hosts and clusters
  push $rsref->{lc $elref->{attrs}{$type}}=$elref;

  return 1;
}


#----------------------------------------------------------------
# Code Begin
#----------------------------------------------------------------
die "Usage:crs11g_upgrade.pl -tgt_home <target_home>\n"
  unless  ( @ARGV >=2 and $ARGV[0] =~ /-tgt_home/ and $ARGV[1] )
      or ( @ARGV >=1 and $ARGV[0] and $ARGV[0] !~ /-tgt_home/);

my $tgtHome;

$tgtHome = $ARGV[1] 
 if @ARGV >=2 and $ARGV[0] =~ /-tgt_home/ and $ARGV[1];
$tgtHome = $ARGV[0] 
if not $tgtHome
 and @ARGV >=1 and $ARGV[0] and $ARGV[0] !~ /-tgt_home/

die "Usage:crs11g_upgrade.pl -tgt_home <target_home>\n" 
 unless $tgtHome;

#build the path to the discovery file
my $tgtFile = File::Spec->catfile($tgtHome,'sysman');
$tgtPath = File::Spec->catfile($tgtPath,,'emd');
$tgtPath = File::Spec->catfile($tgtPath,'targets.xml');

# open the target discover file and read its contents
stat($tgtPath);

die "crs11g_upgrade.pl:ERROR:File $tgtPath is not accessible\n"
 unless -e $tgtPath and -r $tgtPath;


open(TGTXML, "<$tgtPath") 
 or die "crs11g_upgrade.pl:ERROR:Failed to open file $tgtPath";

my @lns = <TGTXML>;

close(TGTXML);

my $xcontent = '';

for my $ln ( @lns )
{
  $xcontent = "$xcontent\n$ln"
}

# remove that newline or space at the begining
$xcontent =~ s/^[\s\n]+|\s+$//g;

die "crs11g_upgrade.pl:ERROR:Failed to get content from $tgtPath\n"
  unless $xcontent;

# parse the xml string to a processable perl structure
my  %xmlvar = has::Common::parse_xml($xcontent);

# traverse the perl structure to pick cluster and host of interest
# picks one host and one cluster ( we assume one target.xml has one host
# and one cluster)
my %reslist;
has::Common::traverse_xml(%xmlvar,&handle_error,&has_target_fn,\%reslist);

EM_PERL_DEBUG("crs11g_upgrade.pl:ERROR:Failed to get both cluster and host\n")
 and exit 0
  unless $reslist{cluster} 
  and $reslist{host}
   and ref($reslist{cluster}) =~ /HASH/
    and ref($reslist{host}) =~ /HASH/;

# get the cluster name , remember practical assumption only 
# one cluster per box
my $crsHome = has::Common::hasGetClusterName();
my $discClsName = has::Common::hasGetCRSHome();

my $isEmcrsp = has::Common::hasCheckForEmcrsp($discClsName);
my $has_type;
my $scanName;
my $scanPort;
my $eonsPort;

if  ( $isEmcrsp )
{
  $has_type = has::Common::hasGetOcrType($discClsName);
  
  if ( $has_type =~ /^cluster$/ )
  {
    $scanName = has::Common::hasGetScanName($discClsName);
    $scanPort = has::Common::hasGetScanPort($discClsName);
    $eonsPort = has::Common::hasGetEONSPort($discClsName);
  }
}

my $type, $name;

my $clsref = $reslist{cluster};
my $hostref = $reslist{host};

# if there is no cluster home then there is nothign to do 
# for the cluster target
if ( $crsHome )
{

 # we check for both type= and TYPE=
 map { $type = $_ if $_ =~/^type$/ic;  $name = $_ if $_ =~/^name$/ic } 
  keys %{$clsref->{attrs}};

 $type = 'TYPE' unless $type;
 $name = 'NAME' unless $name;

 # use the discovered cluster name if there is no cluster name
 $clsref->{attrs}{$name} = $discClsName unless $clsref->{attrs}{$name};

 # if the cluster xml in the discovery file has properties get the property
 # tag
 my $propertytag;

 map { $propertytag = $_ if $_ =~ /property/i } 
  keys %{$clsref->{child_elements}}
   if $clsref->{child_elements};

 # build the list of existign cluster properties in the discovery file
 my %already_existing_properties;
 
 if ( $propertytag )
 {
   for my $elref ( @{$clsref->{child_elements}{$propertytag}} )
   {
    next unless $elref and ref($elref} =~ /HASH/;

    next unless $elref->{attrs};

    # save the existing cluster properties 
    $already_existing_properties{cluster}{uc $elref->{attrs}{NAME}} = 1
     if $elref->{attrs}{NAME};
   }
 }

 #if OracleHome is not a property add it
 my $propref = has::Common:make_element('Property','',
   (NAME=>'OracleHome',VALUE=>$crsHome));

 has::Common::append_element($clsref,$propref) unless
  $already_existing_properties{cluster} and
  $already_existing_properties{cluster}{uc 'OracleHome'};

}

# cluster target is modified now modify the host target
EMD_PERL_WARN("crs11g_upgrade.pl:ERROR:Failed to find name for cluster in $tgtPath cluster target not modified")
  unless $clsref->{attrs} and $clsref->{attrs}{$name};

my $clsName = $clsref->{attrs}{$name};


# check if the host target has the assoc property
my $assoctag;

 map { $assoctag = $_ if $_ =~ /AssocTargetInstance/i } 
  keys %{$hostref->{child_elements}}
   if $hostref->{child_elements};

 # build the list of existing host properties in the discovery file
 if ( $assoctag )
 {
   for my $elref ( @{$hostref->{child_elements}{$assoctag}} )
   {
    next unless $elref and ref($elref} =~ /HASH/;

    next unless $elref->{attrs};

    # save the existing cluster properties 
    $already_existing_properties{host}{uc $elref->{attrs}{ASSOCIATION_NAME}} = 1
     if $elref->{attrs}{ASSOCIATION_NAME};
   }
 }


# find if there is a composite membership of cluster for the host
my $comptag;

map { $comptag = $_ if $_ =~ /CompositeMembership/i } 
  keys %{$hostref->{child_elements}}
   if $hostref->{child_elements};

# build the list of existing host CompositeMemberships in the discovery file
if ( $comptag )
{
   for my $elref ( @{$hostref->{child_elements}{$comptag}} )
   {
     next unless $elref and ref($elref} =~ /HASH/;

     # find if there is a memberof of cluster for the host
     my $membertag;

     map { $membertag = $_ if $_ =~ /MemberOf/i }
      keys %{$elref->{child_elements}}
       if $elref->{child_elements};

     next unless $membertag;

     # from ther memberof find if its a cluster member
     for my $memref ( @{$elref->{child_elements}{$membertag}} )
     {
       next unless $memref and ref($memref} =~ /HASH/;

       # save the existing cluster properties 
       $already_existing_properties{host_memberof}{uc $elref->{attrs}{ASSOCIATION}} = 1
         if $elref->{attrs}{ASSOCIATION};
    }

   }

}


# check and modify the host target xml
for ( (1) )
{

 # create the assoc element if both no assoc target and no memberof exists
 last 
   if $already_existing_properties{host_memberof}{uc 'cluster_member'}
     or $already_existing_properties{host}{uc 'AssocTargetInstance'};

  my $assocref = has::Common:make_element('AssocTargetInstance','',
   (ASSOCIATION_NAME =>'cluster_instance',
    ASSOC_TARGET_TYPE => 'cluster',
    ASSOC_TARGET_NAME => $clsName));

  has::Common:append_element($hostref,$assocref);

}

my $dumpstr = has::Common:dump_xml();

open (OUTFILE, ">$tgtPath") 
 or die "crs11g_upgrade.pl:ERROR:Failed to open $tgtPath for write\n";

print OUTFILE $dumpStr;

close (OUTFILE);

exit 0;

