#!/usr/bin/perl
# IBM_PROLOG_BEGIN_TAG 
# This is an automatically generated prolog. 
#  
#  
#  
# Licensed Materials - Property of IBM 
#  
# (C) COPYRIGHT International Business Machines Corp. 2005,2007 
# 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 
#####################################################################
#                                                                   #
# Command: adapter_config_Linux                                     #
#                                                                   #
#-------------------------------------------------------------------#
#                                                                   #
#      This CSM script will configure ethernet adapters on a        #
#      Linux cluster node during a node install.                    #
#                                                                   #
#      It uses an adapter stanza file containing the required       #
#      adapter information.                                         #
#                                                                   #
#      See the adapter_condig_Linux.README file for details on      #
#      how to use this customization scripts.                       #
#                                                                   #
# Exit codes:                                                       #
#     0 - All was successful.                                       #
#     1 - An error occured.                                         #
#                                                                   #
#                                                                   #
#####################################################################

use strict;

#-------------------------------------------------------------------#
#   MAIN Main main section of code
#-------------------------------------------------------------------#
$::progname = "adapter_config_Linux";

#
# The name of the adapter stanza file to read - which is located in the
#   <csm mount point>/csm/scripts/data directory
#
$::STANZA_FILE_NAME = "Linux_adapter_stanza_file";

#
# The templet of adapter config file name
#
$::RH_CONFIG_FILE      = "/etc/sysconfig/network-scripts/ifcfg-xxxxxx";
$::SLES_CONFIG_FILE    = "/etc/sysconfig/network/ifcfg-xxxxxx";
$::MODULE_CONF_FILE_24 = "/etc/modules.conf";
$::MODULE_CONF_FILE_26 = "/etc/modprobe.conf";
$::RHEL_ROUTE_FILE     = "/etc/sysconfig/network-scripts/route-xxxxxx";
$::SLES_ROUTE_FILE     = "/etc/sysconfig/network/ifroute-xxxxxx";

#
# The default stanza name
#
$::DefaultStanzaName = "default";

$::GLOBAL_EXIT = 0;
$::NOK         = 1;
$::OK          = 0;

#
# Hostname/IP of this node as known by the management server
#  this is the name used in the adapter stanza file
#
$::Hostname;
$::HostIP;

$::InstallOSName;                 #  ex. Linux or AIX
$::InstallDistributionName;       #  ex. RedHatEL-AS or SLES etc.
$::InstallDistributionVersion;    #  Linux distribution version

#
# Any attributes contained in an adapter stanza other than the following
#   will be added directly to the adapter "ifcfg" file.
#
@::CSM_ATTRIBUTE_SET = (
						"machine_type",   "network_type",
						"interface_name", "device_driver",
						"MAC_address",    "gateway",
						"destination",    "dest_netmask"
					   );
@::ADAPTERS;

#
#CSM log directory/file
#
$::CSMLOG      = "/var/log/csm";
$::INSTALL_LOG = "/var/log/csm/install.log";

#
# Append logging information to the install.log file on the node that was
#     started by osprereboot
#
&append_logging($::INSTALL_LOG);
$::logging++;

#
# check the platform
#
my $cmd_res = `uname -s -r`;
chomp $cmd_res;
($::PLTFRM, $::KERNEL_RELEASE) = ($cmd_res =~ /^(\w+)\s([\d\.]+)/);
if ($::PLTFRM ne "Linux")
{
	print $::LOG_FILE_HANDLE
	  "$::progname:  This script may only be run on a Linux system.\n";
	$::GLOBAL_EXIT = 1;
	exit;
}

#
# Get some attribute values for this node from the configinfo file
#

if (&get_config_info() != $::OK)
{
	print $::LOG_FILE_HANDLE
	  "$::progname:  Could not get node attribute values from the /opt/csm/install/configinfo file.\n";
	$::GLOBAL_EXIT = 1;
	exit;
}

#
# Parse the stanza information
#
if (&parse_stanza_file() != $::OK)
{
	print $::LOG_FILE_HANDLE
	  "$::progname:  Irrecognizable stanza file format.\n";
	$::GLOBAL_EXIT = 1;
	exit;
}

#
#Create adapter config file
#
if (&config_eth_adapters() != $::OK)
{
	print $::LOG_FILE_HANDLE
	  "$::progname:  Failed to config ethernet adapter.\n";
	$::GLOBAL_EXIT = 1;
	exit;
}

#
#Bring up second adapter
#
if (&bring_up_adapters() != $::OK)
{
	$::GLOBAL_EXIT = 1;
	exit;
}

#
# finish up and exit
#
END
{

	if ($::logging)
	{
		&stop_logging();
	}

	#Determine exit code
	if ($::GLOBAL_EXIT > $?)
	{
		$? = $::GLOBAL_EXIT;
	}
}

exit;    # end of Main

#--------------- subroutines ----------------------------------

#-------------------------------------------------------------------------#
#   get_config_info - Get required information out of the configinfo      #
#                     file. This file contains attributes and values for  #
#                     the node we are running on.                         #
#                                                                         #
#   Return Codes: 0 - All was successful.                                 #
#                 1 - An error occured.                                   #
#--------------------------------------#----------------------------------#
sub get_config_info
{

	my ($attr, $value);
	my $cfg_file   = "/opt/csm/install/configinfo";    #created by osprereboot
	my $match_node = 0;

	chomp $cfg_file;

	# get attribute values from the config_info file
	if (-f $cfg_file)
	{
		unless (open(CFGINFO, "<$cfg_file"))
		{

			# Couldn't open $cfg_file
			print $::LOG_FILE_HANDLE
			  "$::progname  Cannot open file $cfg_file for reading.\n";
			return $::NOK;
		}

		while (<CFGINFO>)
		{
			($attr, $value) = split('=');

			if ($attr eq "Hostname")
			{

				# Hostname as known on the MS
				$match_node = 1;
				$::Hostname = $value;
				chomp $::Hostname;
			}
			elsif ($attr eq "InstallOSName")
			{
				$::InstallOSName = $value;
				chomp $::InstallOSName;
			}
			elsif ($attr eq "InstallDistributionName")
			{
				$::InstallDistributionName = $value;
				chomp $::InstallDistributionName;
			}
			elsif ($attr eq "InstallDistributionVersion")
			{
				$::InstallDistributionVersion = $value;
				chomp $::InstallDistributionVersion;
			}
			elsif ($attr eq "HostnameIP")
			{
				$match_node = 1;
				$::HostIP   = $value;
				chomp $::HostIP;
			}
		}

		# see if we got something
		if (!$match_node)
		{

			# Could not find attribute values in file.
			print $::LOG_FILE_HANDLE
			  "$::progname: Could not find attribute values in $cfg_file.\n";
			return $::NOK;
		}

		close(CFGINFO);
	}
	else
	{

		# $cfg_file does not exist.
		print $::LOG_FILE_HANDLE "$::progname:  $cfg_file does not exist.\n";
		return $::NOK;
	}
	return $::OK;
}

#--------------- subroutines ----------------------------------

#-------------------------------------------------------------------------#
#   parse_stanza_file - parse a stanza file                               #
#                                                                         #
#   Return Codes: 0 - All was successful.                                 #
#                 1 - An error occured.                                   #
#--------------------------------------#----------------------------------#
sub parse_stanza_file
{

	#
	#  open the stanza file
	#
	my $csm_mount_point = $ENV{'CSMMOUNTPOINT'};    # set by osprereboot
	my $scripts_data_dir = $csm_mount_point . "/csm/scripts/data";
	my $stanzafile       = "$scripts_data_dir/$::STANZA_FILE_NAME";

	if (!-e $stanzafile)
	{

		#  error - file does not exist
		print $::LOG_FILE_HANDLE
		  "$::progname: The stanza file $::STANZA_FILE_NAME does not exist.\n";
		return $::NOK;
	}
	else
	{    # open the file
		unless (open(STANZAFILE, "<$stanzafile"))
		{

			# Couldn't open stanzaafile
			print $::LOG_FILE_HANDLE
			  "$::progname: Cannot open file $::STANZA_FILE_NAME for reading.\n";
			returen $::NOK;
		}
	}

	#
	# parse the contents of the stanza file, collect original adapter attribute
	#
	my $look_for_colon = 1;    # start with first line that has a colon
	                           #  reset when looking for next colon
	my $current_stanza_name;
	my $stanza_num = -1;
	my @original_attrs;
	my %default_attr;

	#  check each line
	while (my $line = <STANZAFILE>)
	{
		my $node_name;

		# see parsing routine ServerUtils->make_adapter_files()
		#   must be modified for this script
		next
		  if ($line =~ /^\s*$/ || $line =~ /^\s*#/)
		  ;    #skip blank and comment linesa
		chomp $line;
		if ($line =~ /^\s*(\S*):\s*$/)
		{
			$current_stanza_name = $1;
			if (   $::Hostname =~ /^\Q$current_stanza_name\E\./
				|| $::Hostname eq $current_stanza_name
				|| $current_stanza_name =~ /^\Q$::Hostname\E\./
				|| $::HostIP eq $current_stanza_name)
			{
				$look_for_colon = 0;
				$stanza_num++;
				$original_attrs[$stanza_num] = ();
			}
			elsif ($::DefaultStanzaName eq $current_stanza_name)
			{
				$look_for_colon = 0;
			}
			else
			{
				$look_for_colon = 1;
			}
			next;
		}
		if (!$look_for_colon && $line =~ /^\s*(\S*)\s*=\s*(\S*)\s*/)
		{
			if ($::DefaultStanzaName eq $current_stanza_name)
			{
				$default_attr{$1} = $2;
			}
			else
			{
				$original_attrs[$stanza_num]{$1} = $2;
			}
		}
	}
	close(STANZAFILE);

	#
	#filtrate and organize original attributes
	#
	my $attr_index = 0;
	foreach my $original_attr_item (@original_attrs)
	{
		%$original_attr_item = (%default_attr, %$original_attr_item);
		next
		  if (   $$original_attr_item{"machine_type"} ne "secondary"
			  || $$original_attr_item{"network_type"} ne "eth");
		my @original_key_set = keys(%$original_attr_item);
		$::ADAPTERS[$attr_index]{"CSM_ATTRIBUTES"}    = ();
		$::ADAPTERS[$attr_index]{"COMMON_ATTRIBUTES"} = ();
		foreach my $original_key (@original_key_set)
		{
			if (grep(/\Q$original_key\E/, @::CSM_ATTRIBUTE_SET))
			{
				$::ADAPTERS[$attr_index]{"CSM_ATTRIBUTES"}{$original_key} =
				  $$original_attr_item{$original_key};
			}
			else
			{
				$::ADAPTERS[$attr_index]{"COMMON_ATTRIBUTES"}{$original_key} =
				  $$original_attr_item{$original_key};
			}
		}
		$attr_index++;
	}
	return $::OK;
}

#--------------- subroutines ----------------------------------

#-------------------------------------------------------------------------#
#   config_eth_adapters - configure an ethernet adapter using the         #
#                     information contain in an adapter stanza.           #
#                                                                         #
#   Return Codes: 0 - All was successful.                                 #
#                 1 - An error occured.                                   #
#--------------------------------------#----------------------------------#
sub config_eth_adapters
{

	my $config_file_name;

	for my $adapter (@::ADAPTERS)
	{

		#
		# create an ifcfg file
		#
		if ($::InstallDistributionName =~ /RedHatEL/)
		{
			$config_file_name = $::RH_CONFIG_FILE;
			$config_file_name =~
			  s/xxxxxx/$$adapter{"CSM_ATTRIBUTES"}{"interface_name"}/;
		}
		elsif ($::InstallDistributionName =~ /SLES/)
		{
			$config_file_name = $::SLES_CONFIG_FILE;
			if ($::InstallDistributionVersion ne "9")
			{
				$config_file_name =~
				  s/xxxxxx/$$adapter{"CSM_ATTRIBUTES"}{"interface_name"}/;
			}
			else
			{
				$config_file_name =~
				  s/xxxxxx/eth-id-$$adapter{"CSM_ATTRIBUTES"}{"MAC_address"}/;
			}
		}
		else
		{
			print $::LOG_FILE_HANDLE
			  "$::progname: Linux Distribution $::InstallDistributionName is not support by CSM currently.\n";
			return $::NOK;
		}

		unless (open(CONFIG_FILE, '>' . $config_file_name))
		{
			print $::LOG_FILE_HANDLE
			  "$::progname: Can't create adapter config file.\n";
			return $::NOK;
		}

		my $adapter_common_attributes = $$adapter{"COMMON_ATTRIBUTES"};
		my @common_key_set            = keys(%$adapter_common_attributes);
		foreach my $common_key (@common_key_set)
		{
			print CONFIG_FILE $common_key . '='
			  . $$adapter_common_attributes{$common_key} . "\n";
		}
		close CONFIG_FILE;

		#
		# optionally - update the modules.conf file
		#
		if (defined($$adapter{"CSM_ATTRIBUTES"}{"device_driver"}))
		{
			my $modules_conf_file;
			if ($::KERNEL_RELEASE > 2.4)
			{
				$modules_conf_file = $::MODULE_CONF_FILE_26;
			}
			else
			{
				$modules_conf_file = $::MODULE_CONF_FILE_24;
			}

			unless (open(MODULECONFFILE, ">>$modules_conf_file"))
			{

				# Couldn't open modules config file
				print $::LOG_FILE_HANDLE
				  "$::progname: Cannot open file $modules_conf_file for appending.\n";
				returen $::NOK;
			}
			print MODULECONFFILE
			  qq(alias $$adapter{"CSM_ATTRIBUTES"}{ "interface_name"} $$adapter{"CSM_ATTRIBUTES"}{ "device_driver"}\n);
			close MODULECONFFILE;
		}

		#
		# optionally - update gateway information
		#
		if (
			defined($$adapter{"CSM_ATTRIBUTES"}{"gateway"})
			&& defined(
					   $$adapter{"CSM_ATTRIBUTES"}{"destination"}
						 && defined($$adapter{"CSM_ATTRIBUTES"}{"dest_netmask"})
					  )
		   )
		{
			if ($::InstallDistributionName =~ /RedHatEL/)
			{
				return $::NOK if &config_rhel_routes($adapter) != $::OK;
			}
			else
			{
				return $::NOK if &config_sles_routes($adapter) != $::OK;
			}
		}
	}
	return $::OK;
}

#--------------- subroutines ----------------------------------

#-------------------------------------------------------------------------#
#   config_rhel_routes - config the routes                                #
#                        in RedHat Enterprise Linux.                      #
#                                                                         #
#   Retrun Codes: 0 - All was successful.                                 #
#                 1 - An error occured.                                   #
#----------------------------------------#--------------------------------#

sub config_rhel_routes
{
	my $adapter         = shift;
	my $route_file_name = $::RHEL_ROUTE_FILE;
	$route_file_name =~ s/xxxxxx/$$adapter{"CSM_ATTRIBUTES"}{"interface_name"}/;

	unless (open(ROUTE_FILE, '>' . $route_file_name))
	{
		print $::LOG_FILE_HANDLE
		  "$::progname: Can't open SLES routes config file for appending.\n";
		return $::NOK;
	}

	print ROUTE_FILE qq(GATEWAY0 $$adapter{"CSM_ATTRIBUTES"}{ "gateway"}\n);
	print ROUTE_FILE
	  qq(NETMASK0 $$adapter{"CSM_ATTRIBUTES"}{ "dest_netmask"}\n);
	print ROUTE_FILE qq(ADDRESS0 $$adapter{"CSM_ATTRIBUTES"}{ "destination"}\n);

	close ROUTE_FILE;
}

#--------------- subroutines ----------------------------------

#-------------------------------------------------------------------------#
#   config_sles_routes - config the routes                                #
#                        in Suse Linux Enterprise Server.                 #
#                                                                         #
#   Retrun Codes: 0 - All was successful.                                 #
#                 1 - An error occured.                                   #
#----------------------------------------#--------------------------------#

sub config_sles_routes
{
	my $adapter         = shift;
	my $route_file_name = $::SLES_ROUTE_FILE;
	if ($::InstallDistributionVersion ne "9")
	{
		$route_file_name =~
		  s/xxxxxx/$$adapter{"CSM_ATTRIBUTES"}{"interface_name"}/;
	}
	else
	{
		$route_file_name =~
		  s/xxxxxx/eth-id-$$adapter{"CSM_ATTRIBUTES"}{"MAC_address"}/;
	}

	unless (open(ROUTE_FILE, '>>' . $route_file_name))
	{
		print $::LOG_FILE_HANDLE
		  "$::progname: Can't open SLES routes config file for appending.\n";
		return $::NOK;
	}

	#SLES9 will restore the installing routes configuration into routes.Yast2save,
	#Some marks should be added for 005CSM_recoverSecondaryAdaptersConfig._SLES9Nodes.
	#    print ROUTE_FILE qq( \#\#\# CSM secondary adapters configuration begin (Please do not remove this line)\n);
	if ($::InstallDistributionVersion ne "9")
	{
		print ROUTE_FILE
		  qq($$adapter{"CSM_ATTRIBUTES"}{ "destination"} $$adapter{"CSM_ATTRIBUTES"}{ "gateway"} $$adapter{"CSM_ATTRIBUTES"}{ "dest_netmask"} $$adapter{"CSM_ATTRIBUTES"}{"interface_name"});
	}
	else
	{
		print ROUTE_FILE
		  qq($$adapter{"CSM_ATTRIBUTES"}{ "destination"} $$adapter{"CSM_ATTRIBUTES"}{ "gateway"} $$adapter{"CSM_ATTRIBUTES"}{ "dest_netmask"} eth-id-$$adapter{"CSM_ATTRIBUTES"}{ "MAC_address"}\n);
	}

	#    print ROUTE_FILE qq( \#\#\# CSM secondary adapters configuration begin (Please do not remove this line)\n);
}

#--------------- subroutines ----------------------------------

#-------------------------------------------------------------------------#
#   bring_up_adapters - Bring up adapters.                                #
#                                                                         #
#   Retrun Codes: 0 - All was successful.                                 #
#                 1 - An error occured.                                   #
#----------------------------------------#--------------------------------#
sub bring_up_adapters
{
	for my $adapter (@::ADAPTERS)
	{
		if (`/sbin/ifup $$adapter{"CSM_ATTRIBUTES"}{"interface_name"}` != 0)
		{
			print $::LOG_FILE_HANDLE
			  qq($::progname:  Failed to bring up adapter $$adapter{"CSM_ATTRIBUTES"}{"interface_name"}.\n);
			return $::NOK;
		}
	}
}

#--------------- subroutines ----------------------------------

#-------------------------------------------------------------------------#
#                                                                         #
#    append_logging                                                       #
#                                                                         #
#         Append logging messages to a logfile. Return the log file       #
#           handle so it can be used to close the file when done logging. #
#                                                                         #
#----------------------------------------#--------------------------------#
sub append_logging
{
	my ($logfile, $stat) = @_;
	my ($cmd,     $rc);

	# create the log directory if it's not already there
	if (!-d $::CSMLOG)
	{
		$cmd = "$::MKDIR -m 644 -p $::CSMLOG";
		$rc  = system("$cmd");
		if ($rc >> 8)
		{
			print
			  "$::progname: 2653-158 Could not create \"$::CSMLOG\" directory.\n";
			return ($::NOK);
		}
	}

	#
	#  get log file ready
	#
	if (!-e $logfile)
	{

		#  create the log file if not already there
		# open the log file
		unless (open(LOGFILE, ">$logfile"))
		{

			# Cannot open file
			print
			  "$::progname: 2653-141 Cannot open file \"$logfile\" for writing.\n";
			return $::NOK;
		}
	}
	else
	{

		# it's there so just append
		unless (open(LOGFILE, ">>$logfile"))
		{
			print "$::progname: 2653-036 Could not update  \"$logfile\".\n";
			return $::NOK;
		}
	}

	$::LOG_FILE_HANDLE = \*LOGFILE;

	if ((defined $stat) && ($stat == 1))
	{
		return ($::LOG_FILE_HANDLE);
	}

	# Print the date to the top of the logfile
	my $sdate = `/bin/date`;
	chomp $sdate;
	print "Output log is being written to \"$logfile\".\n";

	print $::LOG_FILE_HANDLE
        "---------------------------------------------------------------------\n";
	print $::LOG_FILE_HANDLE "$::progname: Logging started $sdate.\n";
	print $::LOG_FILE_HANDLE
        "---------------------------------------------------------------------\n";

	return ($::LOG_FILE_HANDLE);
}

#--------------- subroutines ----------------------------------

#-------------------------------------------------------------------------#
#                                                                         #
#    stop_logging                                                         #
#                                                                         #
#                  Turn off message logging.  (Expects to have a file     #
#                   handle passed in. )                                   #
#                                                                         #
#--------------------------------------#----------------------------------#

sub stop_logging
{

	# Print the date at the bottom of the logfile
	my $sdate = `/bin/date`;
	chomp $sdate;
	print $::LOG_FILE_HANDLE
        "---------------------------------------------------------------------\n";
	print $::LOG_FILE_HANDLE "$::progname: Logging stopped $sdate.\n";
	print $::LOG_FILE_HANDLE
        "---------------------------------------------------------------------\n";

	close($::LOG_FILE_HANDLE);
	$::LOG_FILE_HANDLE = undef;

	return $::OK;
}

