#!/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 
# @(#)27   1.81   src/csm/core/cmds/rmnode.perl, csmcore, csm_rfish, rfishs001b 10/31/06 06:38:46

use strict;
use locale;

BEGIN
{
	# this enables us to redirect where it looks for other CSM files during development
	$::csmroot = $ENV{'CSM_ROOT'} ? $ENV{'CSM_ROOT'} : '/opt/csm';
	$::csmpm   = "$::csmroot/pm";
	$::csmbin  = "$::csmroot/bin";
}
use lib $::csmpm;
use Getopt::Std;
require NodeUtils;
require MessageUtils;
require ServerUtils;
require NetworkUtils;
require CSMDefs;
require InstallKRB5Utils;
require NodesetUtils;
require DCUtils;
require DCAPI;

# get the global definitions we need for this command
# in this case get_OSDefs uses the attrs of the management
# server to identify the correct definitions
%::myOSDefs = ServerUtils->get_OSDefs();

# For the usage, see nodecmds.msg
sub usage
{
	MessageUtils->message('I', 'IMsgRmnodeUsage');
	exit(scalar(@_) ? $_[0] : 1);
}

# dsh will not set default PATH. We run some commands without full path name 
# before eso release, so we should set PATH manually.
$ENV{'DSH_PATH'}='/usr/bin:/bin:/usr/sbin:/sbin';

# set local scope because we only want classes on the mgmt svr
$ENV{'CT_MANAGEMENT_SCOPE'} = 1;    
$::MSGSET     = 'rmnode';               # setting this explicitly
$::MSGCAT     = 'nodecmds.cat';
$::MSGMAPPATH = "$::csmroot/msgmaps";

# Parse the cmd line args and check them
if (!getopts('uhvVN:f:n:')) { &usage; }
if ($::opt_h) { &usage(0); }
if (   scalar(@ARGV) < 1 && !defined($::opt_N)
	&& !defined($::opt_f) && !defined($::opt_n))
{
	&usage;
}

$::VERBOSE       = $::opt_v || $::opt_V;
$::RMNODE_CLIENT = "/opt/csm/csmbin/rmnode_client";

#
# Get KRB5 credentials
#
my $krb5_tgt   = 0;
my $KRB5CCNAME = "";
$KRB5CCNAME = InstallKRB5Utils->getKRB5tgt;
if ($KRB5CCNAME ne "")
{
	$ENV{'KRB5CCNAME'} = $KRB5CCNAME;
	$krb5_tgt = 1;
}

my ($nodeListRef, $lsnodeInfoRef, $nodeHashRef) =
  NodeUtils->get_target_nodes(\@ARGV,'',$::opt_f);
$ENV{'DC_ENVIRONMENT'}="CSM";
my ($nodeHashRef, $ISHashRef) = ServerUtils->getInstallServerHashFromNode($nodeHashRef, 1);
my $skip_generate_scripts_list = 1;
my $nodeinfoHashRef = ServerUtils->make_nodeinfo_hash($nodeHashRef, $skip_generate_scripts_list);
my $ISinfoHashRef = ServerUtils->make_nodeinfo_hash($ISHashRef, $skip_generate_scripts_list);
my %clusterInfoHash = ();
ServerUtils->set_cluster_info_hash(\%clusterInfoHash);

my $skipFileLoad = 0;
DCAPI->DCrmnode(\%clusterInfoHash,$nodeinfoHashRef,$ISinfoHashRef,$skipFileLoad,$::VERBOSE);

#NodeUtils->get_target_nodes() will set $ENV{'CSM_NO_NAME_RES'}
delete $ENV{'CSM_NO_NAME_RES'} if exists $ENV{'CSM_NO_NAME_RES'};

my $nodelist = NodeUtils->gatherNodeList(\@ARGV);
if (!scalar(@$nodelist))
{
	$::MSGSET = 'createnode';
	MessageUtils->message('E13', 'EMsgNO_NODES');
}
my $res2unres;
($nodelist, $res2unres) = NodeUtils->resolveAndUndup($nodelist);
my $where = qq/"Hostname IN ('XXX')"/;
my @cleanup_nodes;

if ($::opt_u)
{
	#Make a Hash of ManagedNodes as keys with their Managemnent Sever as the value
	%::MgNodeMgSvrHash;
	%::MgNodeMgOSnameHash;
	my ($mynode_file, $myhostname, $mymanagemnentserver, $installmethod, @myNodeList, $myDshCmd,
		$myNodeOSName, $mymode, @localresults);
	my ($myval, $myval1, $myval2);
	@myNodeList = @$nodelist;
	my $myresults =
	  NodeUtils->listNodeAttrs(\@myNodeList,
							 "Hostname, ManagementServer, Mode, InstallOSName, InstallMethod");

	foreach $myval (@$myresults)
	{
		($myhostname, $mymanagemnentserver, $mymode, $myNodeOSName, $installmethod) = split(':\|:', $myval);
		if (!($mymode =~ /PreManaged/) and !($mymode =~ /$::CSMLITE/)
			and !($installmethod =~ /warewulf/))
		{
			$::MgNodeMgSvrHash{"$myhostname"}    = $mymanagemnentserver;
			$::MgNodeMgOSnameHash{"$myhostname"} = $myNodeOSName;
			push(@cleanup_nodes, $myhostname);
		}
	}

	if (scalar(keys %::MgNodeMgSvrHash) != 0)
	{
		#Run dsh command on all the nodes to get the Management Server fromn the node
		#put all dest nodes in tmp file
		$mynode_file = ServerUtils->make_node_list_file(\@cleanup_nodes);    
		$ENV{'DSH_LIST'} = $mynode_file;

		$myDshCmd =
		  "$::DSH -v  \" lsrsrc-api -s IBM.ManagementServer::\\\"ManagerType='CSM'\\\"::Hostname\"";
		MessageUtils->messageFromCat('csmInstall.cat', $::MSGMAPPATH,
									 'csminstall', 'V', 'IMsgRUN_CMD',
									 $myDshCmd);
		@localresults = NodeUtils->runcmd("$myDshCmd", -1);
		if ($::RUNCMD_RC != 0)
		{
			MessageUtils->messageFromCat('csmInstall.cat', $::MSGMAPPATH,
										 'csminstall', 'E', 'EMsgNO_DSH');
		}
		#delete node file
		ServerUtils->close_delete_file($::NODE_LIST_FILE, $mynode_file);    
		delete $ENV{'DSH_LIST'};

		$myval = "";

		# For each ManagedNode compare the Management server value with value from the dsh command
		# if not equal the delete the node
		foreach my $myval (@localresults)
		{
			chomp $myval;
			($myval1, $myval2) = split(': ', $myval);
			if ($::MgNodeMgSvrHash{"$myval1"} ne $myval2)
			{
				delete $::MgNodeMgSvrHash{"$myval1"};
				delete $::MgNodeMgOSnameHash{"$myval1"};
			}
		}
	}
}

# Delete the nodes
my $outref =
  NodeUtils->runrmccmd('rmrsrc-api', '-i', qq(-s IBM.ManagedNode::$where),undef,$nodelist);
my $numfound  = scalar(@$outref);
my $numtofind = (defined($nodelist) ? scalar(@$nodelist) : 0);

# Check for nodes not found so we can try the unresolved names
if ($numtofind && $numfound < $numtofind)
{
	# If we only try the names that were resolved into a different name, then we should not end
	# up trying to remove any nodes twice.
	my @a;
	foreach my $k (keys %$res2unres)
	{
		if ($k ne "" && $k ne $$res2unres{$k}) { push @a, @{$$res2unres{$k}}; }
	}
	$where  = qq/"Hostname IN ('XXX')"/;
	$outref =
	  NodeUtils->runrmccmd('rmrsrc-api', '-i', qq(-s IBM.ManagedNode::$where),undef,\@a);
	$numfound += scalar(@$outref);
}

if ($numfound < $numtofind)
{
	$::MSGSET = 'lsnode';
	if (scalar(@$nodelist) == 1)
	{
		MessageUtils->message('E12', 'EMsgNODE_NOT_FOUND', $$nodelist[0]);
	}
	elsif (scalar(@$nodelist) <= 10)
	{
		MessageUtils->message('W12', 'EMsgSOME_NOT_FOUND_LIST',
							  join(', ', @$nodelist));
	}
	else { MessageUtils->message('W12', 'EMsgSOME_NOT_FOUND'); }
}

# wait for DMSRM to be recycled after removing the resource.
# this will prevent the removed node to come back alive after restarting RMC.
sleep(1); 

#if the -u option is set then run rmnode.client on the node which in turn
#uninstalls csm, rsct packages and logs for Linux and log files for AIX on the
#node after removing the node from the database
if ($::opt_u)
{

	if ($::PLTFRM eq "AIX")
	{
		#  Ensure the binaries in /csminstall/csm are current
		ServerUtils->copyBinaries;
	}

	# use dsh run /opt/csm/csmbin/rmnode.client
	# and unmount
	if (scalar @cleanup_nodes)
	{
		my $ref_nodelist = moveRmnode_client(\@cleanup_nodes);
		@cleanup_nodes = @$ref_nodelist;
		if ((scalar @cleanup_nodes) and &run_DSH_Commands(\@cleanup_nodes) != 0)
		{
			# An error occured when executing DSH
			MessageUtils->messageFromCat('csmInstall.cat', $::MSGMAPPATH,
										 'csminstall', 'E2', 'EMsgNO_DSH');
		}
	}

	MessageUtils->messageFromCat('csmInstall.cat', $::MSGMAPPATH, 'csminstall',
								 'I', 'IMsgDidnotUninstallOpenSrcPkgs');
	MessageUtils->messageFromCat(
								 'csmInstall.cat',
								 $::MSGMAPPATH,
								 'csminstall',
								 'I',
								 'IMsgDidnotUnconfigureRemoteShellNode'
								);

}

# get rid of KRB5 tgt if gotten
if ($krb5_tgt == 1)
{
	NodeUtils->runcmd("$::CSMCSMBIN/k5destroytgt 2>&1", -1);    # never errors
}

exit;

#--------------------------------------------------------
#
# Sub routines
#
#--------------------------------------------------------
#####################################################################
sub run_DSH_Commands
{
	my ($nodelist) = @_;
	my @dsh_results;
	my $rc                = 0;
	my $rmnode_client_cmd = $::RMNODE_CLIENT;
	if ($::VERBOSE)
	{
		$rmnode_client_cmd .= " -v";
	}
	#put all dest nodes in tmp file
	my $node_file = ServerUtils->make_node_list_file($nodelist);    
	$ENV{'DSH_LIST'} = $node_file;
	my @local_dsh_results = ();
	my $dsh_command       = "$::DSH -v  ";

	$dsh_command .= "$rmnode_client_cmd 2>&1; ";

	MessageUtils->messageFromCat('csmInstall.cat', $::MSGMAPPATH, 'csminstall',
								 'V', 'IMsgRUN_CMD', $dsh_command);
	@local_dsh_results = NodeUtils->runcmd("$dsh_command", -1);
	$rc                = $::RUNCMD_RC;

	if ($rc != 0)
	{
		# Error executing DSH.
		MessageUtils->messageFromCat('csmInstall.cat', $::MSGMAPPATH,
									 'csminstall', 'E', 'EMsgNO_DSH');
	}
	chop @local_dsh_results;
	ServerUtils->close_delete_file($::NODE_LIST_FILE, $node_file);    
    # push @dsh_results, @local_dsh_results;
    # print errors
	foreach my $line (@local_dsh_results)
	{
		MessageUtils->messageFromCat('csmInstall.cat', $::MSGMAPPATH,
									 'csminstall', 'I', 'IMsgShow_Output',
									 $line);
	}
	return $rc;
}

sub moveRmnode_client
{
	my ($nodelist) = @_;

	#first determine which machines do not have /opt/csm/csmbin/rmnode_client
	my $node_file = ServerUtils->make_node_list_file($nodelist);
	$ENV{'DSH_LIST'} = $node_file;
	my @local_dsh_results = ();
	my $dsh_command       = "LANG=C $::DSH -v  ";
	$dsh_command .= "$::LS $::RMNODE_CLIENT 2>&1; ";

	MessageUtils->messageFromCat('csmInstall.cat', $::MSGMAPPATH, 'csminstall',
								 'V', 'IMsgRUN_CMD', $dsh_command);
	@local_dsh_results = NodeUtils->runcmd("$dsh_command", -1);
	#delete node file
	ServerUtils->close_delete_file($::NODE_LIST_FILE, $node_file);
	delete $ENV{'DSH_LIST'};
    
	my @nocsm_nodes;
	foreach my $line (@local_dsh_results)
	{
		chomp $line;
		my ($node, $info) = split ':', $line, 2;
		if ($info =~ m/No such file or directory/)
		{
			push @nocsm_nodes, $node;
		}
	}
	my @target_nodes = ();
	
	if (scalar @nocsm_nodes)
	{
		MessageUtils->message('I', 'IMsgNoCommandInNodes',"$::RMNODE_CLIENT", 
							  join(",", @nocsm_nodes)); 
		foreach my $node (@$nodelist)
		{
			if (! grep /^$node$/, @nocsm_nodes)
			{
				push @target_nodes, $node;
			}
		}
		return \@target_nodes;
	}	
	return $nodelist;
}
