#!/usr/bin/perl
# IBM(c) 2007 EPL license http://www.eclipse.org/legal/epl-v10.html

package XCAT;
use base xCAT::DSHContext;
use strict;
use Socket;
use xCAT::Utils;
use xCAT::MsgUtils;
use xCAT::TableUtils;
# Define remote shell globals from xCAT

our $XCAT_RSH_CMD;
our $XCAT_RCP_CMD;

#
# get the remote command settings
#

XCAT->get_xcat_remote_cmds;

# Global Data structures for xCAT context

our @xcat_node_list       = ();
our %xcat_nodegroup_table = ();

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

=head3
        context_defaults

        Assign default properties for the xCAT context.  A default
        property for a context will be used if the property is
        not user configured in any other way.

        Arguments:
        	None

        Returns:
        	A reference to a hash table with the configured
        	default properties for the xCAT context
                
        Globals:
        	$XCAT_RSH_CMD
    
        Error:
        	None
    
        Example:
        	$default_properties = XCAT->config_defaults;

        Comments:
        	$defaults hash table contents:
        	
        		$defaults{'NodeRemoteShell'} - default remote shell to use for node targets

=cut

#-------------------------------------------------------------------------------
sub context_defaults
{
    my %defaults = ();

    $defaults{'NodeRemoteShell'} = $XCAT_RSH_CMD;

    return \%defaults;
}

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

=head3
        context_properties

        Configure the user specified context properties for the xCAT context.
        These properties are configured by the user through environment
        variables or external configuration files.

        Arguments:
        	None

        Returns:
        	A reference to a hash table of user-configured properties for
        	the xCAT context.
                
        Globals:
        	None
    
        Error:
        	None
    
        Example:
        	$properties = XCAT->config_properties

        Comments:

=cut

#-------------------------------------------------------------------------------
sub context_properties
{
    my %properties = ();

    $properties{'RemoteShell'}   = $XCAT_RSH_CMD;
    $properties{'RemoteCopyCmd'} = $XCAT_RCP_CMD;

    return \%properties;
}

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

=head3
        all_devices
            
        Comments: devices are nodes in the XCAT context.  Use node flags
        and not device flags.

=cut

#-------------------------------------------------------------------------------
sub all_devices
{
    my ($class, $resolved_targets) = @_;

    xCAT::MsgUtils->message(
        "E",
        " Nodes and Devices are considered nodes in xCAT.\n The -A flag is not supported. Use the all group in XCAT to dsh to all node/devices.\n"
        );
    return;
}

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

=head3
        all_nodes

        Returns an array of all node names in the xCAT context
		Note in xCAT everything is a node including devices

        Arguments:
        	None

        Returns:
        	An array of node/device names
                
        Globals:
        	@xcat_node_list
    
        Error:
        	None
    
        Example:
        	@nodes = XCAT->get_xcat_node_list;

        Comments:

=cut

#-------------------------------------------------------------------------------
sub all_nodes
{
    scalar(@xcat_node_list) || XCAT->get_xcat_node_list;
    return @xcat_node_list;
}

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

=head3
        all_nodegroups

        Returns an array of all node group names in the xCAT context
		Note in xCAT everything is a node including devices

        Arguments:
        	None

        Returns:
        	An array of node/device group names
                
        Globals:
        	%xcat_nodegroup_table
    
        Error:
        	None
    
        Example:
        	@nodegroups = XCAT->all_nodegroups;

        Comments:

=cut

#-------------------------------------------------------------------------------
sub all_nodegroups
{
    scalar(%xcat_nodegroup_table) || XCAT->get_xcat_nodegroup_table;
    return keys(%xcat_nodegroup_table);
}

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

=head3
        nodegroup_members

        Given a node/device group in the xCAT context, this routine expands the
        membership of the  group and returns a list of its members.

        Arguments:
        	$nodegroup - node group name

        Returns:
        	An array of node group members
                
        Globals:
        	$nodegroup_path
    
        Error:
        	None
    
        Example:
        	$members = XCAT->nodegroup_members('MyGroup1');

        Comments:

=cut

#-------------------------------------------------------------------------------
sub nodegroup_members
{
    my ($class, $nodegroup) = @_;
    my %node_list = ();
    scalar(%xcat_nodegroup_table) || XCAT->get_xcat_nodegroup_table;
    !defined($xcat_nodegroup_table{$nodegroup}) && return undef;

    my @nodes = split /,/, $xcat_nodegroup_table{$nodegroup};

    foreach my $node (@nodes)
    {
        $node_list{$node}++;
    }

    my @members = keys(%node_list);
    return \@members;

}

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

=head3
        resolve_node

        Within the xCAT context, resolve the name of a given node and
        augment the supplied property hash table with xCAT node information.        

        Arguments:
        	$target_properties - basic properties hash table reference for a node

        Returns:
        	1 if resolution was successful
        	undef otherwise
                
        Globals:
        	$XCAT_RSH_CMD
        	$XCAT_RCP_CMD
    
        Error:
        	None
    
        Example:
        	XCAT->resolve_node($target_properties);

        Comments:

=cut

#-------------------------------------------------------------------------------
sub resolve_node
{
    my ($class, $target_properties) = @_;

    $$target_properties{'remote-shell'} = $XCAT_RSH_CMD;
    $$target_properties{'remote-copy'}  = $XCAT_RCP_CMD;

    return 1;
}

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

=head3
        get_xcat_remote_cmds

        Using xCAT native commands,check the useSSHonAIX attribute for AIX 
          on Linux use ssh    
          on AIX, check for useSSHonAIX,  if says use ssh and
           it is installed and configured, use it
          , otherwise use rsh

        site.rsh and site.rcp are no longer used

        Arguments:
        	None

        Returns:
        	None
        	                
        Globals:
        	$XCAT_RSH_CMD
        	$XCAT_RCP_CMD
    
        Error:
        	None
    
        Example:
        	XCAT->get_xcat_remote_cmds

        Comments:
        	Internal routine only

=cut

#-------------------------------------------------------------------------------
sub get_xcat_remote_cmds
{
    # override with site table settings, if they exist 
    my $ssh_setup = 0;
    my @useSSH = xCAT::TableUtils->get_site_attribute("useSSHonAIX");
    if (defined($useSSH[0])) {
      $useSSH[0] =~ tr/a-z/A-Z/;    # convert to upper 
      if (($useSSH[0] eq "1") || ($useSSH[0] eq "YES"))
      {
          $ssh_setup = 1;
      }
    } else {   # default is SSH
          $ssh_setup = 1;
    }
    if (xCAT::Utils->isLinux()) { 
      $XCAT_RSH_CMD = "/usr/bin/ssh";    # use ssh
      $XCAT_RCP_CMD = "/usr/bin/scp"; 
    } else { # AIX
      if ((-e "/usr/bin/ssh") && ( $ssh_setup == 1)) {  # ssh is configured 
        $XCAT_RSH_CMD = "/usr/bin/ssh";    # use ssh 
        $XCAT_RCP_CMD = "/usr/bin/scp"; 
      } else {
        $XCAT_RSH_CMD = "/usr/bin/rsh";    #  use rsh
        $XCAT_RCP_CMD = "/usr/bin/rcp"; 
      }
    }

}

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

=head3
        get_xcat_node_list

        Using xCAT native commands, this routine builds a cached list of
        node/device names defined in the xCAT context

        Arguments:
        	None

        Returns:
        	None
                
        Globals:
        	%xcat_node_list
    
        Error:
        	None
    
        Example:
        	XCAT->get_xcat_node_list

        Comments:
        	Internal routine only

=cut

#-------------------------------------------------------------------------------
sub get_xcat_node_list
{
    @xcat_node_list = xCAT::Utils->get_node_list;
    chomp(@xcat_node_list);
}

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

=head3
        get_xcat_nodegroup_table

        Using xCAT native commands, this routine builds a cached list of
        node groups and their members defined in the xCAT context

        Arguments:
        	None

        Returns:
        	None
                
        Globals:
        	%xcat_nodegroup_table
    
        Error:
        	None
    
        Example:
           XCAT->get_xcat_nodegroup_table

        Comments:
        	Internal routine only

=cut

#-------------------------------------------------------------------------------
sub get_xcat_nodegroup_table
{
    my $node_list = "";
    my @nodegroups = xCAT::TableUtils->list_all_node_groups;
    for my $group (@nodegroups)
    {
        chomp($group);
        my @nodes = `nodels $group`;
        my $node_list;
        while (@nodes)
        {
            my $nodename = shift @nodes;
            chomp($nodename);
            $node_list .= $nodename;
            $node_list .= ",";
        }
        chop($node_list);
        $xcat_nodegroup_table{$group} = $node_list;
        $node_list = "";
    }
}

sub query_node
{
    my ($class, $node, $flag) = @_;
    my @xcat_nodes = all_nodes();

    $~ = "NODES";
    if ($flag)
    {
        if (grep(/^$node$/, @xcat_nodes))
        {
            print("$node : Valid\n");
        }
        else
        {
            print("$node : Invalid\n");
        }
    }
    else
    {
        print("$node : Invalid\n");
    }
}

sub query_group
{

    my ($class, $group) = @_;
    my @xcat_groups = all_nodegroups();

    $~ = "GROUPS";
    if (grep(/^$group$/, @xcat_groups))
    {
        print("$group : Valid\n");
    }
    else
    {
        print("$group : Invalid\n");
    }
}

1;    #end