#! /usr/perl5/bin/perl -w
#
# ident   "@(#)ShellScriptDumper.pm 1.2     04/11/01 SMI"
# 
# Copyright 2004 Sun Microsystems, Inc.  All rights reserved.
# Use is subject to license terms.
#

# 
# Module: ScSnapshot::ShellScriptDumper
#
# Implementation of the abstract class ScSnapshot::InternalViewDumper
# used for creating shell scripts for a given view.
#

package ScSnapshot::ShellScriptDumper;
use strict;

# Inheritance declaration
@ScSnapshot::ShellScriptDumper::ISA = 
  qw(ScSnapshot::InternalViewDumper);

#
# Constructor.
#
sub new {
  my $proto = shift;
  my $class = ref($proto) || $proto;
  my $self = {};
  bless ($self, $class);
  return $self;
}

#
# Generates code for a given view into a given file handle.
# Arguments:
#   1) The view for which the code should be generated.
#      Cannot be undefined.
#   2) The file handle onto which the code should be generated.
#      Cannot be undefined.
#
sub dump {
  my $self = shift;
  my $view = shift;
  my $output = shift;
  my %buffers;
  
  # Print shell script header
  print $output "#!/bin/sh\n\n";
  print $output "#\n";
  print $output "# Generated by scsnapshot on ".localtime()."\n";
  print $output "#\n";
  
  print $output "\nSCRGADM=/usr/cluster/bin/scrgadm\n";
  
  # Generate code for user access checking
  print $output "\n# User access right checking: `resource.modify`\n";
  print $output "#----------------------------------------------\n";
  print $output "\necho \"[INFO] : Check credential for script running\"\n";
  print $output "AUTHS=`/usr/bin/auths`\n";
  print $output "if [      \\( -z \"`echo \$AUTHS | grep 'solaris\\.cluster\\.resource\\.modify'`\" \\) \\\n";
  print $output "       -a \\( -z \"`echo \$AUTHS | grep 'solaris\\.cluster\\.resource\\.\\*'`\" \\) \\\n";
  print $output "       -a \\( -z \"`echo \$AUTHS | grep 'solaris\\.cluster\\.\\*'`\" \\) \\\n";
  print $output "       -a \\( -z \"`echo \$AUTHS | grep 'solaris\\.\\*'`\" \\) ]; then\n";
  print $output "  echo \"`basename \$0` : Not authorized to run this command.\"\n";
  print $output "  echo \"Minimal access rights are 'solaris.cluster.resources.modify'.\"\n";
  print $output "  exit 3\n";
  print $output "fi\n";
  
  # Generate flag retrieval
  print $output "\nfflag=\n";
  print $output "while getopts f name\n";
  print $output "do\n";
  print $output "  case \$name in\n";
  print $output "    f) fflag=1;;\n";
  print $output "    ?) echo \"Usage Error:\"\n";
  print $output "       echo \"`basename \$0` [-f]\"\n";
  print $output "       exit 1;;\n";
  print $output "  esac\n";
  print $output "done\n";
  
  # Generate cmd wrapper function
  my $runcmd="run_cmd";
  print $output "\n# Command wrapper";
  print $output "\n#----------------\n";
  print $output "\n$runcmd() {\n";
  print $output "  cmd=\$1\n";
  print $output "  echo \"Running: \$cmd\"\n";
  print $output "  eval \$cmd\n";
  print $output "  ec=\$?\n";
  print $output "  if [ \$ec -ne 0 ]; then\n";
  print $output "    echo \"... ERROR: Exit status is: \$ec\"\n";
  print $output "    [ -z \"\$fflag\" ] && exit 1\n";
  print $output "  fi\n";
  print $output "}\n";  

  # Generate software version level checking
  foreach my $info (@{$view}) {
    if ($info->{Type} eq "METADATA") {
      my $scversion = $info->{Parameters}->{REQUESTED_SOFTWARE_VERSION};
      my $osversion = $info->{Parameters}->{REQUESTED_OS_VERSION};
      my $arch = $info->{Parameters}->{REQUESTED_ARCH};
      print $output "\n# Software version and architecture consistency check\n";
      print $output   "#----------------------------------------------------\n";
      print $output "\necho \"[INFO] : Check software version and architecture consistency\"\n";
      print $output "if [ -z \"\$fflag\" ]; then\n";
      print $output "  LOCAL_OS_VERSION=`/usr/bin/uname -r 2>/dev/null`\n";
      print $output "  LOCAL_ARCH=`/usr/bin/uname -p 2>/dev/null`\n";
      print $output "  LOCAL_SC_VERSION=`/usr/cluster/bin/scinstall -p 2>/dev/null | /usr/bin/head -1`\n";
      print $output "  if [ \"\$LOCAL_SC_VERSION\" != \"" 
	. $scversion . "\" -o \"\$LOCAL_OS_VERSION\" != \"" 
	. $osversion . "\" -o \"\$LOCAL_ARCH\" != \"" . $arch . "\" ]; then\n";
      print $output "    echo \"This script has been generated on a " . $arch .
	" cluster running Solaris $osversion and SunCluster version '$scversion'\"\n";
      print $output "    echo \"while the local cluster is running on \$LOCAL_ARCH machine Solaris \$LOCAL_OS_VERSION and " .
	"SunCluster version \$LOCAL_SC_VERSION.\"\n";
      print $output "    echo \"This message is to warn you that this " .
	"inconsistency might lead to errors.\"\n";
      print $output "    echo \"You can force the execution by running " .
	"the script with the -f force flag:\"\n";
      print $output "    echo \"\t`basename \$0` -f\"\n";
      print $output "    exit 1\n";
      print $output "  fi\n";
      print $output "else\n";
      print $output "  echo \"You're running this script using the force mode\"\n";
      print $output "fi\n\n";
    }
  }
    
  # Resource deletion handling
  my $preamble = "\n# Old resource definitions removal\n";
  $preamble .=     "# --------------------------------\n";
  $preamble .= "\necho \"[INFO] : Remove old Resources:\"\n";
  my $any = 0;
  my $code = "";

  foreach my $action (@{$view}) {
    if ($action->{Type} eq "DELETE_RESOURCE") {
      $any=1;
      my $name = $action->{Parameters}->{RESOURCE_NAME};
      $code .= "\n# $name\n";
      $code .= "$runcmd \"\$SCRGADM -r -j $name\"\n";
      $code.="\n# END\n";
    }
  }
  if ($any) {
    $preamble .= $code;
    print $output $preamble;
  }
  
  $preamble  = "\n# Old resource group definitions\n";
  $preamble .= "#-------------------------------\n";
  $preamble .= "\necho \"[INFO] : Remove old Resource Group definitions:\"\n";

  $code = "";
  $any = 0;

  # Resource group deletion handling
  foreach my $action (@{$view}) {
    if ($action->{Type} eq "DELETE_RESOURCE_GROUP") {
      $any = 1;
      my $name = $action->{Parameters}->{RESOURCE_GROUP_NAME};
      $code .= "\n# $name\n";
      $code .= "$runcmd \"\$SCRGADM -r -g $name\"\n";
      $code.="\n# END\n";
    }
  }
   
  if ($any) {
    $preamble .= $code;
    print $output $preamble;
  }
  
  $preamble  = "\n# Removal of resource types from old configuration\n";
  $preamble .= "#------------------------------------------\n";
  $preamble .= "\necho \"[INFO] : Remove Resource Types from Old Configuration:\"\n";

  $code = "";
  $any = 0;

  # Writing code for old resource type removal
  foreach my $action (@{$view}) {
    if ($action->{Type} eq "DELETE_RESOURCE_TYPE") {
      $any =1 ;
      my $name = $action->{Parameters}->{RESOURCE_TYPE_NAME};
      $code .= "\n# $name\n";
      $code .= "$runcmd \"\$SCRGADM -r -t $name\"\n";
      $code.="\n# END\n";
    }
  }
   
  if ($any) {
    $preamble .= $code;
    print $output $preamble;
  }	

  # Generate some code to check that all wished Resource Type are installed
  # on the machine.
  my @rtlist;
  foreach my $action (@{$view}) {
    if ($action->{Type} eq "CREATE_RESOURCE_TYPE") {
      @rtlist = (@rtlist, 
		 $action->{Parameters}->{RESOURCE_TYPE_NAME} . 
		 ":" . $action->{Parameters}->{RESOURCE_TYPE_VERSION} . ":" . "/usr/cluster/lib/rgm/rtreg");
    }
  }

  if(@rtlist) {
    print $output "\n# Resource Type presence checking\n";
    print $output "#--------------------------------\n";
    print $output "\necho \"[INFO] : Resource Type presence checking:\"\n\n";
    print $output "# Each RT in the list below consists of 3 colon separated fields: \n";
    print $output "# name, version, and default rtr directory. \n";  
    print $output "# If the rtr file for a particular RT is not located in the default directory, \n";
    print $output "# you must edit the corresponding field \n"; 
    print $output "RTLIST=\"" . join(" \\\n        ",@rtlist) . "\"\n";
    print $output "MISSING=\n";
    print $output "RT_REGISTRATION_LIST=\n";
    print $output "for each in \$RTLIST; do\n";
    print $output "  RTNAME=`echo \$each | /usr/bin/cut -f 1 -d \":\"`\n";
    print $output "  RTVERSION=`echo \$each | /usr/bin/cut -f 2 -d \":\"`\n";
    print $output "  RT_DEFAULT_RTRDIR=`echo \$each | /usr/bin/cut -f 3 -d \":\"`\n\n";
    print $output "  if [ \$RTVERSION = \"1.0\" ]; then \n";
    print $output "    /usr/cluster/bin/scha_resourcetype_get -O START -T \$RTNAME >/dev/null 2>&1 \n";
    print $output "  else \n";
    print $output "    /usr/cluster/bin/scha_resourcetype_get -O START -T \$RTNAME:\$RTVERSION >/dev/null 2>&1 \n";
    print $output "  fi \n";
    print $output "  if [ \$? -eq 0 ]; then \n";
    print $output "    \# This RT is already registered, so continue and don't register it later \n";
    print $output "    continue \n";
    print $output "  else \n";
    print $output "    \# This RT is not yet registered, so add it to list of RTs to be registered \n";
    print $output "    RT_REGISTRATION_LIST=\"\$RT_REGISTRATION_LIST \$each\" \n";
    print $output "  fi \n";
    print $output "  if [ -z \"`\\grep RT_VERSION \${RT_DEFAULT_RTRDIR}/\${RTNAME}* 2>/dev/null | \\grep \$RTVERSION 2>/dev/null`\" ]; then \n";
    print $output "    MISSING=\"\$MISSING \$RTNAME:\$RTVERSION\"\n";
    print $output "  fi\n";
    print $output "done\n";
    print $output "if [ ! -z \"\$MISSING\" ]; then\n";
    print $output "  echo \"The Resource types listed below are not installed on this machine.\"\n";
    print $output "  echo \"Please install them before trying to run this script again:\"\n";
    print $output "  echo \"\$MISSING\"\n";
    print $output "  exit 1\n";
    print $output "fi\n\n";
  }

  $preamble  = "\n# Resource Type definitions\n";
  $preamble .=   "#--------------------------\n";
  $preamble .= "\necho \"[INFO] : Register needed Resource Types:\"\n";
  $code = "";

  # Write code relative to resource type creation
    my @installed_on_nodes = ();
    foreach my $action (@{$view}) {
      if ($action->{Type} eq "CREATE_RESOURCE_TYPE") {
        my $name = $action->{Parameters}->{RESOURCE_TYPE_NAME};
        if ((my $nodes = $action->{Parameters}->{INSTALLED_ON_NODES}) ne "*") {
          push @installed_on_nodes, ("$name:$nodes");
        }
      }
    }
    # Resource Types that are installed on only certain nodes and not ALL
    my $types_installed_on_nodes = join(" ", @installed_on_nodes);
    $code .= "installed_on_nodes=\"$types_installed_on_nodes\"\n";
    $code .= "command_string=\n";
    $code .= "for each in \$RT_REGISTRATION_LIST; do \n";
    $code .= "  RTNAME=`echo \$each | /usr/bin/cut -f 1 -d \":\"` \n";
    $code .= "  RT_DEFAULT_RTRDIR=`echo \$each | /usr/bin/cut -f 3 -d \":\"` \n";
    $code .= "  command_string=\"\$SCRGADM -a -t \$RTNAME -f \${RT_DEFAULT_RTRDIR}/\${RTNAME}\" \n";
    $code .= "  for type in \$installed_on_nodes; do \n";
    $code .= "    rt_name=`echo \$type | /usr/bin/cut -f 1 -d \":\"` \n";
    $code .= "    nodes=`echo \$type | /usr/bin/cut -f 2 -d \":\"` \n";
    $code .= "    if [ \$rt_name = \$RTNAME ]; then \n";
    $code .= "       command_string=\"\$command_string -h \$nodes\" \n";
    $code .= "    fi \n";
    $code .= "  done \n";
    $code .= "  $runcmd \"\$command_string\" \n";
    $code .= "done \n";
   
    $preamble .= $code;
    print $output $preamble;

  $preamble =  "\n# Resource group definitions\n";
  $preamble .=   "#---------------------------\n";
  $preamble .= "\necho \"[INFO] : Add new Resource Group definitions:\"\n";

  $code = "";
  $any = 0;

  # Write code for resource group creations
  foreach my $action (@{$view}) {
    
    if ($action->{Type} eq "CREATE_RESOURCE_GROUP") {
      $any=1;
      my $name = $action->{Parameters}->{RESOURCE_GROUP_NAME};
      my $properties = $action->{Parameters}->{PROPERTIES};
      $code .= "\n# $name\n";
      my $nl=$properties->{nodelist};
      $code .= "$runcmd \"\$SCRGADM -a -g $name -h \\\"$nl\\\"";
      foreach my $property (keys(%{$properties})) {    
	if(lc($property) ne "nodelist") {
	  my $string = $properties->{$property};
	  $string =~ s/\"/\\\\\\\"/g;
	  $code .= " -y $property=\\\"$string\\\"";
	}
      }
      $code.="\"\n\n# END\n";
    }
  }
  
  if ($any) {
    $preamble .= $code;
    print $output $preamble;
  }	

  $preamble  = "\n# Resource definitions\n";
  $preamble .= "#---------------------\n";
  $preamble .= "\necho \"[INFO] : Add new Resource definitions:\"\n";
  $code = "";
  $any = 0;

  # Write code for resource creations :
  foreach my $action (@{$view}) {
    # General-purpose resource
    if ($action->{Type} eq "CREATE_RESOURCE") {
      $any=1;
      my $name = $action->{Parameters}->{RESOURCE_NAME};
      my $group = $action->{Parameters}->{RESOURCE_GROUP_NAME};
      my $type = $action->{Parameters}->{RESOURCE_TYPE_NAME};
      $code .= "\n# $name\n";
      $code .= "$runcmd \"\$SCRGADM -a -j $name -g $group -t $type";
      my $stdproperties = 
	$action->{Parameters}->{STANDARD_PROPERTIES};
      foreach my $property (keys(%{$stdproperties})) {
	my $string = $stdproperties->{$property};
	$string =~ s/\"/\\\\\\\"/g;
	$code .= " -y $property=\\\"$string\\\"";
      }
      my $extproperties = 
	$action->{Parameters}->{EXTENSION_PROPERTIES};
      foreach my $property (keys(%{$extproperties})) {
	my $string = $extproperties->{$property};
	$string =~ s/\"/\\\\\\\"/g;
	$code .= " -x $property=\\\"$string\\\"";
      }
      $code.="\"\n\n# END\n";
    }
    # LogicalHostname resource
    elsif ($action->{Type} eq "CREATE_LOGICAL_HOSTNAME_RESOURCE") {
      $any=1;
      my $name = $action->{Parameters}->{RESOURCE_NAME};
      my $group = $action->{Parameters}->{RESOURCE_GROUP_NAME};
      my $hostnamelist = $action->{Parameters}->{HOSTNAME_LIST};
      my $netiflist = $action->{Parameters}->{NETIF_LIST};
      $code .= "\n# ";
      $code .= (defined($name) && length($name))?$name:"anonymous";
      $code .= "\n";
      $code .= "$runcmd \"\$SCRGADM -a -L -g $group";
      if (defined($name) && length($name)) {
	$code .= " -j $name";
      }
      if(defined($hostnamelist) && length($hostnamelist)) {
	$code .=" -l $hostnamelist";
      }
      if (defined($netiflist) && length($netiflist)) {
	$code .= " -n $netiflist";
      }
      my $stdproperties = $action->{Parameters}->{STANDARD_PROPERTIES};
      foreach my $property (keys(%{$stdproperties})) {
	my $str = $stdproperties->{$property};
	$str =~ s/\"/\\\\\\\"/g;
	$code .= " -y $property=\\\"$str\\\"";
      }
      $code.="\"\n\n# END\n";
    }
    # SharedAddress resource
    elsif ($action->{Type} eq "CREATE_SHARED_ADDRESS_RESOURCE") {
      $any=1;
      my $name = $action->{Parameters}->{RESOURCE_NAME};
      my $group = $action->{Parameters}->{RESOURCE_GROUP_NAME};
      my $hostnamelist = $action->{Parameters}->{HOSTNAME_LIST};
      my $netiflist = $action->{Parameters}->{NETIF_LIST};
      my $auxnodelist = $action->{Parameters}->{AUXNODE_LIST};
      $code .= "\n# ";
      $code .= (defined($name) && length($name))?$name:"anonymous";
      $code .= "\n";
      $code .= "$runcmd \"\$SCRGADM -a -S -g $group";
      if (defined($name) && length($name)) {
	$code .= " -j $name";
      }
      if(defined($hostnamelist) && length($hostnamelist)) {
	$code .=" -l $hostnamelist";
      }
      if (defined($netiflist) && length($netiflist)) {
	$code .= " -n $netiflist";
      }
      if (defined($auxnodelist) && length($auxnodelist)) {
	$code .= " -X $auxnodelist";
      }
      my $stdproperties = 
	$action->{Parameters}->{STANDARD_PROPERTIES};
      foreach my $property (keys(%{$stdproperties})) {
	my $str = $stdproperties->{$property};
	$str =~ s/\"/\\\\\\\"/g;
	$code .= " -y $property=\\\"$str\\\"";
      }
      $code.="\"\n\n# END\n";
    }
  }

  if ($any) {
    $preamble .= $code;
    print $output $preamble;
  }		
} 

# Return success for module load
1; 
