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

package XCAT;
use Socket;
use xCAT::Utils;
use xCAT::MsgUtils;
use base xCAT::DSHContext;
# 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, store the remote command settings for
        the remote shell and remote copy commands as defined in xCAT 
		site.tab file.

        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
{
    $XCAT_RSH_CMD = "/usr/bin/ssh";    # default
    $XCAT_RCP_CMD = "/usr/bin/scp";    #default
    my @remote_shell = xCAT::Utils->get_site_attribute("rsh");
    if ($remote_shell[0])
    {
        $XCAT_RSH_CMD = $remote_shell[0];
    }
    my @remote_copy = xCAT::Utils->get_site_attribute("rcp");
    if ($remote_copy[0])
    {
        $XCAT_RCP_CMD = $remote_copy[0];
    }

}

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

=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
{
    $node_list = "";
    my @nodegroups = xCAT::Utils->list_all_node_groups;
    for my $group (@nodegroups)
    {
        chomp($group);
        my @nodes = `nodels $group`;
        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