#!/usr/bin/perl
# IBM_PROLOG_BEGIN_TAG 
# This is an automatically generated prolog. 
#  
#  
#  
# Licensed Materials - Property of IBM 
#  
# (C) COPYRIGHT International Business Machines Corp. 2000,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 
# @(#)80   1.28.13.1   src/csm/install/installms.perl, setup, csm_rfish, rfishs001b 3/19/07 01:34:17
#--------------------------------------------------------------------------------

=head1    installms.perl

	Installs CSM on Linux managment servers

	Notes:  

	AIX code removed

=cut

#--------------------------------------------------------------------------------

=head3  File header

        Notes:

          file header gathers pkgdefs values.

=cut

#--------------------------------------------------------------------------------

use strict;
BEGIN { $::csmpm = $ENV{'CSM_PM'} ? $ENV{'CSM_PM'} : '/opt/csm/pm'; }
use lib $::csmpm;
use File::Path;

# Provides mkpath();
use FindBin qw($Bin);
use lib "$Bin";

use Getopt::Long;
use NodeUtils;
use CSMDefs;
require ServerUtils;
require NetworkUtils;

$::MSGCAT     = 'csmInstall.cat';
$::MSGMAPPATH = $ENV{'CSM_MSGMAPS'} ? $ENV{'CSM_MSGMAPS'} : '/opt/csm/msgmaps';
$::MSGSET     = 'csminstall';

#--------------------------------------------------------------------------------

=head3	initialize

	initializes globals from package defs

=cut

#--------------------------------------------------------------------------------

sub initialize
{

	# 0 = tftp server rpm not installed.
	$::default_tftp_server_installed = 0;

	#  OS Definitions
	my %OSDefs = ServerUtils->get_OSDefs();

	$::PREREQS_ATTR{'OSName'} = NodeUtils->get_OSName;
	my $OSName = $::PREREQS_ATTR{'OSName'};

	# NLS hack
	if ($ENV{LANG} =~ /^(C|POSIX|en_US)/) { $::ENGLISH = 1; }

	# installms is not supported on AIX management servers
	if ($OSName eq "AIX")
	{
		MessageUtils->message('E', 'EMsgAIXandInstallms');
		exit 1;
	}

	# processor
	$::PREREQS_ATTR{'PkgArchitecture'} = NodeUtils->get_PkgArchitecture;
	if ($::PREREQS_ATTR{'PkgArchitecture'} =~ /i.86/)
	{
		$::PREREQS_ATTR{'PkgArchitecture'} = "i386";
	}

	# CSM version
	$::PREREQS_ATTR{'CsmCoreVersion'} = NodeUtils->get_CSMVersion("csm\.core");
	if (length($::PREREQS_ATTR{'CsmCoreVersion'}) == 0)
	{
		MessageUtils->message('E2', 'EMsgNO_CORE');
	}

	@::VALID_ATTRS = ("RemoteShell", "SetupRemoteShell");
	$::PREREQS_ATTR{'DistributionName'}    = NodeUtils->get_DistributionName;
	$::PREREQS_ATTR{'DistributionVersion'} = NodeUtils->get_DistributionVersion;

	# Pacakge Defines

	# management server
	%::Svrpkgdefs =
	  ServerUtils->get_pkgdefs(
							   $::PREREQS_ATTR{'OSName'},
							   $::PREREQS_ATTR{'DistributionName'},
							   $::PREREQS_ATTR{'DistributionVersion'},
							   $::PREREQS_ATTR{'PkgArchitecture'},
							   "MgmtServer",
							   $::PREREQS_ATTR{'CsmCoreVersion'}
							  );

	# install server
	%::Isvrpkgdefs =
	  ServerUtils->get_pkgdefs(
							   $::PREREQS_ATTR{'OSName'},
							   $::PREREQS_ATTR{'DistributionName'},
							   $::PREREQS_ATTR{'DistributionVersion'},
							   $::PREREQS_ATTR{'PkgArchitecture'},
							   "InstallServer",
							   $::PREREQS_ATTR{'CsmCoreVersion'}
							  );

	# managed node
	%::Nodepkgdefs =
	  ServerUtils->get_pkgdefs(
							   $::PREREQS_ATTR{'OSName'},
							   $::PREREQS_ATTR{'DistributionName'},
							   $::PREREQS_ATTR{'DistributionVersion'},
							   $::PREREQS_ATTR{'PkgArchitecture'},
							   "MgdNode",
							   $::PREREQS_ATTR{'CsmCoreVersion'}
							  );

	# override $::RPMCMD if going to suppress signature warning.
	ArchiveUtils->suppressRpmSigWarning();

	return;

}

#-------------------------------------------------------------------------------

=head3    set_variables


=cut

#-------------------------------------------------------------------------------

sub set_variables
{

	my $OSName = $::PREREQS_ATTR{'OSName'};

	my $temp_distro =
	    $::PREREQS_ATTR{'DistributionName'} . " "
	  . $::PREREQS_ATTR{'DistributionVersion'};
	if (!grep(/^$::PREREQS_ATTR{'CsmCoreVersion'}$/, @::VALID_CSM_DISTROS))
	{
		MessageUtils->message(
						   'E5',
						   'EMsgUNSUPPORTED_CSM_DISTRO',
						   "CSM" . $::PREREQS_ATTR{'CsmCoreVersion'},
						   join(', ', @::VALID_CSM_DISTROS)
						  );
	}
	else
	{
		MessageUtils->message('V', 'IMsgDETECTED_CSM_DISTRO',
						   "CSM" . $::PREREQS_ATTR{'CsmCoreVersion'});
	}

	$::PREREQS_ATTR{'OSTypeVer'} =
	    $::PREREQS_ATTR{'OSName'}
	  . $::PREREQS_ATTR{'DistributionName'}
	  . $::PREREQS_ATTR{'DistributionVersion'};

	# installation path
	$::INSTALLDIR_CSM   = $::CSMINSTDIR . "/csm";
	$::INSTALLDIR_CSMVR =
	  $::INSTALLDIR_CSM . "/" . $::PREREQS_ATTR{CsmCoreVersion};
	$::INSTALLDIR_CSMVRBIN = $::INSTALLDIR_CSMVR . "/bin";
	$::INSTALLDIR_OS       =
	    $::CSMINSTDIR . "/"
	  . $::PREREQS_ATTR{"OSName"} . "/"
	  . $::PREREQS_ATTR{'DistributionName'};
	$::INSTALLDIR_OSVER =
	  $::INSTALLDIR_OS . "/" . $::PREREQS_ATTR{DistributionVersion};
	$::INSTALLDIR_OSVER_ARCH =
	  $::INSTALLDIR_OSVER . "/" . $::PREREQS_ATTR{'PkgArchitecture'};
	$::INSTALLDIR_OSCSM  = $::INSTALLDIR_OS . "/csm";
	$::INSTALLDIR_CSMVER =
	  $::INSTALLDIR_OSCSM . "/" . $::PREREQS_ATTR{CsmCoreVersion};
	my $INSTALLDIR_OS_NAME = $::PREREQS_ATTR{DistributionName};

	if ($::PREREQS_ATTR{DistributionName} =~ /RedHat/)
	{
		$INSTALLDIR_OS_NAME = "RedHat";
	}
	if ($::PREREQS_ATTR{DistributionName} =~ /RedHat/)
	{
		my $my_dirname;
		if ($::PREREQS_ATTR{"InstallServiceLevel"} eq "GA")
		{
			$my_dirname =
			    $::PREREQS_ATTR{DistributionName}
			  . $::PREREQS_ATTR{'DistributionVersion'} . "-"
			  . $::PREREQS_ATTR{'PkgArchitecture'};
		}
		else
		{
			$my_dirname =
			    $::PREREQS_ATTR{DistributionName}
			  . $::PREREQS_ATTR{'DistributionVersion'} . "-"
			  . $::PREREQS_ATTR{"InstallServiceLevel"};
		}
		$::INSTALLDIR_OS_NAME_RPMS =
		  $::INSTALLDIR_OSVER_ARCH . "/" . $my_dirname . "/RedHat/RPMS";
	}
	else
	{
		$::INSTALLDIR_OS_NAME_RPMS =
		    $::INSTALLDIR_OSVER_ARCH . "/"
		  . $::PREREQS_ATTR{"InstallServiceLevel"} . "/RPMS";
	}
	$::INSTALLDIR_CSMBIN = $::INSTALLDIR_CSMVER . "/bin";
	$::INSTALLDIR_CSMPKG = $::INSTALLDIR_CSMVER . "/packages";

}

#--------------------------------------------------------------------------------

=head3    usage

        Notes:

=cut

#--------------------------------------------------------------------------------

sub usage
{

	MessageUtils->message('I', 'IMsginstallmsUsage', join(' ', @::VALID_ATTRS));
	exit 1;
}

#--------------------------------------------------------------------------------

=head3    getArgs

        Notes:

=cut

#--------------------------------------------------------------------------------

sub getArgs
{
	my @command_line = ();
	@command_line   = @ARGV;
	$::command_line = $0 . " " . join(" ", @command_line);

	my $my_dir = NodeUtils->runcmd("pwd");
	chomp($my_dir);
	if ($my_dir =~ /$::MNTCDROM/)
	{
		MessageUtils->message('E1', 'IMsgCHANGE_TO_NON_CDROM_DRIVE', $my_dir);
		exit 1;
	}

	my $pkgpath = "";

# Checks case in GetOptions
    	$Getopt::Long::ignorecase = 0;

    	# Allows opts to be grouped (e.g. -avx)
	Getopt::Long::Configure("bundling");
	Getopt::Long::Configure("pass_through");
	if (
        	!GetOptions(
                        'h'  => \$::opt_h,
                        'c'  => \$::opt_c,
                        'p=s' => \$::opt_p,
                        'v' => \$::opt_v,
                        'V'  => \$::opt_V,
                        'f' => \$::opt_f,
                        'x' => \$::opt_x,
                        'noprompt' => \$::NO_MOUNT_CD,
                	   )
       	   )
    	   {
        	$::GLOBAL_EXIT = 1;
	        &usage;
	        exit $::GLOBAL_EXIT;
    	   }

	if ($::opt_h)             { &usage }
	$::DONT_COPY_RPMS = $::opt_x;
	$::FORCE_INSTALL  = $::opt_f;
	$::COPY_OPT_FLAG  = $::opt_c;

	if ($::opt_v || $::opt_V)
	{
		if ($::opt_v) { $::VERBOSE = $::opt_v; }
		if ($::opt_V) { $::VERBOSE = $::opt_V; }

	}

	if ($::opt_x && $::opt_p) { &usage; }
	if (!($::opt_p ^ $::opt_x)) { &usage; }

	# Packages path
	if ($::opt_p) { $pkgpath = $::opt_p; }

	# Handle attr=value arguments
	if (scalar(@ARGV) > 0)
	{
		foreach my $a (@ARGV)
		{

			# allow a null attr values
			my ($attr, $value) = $a =~ /^\s*(\S+?)\s*=\s*(\S*.*)$/;

			if (!length($value)) { $value = "''"; }

			if (!defined($attr))
			{
				MessageUtils->message('W', 'EMsgBAD_ATTR_VAL_FORM');
				&usage;
			}
			my $found = 0;
			foreach my $va (@::VALID_ATTRS)
			{
				if ($attr =~ /^$va$/i)
				{

					# Put quotes around the value to protect spaces
					# or weird chars
					$::ATTRS{$va} = $value;    # Quotes mess up some values
					$found = 1;
				}
			}
			if (!$found)
			{
				MessageUtils->message('E', 'EMsgBAD_ATTR', $attr);
				MessageUtils->message('I', 'IMsgVALID_ATTRS',
								   join('\n\t', @::VALID_ATTRS));
				exit 1;
			}
		}
	}

	# Validate attributes and flags
	my $distro =
	    $::PREREQS_ATTR{'DistributionName'} . " "
	  . $::PREREQS_ATTR{'DistributionVersion'};

    my $location = 'MgmtServer';
	if (!grep(/^$location$/, @{$::Svrpkgdefs{'where_supported'}}))
	{
		my $officially_supported = 1;	
		my %supported_distro = NodeUtils->getSupportedDistro($officially_supported);
		MessageUtils->message(      'E', 'EMsgUNSUPPORTED_DISTRO',
						   $distro, $supported_distro{$location});
		MessageUtils->message('E1', 'EMsgREINSTALLCSMCORE');
	}
	else { MessageUtils->message('V', 'IMsgDETECTED_DISTRO', $distro); }
	$::DISTRO = $distro;

	$::PREREQS_ATTR{"InstallServiceLevel"} = NodeUtils->get_ServiceLevel;
	if (   $::PREREQS_ATTR{"InstallServiceLevel"}
		&& $::PREREQS_ATTR{"InstallServiceLevel"} ne "")
	{
		MessageUtils->message('V', 'IMsgDETECTED_SERVICE_LEVEL',
						   $::PREREQS_ATTR{"InstallServiceLevel"});
	}
	else
	{
		MessageUtils->message('E1', 'EMsgUNSUPPORTED_SERVICE_LEVEL');
	}

	# installms should be forbidden when HA MS is running
	my $hamode =
	  NodeUtils->runcmd(
		"CT_MANAGEMENT_SCOPE=1 /usr/sbin/rsct/bin/lsrsrc-api -i -s IBM.DmsCtrl::::HAMode",
		-1
	  );
	if ($::RUNCMD_RC == 0 && $hamode != 0)
	{
		MessageUtils->message('E1', 'EMsgHAMSRunning');
	}

	@::PKGPATH = split(":", $pkgpath);

	# Gather the subdirectories
	foreach my $p (split(":", $pkgpath))
	{
		push @::PKGPATH, (ServerUtils->returnSubdirectory($p));
	}

}

#--------------------------------------------------------------------------------

=head3   set_cluster_attrs

        Notes: move to ServerUtls? Big routine...

	Set global cluster attributes by using ATTR=Value provided by the user.
	This set attributes in the dmsctrl resource class.  The attributes are stored
	in the %::ATTRS hash.

=cut

#--------------------------------------------------------------------------------

sub set_cluster_attrs
{
	my $rc = 0;
	my ($attr, $value, $dmsctrlkey);

	return 0 if (!(keys %::ATTRS));

	my $cmd = "/opt/csm/bin/csmconfig";

	foreach $attr (keys %::ATTRS)
	{
		$value = $::ATTRS{$attr};
		$cmd .= " $attr=$value";
	}

	my $output = NodeUtils->runcmd($cmd, 0);
	$rc = $::RUNCMD_RC;

	return $rc;
}

#--------------------------------------------------------------------------------

=head3    checkPreviousInstallation

        Notes:
 		 empty subroutine

=cut

#--------------------------------------------------------------------------------

sub checkPreviousInstallation { }

#--------------------------------------------------------------------------------

#--------------------------------------------------------------------------------

=head3    migrateConserverCfg

# Check the version of the conserver configuration file and create a new version, if necessary
#

=cut

#--------------------------------------------------------------------------------

sub migrateConserverCfg
{
	my $CFGFILE    = "/etc/opt/conserver/conserver.cf";
	my @cfg        = ();
	my $old_format = 0;
    my $new_format = 0;
    my $regen_cfg  = 0;
    my $rc         = 0;
	my $cmd;

	if (-e $CFGFILE)
	{
		unless (open CONFIGCURRENT, "<$CFGFILE")
		{
			#MessageUtils->message('E', 'EMsgCANT_OPEN', $CFGFILE);
			return;
		}

		# seek to the beginning of the config file and read it.
		#
		seek CONFIGCURRENT, 0, 0;

		@cfg = <CONFIGCURRENT>;

		close CONFIGCURRENT;

        # The conserver pre-8.1 configuration file format requires the '%%'
        # line as a separator between configuration sections. This line will
        # not be in a 8.1 configuration file.
        #
        # Up til now, what was in the 8.1 configuration file was '#### CSM'.
        # Feature 133272 required a redesign which again changed the format
        # of the configuration file. The identifier '#### CSM' was changed
        # to '#### CSM Version 8.1.1' to tag the new format. BTW, unlike the
        # 7.2->8.1 reformat, the 8.1 and 8.1.1 formats are both conserver
        # compatible.
        #
		$old_format = grep /%%/, @cfg;

        # If we have an old format file, move it to a new location, then
        # generate a new file from all the nodes currently defined.
        #
		if ($old_format)
		{
			$cmd = "/bin/mv /etc/opt/conserver/conserver.cf /etc/opt/conserver/conserver.cf.7.2";
			NodeUtils->run_cmd( $cmd, "W", "show_all" );
            $regen_cfg = 1;  # this will generate an 8.1.1 file in this release
        }
        else {
            $new_format = grep /##### CSM Version 8.1.1/, @cfg;
            if ($new_format == 0) {
			    $cmd = "/bin/mv /etc/opt/conserver/conserver.cf /etc/opt/conserver/conserver.cf.8.1";
			    NodeUtils->run_cmd( $cmd, "W", "show_all" );
                $regen_cfg = 1;  # if it's an 8.1 generate an 8.1.1. otherwise,
                                 # we must have already generated an 8.1.1
            }
        }

        # If a new format is required
        #
        if ($regen_cfg == 1) {

            # Call chrconsolecfg with the hidden -s option to retrieve the
            # node data directly from the CSM registry tables. Without this
            # flag, the command would try to retrieve the values via DMSRM.
            # This doesn't work at this point of the install, since the
            # CSM license agreement hasn't been accepted yet.
            #
			$cmd = "/opt/csm/bin/chrconsolecfg -a -s";
			$rc = NodeUtils->run_cmd( $cmd, "W", "show_all" );

            # If there was an error generating the configuration file, or there
            # is no configuration file, there's no point
            # in trying to start conserver (it won't run without a configuration
            # file).
            #
            if( $rc == 0 ) {
                if( -e $CFGFILE ) {
                    # Restart the conserver daemon so it sees the new config file
                    #
			        $cmd = "/opt/csm/bin/rconsolerefresh -r >/dev/null";
			        NodeUtils->run_cmd( $cmd, "W", "show_all" );
                }
            }
		}
	}
}

#--------------------------------------------------------------------------------

=head3    Main

        Notes: 

=cut

#--------------------------------------------------------------------------------

{    # main

	my ($rc)         = 0;
	my ($returncode) = 0;
	if (NodeUtils->isHMC() && ($ENV{'DC_ENVIRONMENT'} ne 1))
	{
		MessageUtils->messageFromCat(
			$::MSGCAT,
			$::MSGMAPPATH,
			$::MSGSET,
			'E1',
			'EMsgDisabledCmdOnHMC',
			'installms'
		);
	}

	$::IGNORE_SIS = 0;

	# load the packagedefs and intialize globs
	&initialize();

	# process command line
	&getArgs;

	# start logging
	MessageUtils->start_logging($::INSTALLMSLOG);

	# check if Migration install from lower level CSM
	my $preVersion =
	  NodeUtils->runcmd("$::RPMCMD -q csm.server --qf '%{VERSION}'", -1);
	if ($::RUNCMD_RC == 0)
	{
		NodeUtils->runcmd(
			 "/usr/bin/chrsrc-api -s IBM.DmsCtrl::::MigrationInfo::$preVersion",
			 -1
		);
	}

	# added end
    &set_variables;

	# verify that the rpm tool is present.
	ArchiveUtils->checkForRpmTool();

	# check for CSM temp directory and create if it does not exist
	#
	if (!-d $::CSMTMP)
	{
		mkpath($::CSMTMP, $::VERBOSE, 0700);
	}

	# Secure the directory and assign ownership
	# (0,0 is root:system on AIX, root:root on Linux)
	#
	chmod 0700, $::CSMTMP;
	chown 0, 0, $::CSMTMP;

	# create install directory
	ServerUtils->create_directory_structure();

	# copy the appropriate rpms to /csminstall
	my @rpmListsToBeCopied;
	push @rpmListsToBeCopied, $::Svrpkgdefs{'pkgs'}{'MgmtServer'};
	push @rpmListsToBeCopied, $::Svrpkgdefs{'pkgs'}{'MgdNode'};
	push @rpmListsToBeCopied, $::Svrpkgdefs{'pkgs'}{'InstallServer'};
    ArchiveUtils->update_packages_to_csminstall( 
					$::PREREQS_ATTR{'DistributionName'},
					$::PREREQS_ATTR{'DistributionVersion'},
					$::PREREQS_ATTR{'InstallServiceLevel'},
					$::PREREQS_ATTR{'PkgArchitecture'},
					$::PREREQS_ATTR{'CsmCoreVersion'},
					\@rpmListsToBeCopied,
                    '/csminstall',
					$::DONT_COPY_RPMS, 
					\%::Svrpkgdefs,
					$::NO_MOUNT_CD
					);

	# Install the packages.
    my @rpmListsToBeInstalled;
    push @rpmListsToBeInstalled, $::Svrpkgdefs{'pkgs'}{'MgmtServer'};
    my $installFlag = '-U --replacefiles';
	if ( ArchiveUtils->install_packages_Linux( \@rpmListsToBeInstalled, $installFlag, $::FORCE_INSTALL))
    {
        $rc = 0;
    }
    else
    {
        $rc = 1;
    }
	$returncode = $rc if ($rc > $returncode);

	# Set global cluster attributes in the dmsctrl resource class
	$rc         = &set_cluster_attrs;
	$returncode = $rc if ($rc > $returncode);

	# migrate conserver configuration file
	#
	migrateConserverCfg();

	# copy the csm command binaries.
	MessageUtils->message('I', 'IMsgCOPYING_CSMBINARIES');
	ServerUtils->copyBinaries;
	MessageUtils->message('I', 'IMsgCOMPLETE_COPYING_CSMBINARIES');

	#  notify success or failure
	if ($returncode == 0)
	{
		MessageUtils->message('I', 'IMsgINSTALLMS_SUCCESSFUL');
	}
	else { MessageUtils->message('E', 'EMsgINSTALLMS_UNSUCCESSFUL', $returncode); }

	# stop logging
	MessageUtils->stop_logging();

	# exit
	exit $returncode;
}
