#!/usr/bin/perl
# IBM_PROLOG_BEGIN_TAG 
# This is an automatically generated prolog. 
#  
#  
#  
# Licensed Materials - Property of IBM 
#  
# (C) COPYRIGHT International Business Machines Corp. 2002,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 
# @(#)40   1.56   src/csm/install/uninstallms.perl, setup, csm_rfish, rfishs001b 10/17/06 21:39:28

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

=head1    uninstallms.perl

        Development notes:

        The html view of the pod headers in this file can be updated
        by running the command:  

                  tidypod <filename>

	The html veiw of the pod headers will be in the file ./<filename>.html
	and can be viewed with a browser.

	The tidy formatted file will be in <filename>.tdy

	Be sure to run tidypod and copy the .tdy file to <filename> before checking
	in changes.

=cut

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

use strict;

BEGIN { $::csmpm = $ENV{'CSM_PM'} ? $ENV{'CSM_PM'} : '/opt/csm/pm'; }

use lib $::csmpm;
use Getopt::Std;
require NodeUtils;
require CSMDefs;
require ServerUtils;
require ArchiveUtils;
require MessageUtils;
use Rpm::RpmList;
use File::Path;    #provides mkpath and rmtree

# sets local scope - we only want classes on the Managment Server
# though it's not clear that classes are being used ...?

$ENV{'CT_MANAGEMENT_SCOPE'} = 1;

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

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

=head3	initialize	

        Notes:	globals only

	get the definitions we need for this command 
	in this case get_OSDefs uses the attrs of the management 
	server to identify the correct definitions

=cut

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

sub initialize
{

	# setup the global os define variables
	ServerUtils->get_OSDefs();

	@::My_NodeList    = ();

	# gather the variables
	$::ATTRS{'InstallCSMVersion'} = NodeUtils->get_CSMVersion("csm\.core");
	$::ATTRS{'InstallOSName'}     = NodeUtils->get_OSName;
	$::ATTRS{'InstallDistributionName'}    = NodeUtils->get_DistributionName;
	$::ATTRS{'InstallDistributionVersion'} = NodeUtils->get_DistributionVersion;
	$::ATTRS{'InstallPkgArchitecture'}     = ArchiveUtils->get_PkgArchitecture;

	$::osTypeVersion =
	    $::ATTRS{'InstallOSName'}
	  . $::ATTRS{'InstallDistributionName'}
	  . $::ATTRS{'InstallDistributionVersion'};

	#
	# get the appropriate lists of filesets/packages
	#
	# for the management server
	%::Svrpkgdefs =
	  ServerUtils->get_pkgdefs(
							   $::ATTRS{'InstallOSName'},
							   $::ATTRS{'InstallDistributionName'},
							   $::ATTRS{'InstallDistributionVersion'},
							   $::ATTRS{'InstallPkgArchitecture'},
							   "MgmtServer",
							   $::ATTRS{'InstallCSMVersion'}
							  );


	if (!defined $::HAMODE && -e "/usr/sbin/rsct/bin/IBM.DMSRMd")
	{
		my $outref =
		  NodeUtils->runcmd("CT_MANAGEMENT_SCOPE=1 /usr/sbin/rsct/bin/lsrsrc-api -i -s IBM.DmsCtrl::::HAMode", -1);
		if (!$::RUNCMD_RC)
		{
			$::HAMODE = $outref;
		}
	}
	if ($::HAMODE != 0)
	{    #cant run uninstallms
		MessageUtils->messageFromCat('hams.cat', $::MSGMAPPATH, 'hams', 'E1',
									 'EMsgUninstallms', $::HAMODE);
	}

}

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

=head3	usage	

        Notes:

=cut

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

sub usage
{

	MessageUtils->message('I', 'IMsguninstallmsUsage');
	exit 1;
}

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

=head3	getArgs	

        Notes:

=cut

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

sub getArgs
{
	if (!getopts('fuvVh')) { &usage; }

	if ($::opt_h) { &usage }
	if ($::opt_v) { $::VERBOSE = $::opt_v; }
	if ($::opt_V) { $::VERBOSE = $::opt_V; }

	if (NodeUtils->isHMC() && ($ENV{'DC_ENVIRONMENT'} ne 1))
	{
		MessageUtils->messageFromCat(
			$::MSGCAT,
			$::MSGMAPPATH,
			$::MSGSET,
			'E1',
			'EMsgDisabledCmdOnHMC',
			'uninstallms'
		);
	}
	
	# check if the Machine is Management Server
	$::isMS = 1;
	if (!NodeUtils->isMgmtSvr())
	{
                $::isMS = 0;
                if (NodeUtils->isNode())
                {
                        MessageUtils->message('E2', 'EMsgCommandOnNode');
                }
        }

        if ($::opt_u && !$::isMS)
        {
                MessageUtils->message('E2', 'EMsgRmnodeNotOnMS');
        }

        if (!$::opt_f && $::opt_u && $::isMS)
	{
		MessageUtils->message('P', 'IMsgUNINSTALLMS_VERIFY_U');
		my $input = getc;
		if (($input !~ /^y/) and ($input !~ /^Y/))
		{
			MessageUtils->message('I', 'IMsgUNINSTALLMS_NOT_UNINSTALLING');
			exit 0;
		}
	}

	if (!$::opt_f && !$::opt_u && $::isMS)
	{
		MessageUtils->message('P', 'IMsgUNINSTALLMS_VERIFY');
		my $input = getc;
		if (($input !~ /^y/) and ($input !~ /^Y/))
		{
			MessageUtils->message('I', 'IMsgUNINSTALLMS_NOT_UNINSTALLING');
			exit 0;
		}
	}

}

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

=head3	remove_files_dir	

        Notes:

=cut

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

sub remove_files_dir
{
	my ($file_name, undef) = @_;
	#rmtree does not support wildcard in filename
	my @files = glob($file_name);
	foreach my $file( @files)
	{
		rmtree($file, $::VERBOSE, 1);
	}
}

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

=head3	Main	

	Programmers note:

		Basically there are 2 conditions: AIX or Linux.
		If this is AIX, then the first big "if" will be done,
		otherwise, go to the other "if" InstallOSName eq Linux.

=cut

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

{    # main

	# Just in case the current directory is one that uninstallms 
	# will delete, change to the user's HOME directory.
	chdir();

	# initialize global variables
	&initialize;

	# parse the arguments
	&getArgs;

	my $runoption = "-1";

	if ($::VERBOSE) { $runoption = "0"; }

	# if backup data is available in /var/opt/csm/csmdata then copy it to
	# /tmp so that it is not removed, and then mv it back so that it is not
	# removed.
	if (-d "/var/opt/csm/csmdata")
	{
		my $cmd = "mv -f /var/opt/csm/csmdata /tmp/csmdata.uninstallms";
		NodeUtils->runcmd($cmd, -1);
	}

	# bad InstallOSName value
	if (   ($::ATTRS{'InstallOSName'} ne "Linux")
		&& ($::ATTRS{'InstallOSName'} ne "AIX"))
	{
		MessageUtils->message('E1', 'EMsgUnsupportedOS');
	}

	my $isLicenseValid = 0;
	if ($::isMS && NodeUtils->csm_license_valid())
	{
		$isLicenseValid = 1;
	}

	#  AIX

	if ($::ATTRS{'InstallOSName'} eq "AIX")
	{
		if ($::isMS && $isLicenseValid)
		{
			# Remove the members of a Node Group
			NodeUtils->runcmd(
				"/usr/bin/chrsrc-api -i -s IBM.NodeGroup::\"MemberList!=''\"::\"MemberList::\"{}\"\"",
				$runoption, 0
			);
			if ($::RUNCMD_RC != 0)
			{
				MessageUtils->message('W', 'EMsgCannotRemoveNodegrpMembers');
			}
	
			# Before we remove the nodes, we need to see if the license has been
			# installed yet.  We can do this by checking to see if the "receipt"
			# file exists.  Their are two places we can check:
			# /var/opt/csm/1.3/tryandbuy/license/status.dat
			# or
			# /var/opt/csm/1.3/full/license/status.dat
			# where 1.3 is the csmversion.
			my $statusDir = "/var/opt/csm/";

			# now get the CSM version.  We only take the version and mod.
			# so 1.3.0.1 -> 1.3
			# and 1.3.2  -> 1.3
			# and 1.5.0  -> 1.5
	
			my $ver = $::ATTRS{'InstallCSMVersion'};
			$ver =~ /(\d+)\.(\d+)/;
			$ver = "$1.$2";
			$statusDir .= "$ver/";

			my $tabStatusFile  = $statusDir . "tryandbuy/license/status.dat";
			my $fullStatusFile = $statusDir . "full/license/status.dat";

			# if one of the above status files exist, then the license has been accepted.
			# this implies that there may be nodes defined.
			if ((-f $tabStatusFile) || (-f $fullStatusFile))
			{

				# Remove the  Node groups from the system
				NodeUtils->runcmd(
					"/usr/bin/rmrsrc-api -i -s IBM.NodeGroup::\"Name!=''\"",
					$runoption, 0);
				if ($::RUNCMD_RC != 0)
				{
					MessageUtils->message('W', 'EMsgCannotRemoveNodegrp');
				}

				# get the node list
				my $myresult = NodeUtils->listNodeAttrs([], "Hostname");
				foreach my $my_node (@$myresult)
				{
					push(@::My_NodeList, $my_node);
				}
				my $rm_cmd = "$::RMNODE";
				$rm_cmd .= " -v" if ($::VERBOSE);
				$rm_cmd .= " -u" if ($::opt_u);
				if (@::My_NodeList){
					my $nodeFile;
					my $mycmd;
					if( scalar(@::My_NodeList) > 500){
						$nodeFile = ServerUtils->make_node_list_file(\@::My_NodeList);
					}
					if($nodeFile){
						$mycmd = "$rm_cmd -f $nodeFile";
					}
					else{
						my $nodeList = join "," , @::My_NodeList;
						$mycmd = "$rm_cmd -n $nodeList";
					}
					$myresult = NodeUtils->runcmd("$mycmd", $runoption);
					if ($::RUNCMD_RC != 0)
					{
						MessageUtils->message('W', 'EMsgCANT_RUN_CMD', $mycmd);
					}
					if ($nodeFile){
						ServerUtils->close_delete_file($::NODE_LIST_FILE, $nodeFile);
					}
				}
			}    # the enclosed is only done if the lic has been accepted.
		}

		# Now remove the CSM packages
		my ($my_package, $my_logfile, $my_cmd, $my_result);

		# remove the pre-defined-condresposes
		# this is done in csmserveruncfg

		# remove the package groups one by one
		my @groups = (\@{$::Svrpkgdefs{'csm_unpackages'}},
			\@{$::Svrpkgdefs{'rsct_unpackages'}});
		foreach my $group_ref (@groups)
		{
			my @installed = NodeUtils->getInstalledPkgs(@$group_ref);
			if (!scalar(@installed))
			{
				next;
			}
			my $installed_pkgs = join ' ', @installed;
			$my_cmd = "$::INSTALLPCMD -ug $installed_pkgs";
			$my_result = NodeUtils->runcmd("$my_cmd", $runoption);
			MessageUtils->message('W', 'EMsgCANT_RUN_CMD', $my_cmd)
			  if ($::RUNCMD_RC);
		}
	}

	# LINUX

	if ($::ATTRS{'InstallOSName'} eq "Linux")
	{
		# For Linux we just remove the CSM packages
		# We don't remove any nodes, because they will get removed with
		# the packages.

		# If -u option is used than than run rmnode command
		if ($::opt_u)
		{

			# get the node list
			my $myresult = NodeUtils->listNodeAttrs([], "Hostname");
			foreach my $my_node (@$myresult)
			{
				push(@::My_NodeList, $my_node);
			}
			my $rm_cmd = "$::RMNODE";
			$rm_cmd .= " -v" if ($::VERBOSE);
			$rm_cmd .= " -u" if ($::opt_u);
			if (@::My_NodeList){
				my $nodeFile;
				my $mycmd;
				if( scalar(@::My_NodeList) > 500){
					$nodeFile = ServerUtils->make_node_list_file(\@::My_NodeList);
				}
				if($nodeFile){
					$mycmd = "$rm_cmd -f $nodeFile";
				}
				else{
					my $nodeList = join "," , @::My_NodeList;
					$mycmd = "$rm_cmd -n $nodeList";
				}
				$myresult = NodeUtils->runcmd("$mycmd", $runoption);
				if ($::RUNCMD_RC != 0)
				{
					MessageUtils->message('W', 'EMsgCANT_RUN_CMD', $mycmd);
				}
				if ($nodeFile){
					ServerUtils->close_delete_file($::NODE_LIST_FILE, $nodeFile);
				}
			}
		}
        
        my @rpmListsToBeUninstalled;
        push @rpmListsToBeUninstalled, $::Svrpkgdefs{'pkgs'}{'MgmtServer'};
	
		if ($::isMS && $isLicenseValid)
		{
			NodeUtils->runcmd(
				"/usr/bin/rmrsrc-api -i -s IBM.NodeGroup::\"Name!=''\"", $runoption, 0);
			NodeUtils->runcmd(
				"/usr/bin/rmrsrc-api -i -s IBM.ManagedNode::\"Name!=''\"", $runoption, 0);
		}

        ArchiveUtils->uninstall_packages_Linux( \@rpmListsToBeUninstalled, '-e');
	}

	# Both AIX and Linux

	# Is rsct.core installed?
	my $rsct_pkg = "rsct.core";
	my $cmd      = "$::RPMCMD -q $rsct_pkg 2>&1 > /dev/null";
	NodeUtils->runcmd("$cmd", -1);

	# Clean the rmsr table if rsct.core is still installed
	if ($::RUNCMD_RC == 0)
	{

		# not adding messages - runcmd should show in the log.
		my $RMSRTBL = "/usr/bin/rmsrtbl-api";

		# DmsCtrl
		$cmd = "$RMSRTBL /IBM/DmsCtrl/Resources";
		NodeUtils->runcmd("$cmd", 0);
	}

	# remove the log files package
	foreach my $my_logfile (@::csm_logfilelist)
	{
		&remove_files_dir($my_logfile);
	}

	# Remove /var/opt/csm/isInstallServer file if it exists
	if (-f $::IsInstallServer_file)
	{
		&remove_files_dir($::IsInstallServer_file);
	}

	# remove the temp files for installation
	&remove_files_dir("/tmp/cluster_info_*");
	&remove_files_dir("/tmp/InstallTime*");

	if ($::isMS)
	{
		# remove RDM links to csm configuration files
		my @links = ("csm", "pxelinux.0", "pxelinux.cfg");
		my $dir = "/tftpboot/opt/IBM/RDM/repository/environment";
		foreach my $link (@links)
		{
			if (-l "$dir/$link")
			{
				unlink "$dir/$link";
			}
		}

		# if the conserver daemon is running, stop it.
		# Without this check, it's possible that the
		# daemon will remain running throughout the uninstall/install
		# process, during which time the conserver UDS socket
		# directory in /var/opt/csm/tmp is removed.  If the daemon
		# is not restarted, this directory will not be re-created
		# and subsequent rconsole commands will fail.  So, we
		# kill the daemon here, and on the subsequent reinstall, it
		# will be started again when the nodes are defined.
		#
		if (-s "/var/run/conserver.pid")
		{
			open CONSERVER_PID, "</var/run/conserver.pid";
			my $conserver_pid = <CONSERVER_PID>;
			close CONSERVER_PID;

			kill "TERM", $conserver_pid;
		}

		# Display a list of the files, Directories and packages that were not
		# uninstalled (because they were not installed by installms)

		my @notremovedirs = @{$::Svrpkgdefs{csm_uninstall_dirs}};

		# Print the messages about diskless directories
		my @disklessdirs = ("/etc/warewulf", "/srv/vnfs");
		foreach my $dir (@disklessdirs) 
		{
			if (-d $dir)
			{
				push @notremovedirs, $dir;
			}
		} 
		MessageUtils->message('I', 'IMsgDidnotRemoveDir',
					join(', ', @notremovedirs));
	}
	MessageUtils->message('I', 'IMsgDidnotRemovePkgs',
						  join(', ', @{$::Svrpkgdefs{csm_nouninstall_pkgs}}));
	MessageUtils->message('I', 'IMsgDidnotUninstallOpenSrcPkgs');
	if ($::isMS)
	{
		MessageUtils->message('I', 'IMsgDidnotUnconfigureRemoteShellServer');
	}

	# put csmdata back
	if (-d "/tmp/csmdata.uninstallms")
	{
		NodeUtils->runcmd("mkdir -p /var/opt/csm/", -1);
		NodeUtils->runcmd("mv -f /tmp/csmdata.uninstallms /var/opt/csm/csmdata",
						  -1);
	}

	exit 0;
}
