git-svn-id: https://svn.code.sf.net/p/xcat/code/xcat-core/trunk@1561 8638fb3e-16cb-4fca-ae20-7b5d299a9bcd
		
			
				
	
	
		
			465 lines
		
	
	
		
			9.5 KiB
		
	
	
	
		
			Perl
		
	
	
	
	
	
			
		
		
	
	
			465 lines
		
	
	
		
			9.5 KiB
		
	
	
	
		
			Perl
		
	
	
	
	
	
#!/usr/bin/perl
 | 
						|
# IBM(c) 2007 EPL license http://www.eclipse.org/legal/epl-v10.html
 | 
						|
 | 
						|
package DSH;
 | 
						|
use base xCAT::DSHContext;
 | 
						|
use xCAT::MsgUtils;
 | 
						|
use File::Path;
 | 
						|
 | 
						|
 | 
						|
# Configure Node group path from environment
 | 
						|
 | 
						|
our $nodegroup_path = $ENV{'DSH_NODEGROUP_PATH'};
 | 
						|
 | 
						|
=head3
 | 
						|
        context_defaults
 | 
						|
 | 
						|
        Assign default properties for the DSH 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 DSH context
 | 
						|
                
 | 
						|
        Globals:
 | 
						|
        	None
 | 
						|
    
 | 
						|
        Error:
 | 
						|
        	None
 | 
						|
    
 | 
						|
        Example:
 | 
						|
        	$default_properties = DSH->config_defaults;
 | 
						|
 | 
						|
        Comments:
 | 
						|
        	$defaults hash table contents:
 | 
						|
        	
 | 
						|
        		$defaults{'NodeRemoteShell'} - default remote shell to use for node targets
 | 
						|
 | 
						|
=cut
 | 
						|
 | 
						|
sub context_defaults {
 | 
						|
	my %defaults = ();
 | 
						|
 | 
						|
	if ( $ENV{'DSH_NODE_RSH'} ) {
 | 
						|
		my @remoteshell_list = split ',', $ENV{'DSH_NODE_RSH'};
 | 
						|
 | 
						|
		foreach $context_remoteshell (@remoteshell_list) {
 | 
						|
			my ( $context, $remoteshell ) = split ':', $context_remoteshell;
 | 
						|
 | 
						|
			if ( !$remoteshell ) {
 | 
						|
				$remoteshell = $context;
 | 
						|
				!$defaults{'NodeRemoteShell'}
 | 
						|
				  && ( $defaults{'NodeRemoteShell'} = $remoteshell );
 | 
						|
			}
 | 
						|
 | 
						|
			elsif ( $context eq 'DSH' ) {
 | 
						|
				$defaults{'NodeRemoteShell'} = $remoteshell;
 | 
						|
			}
 | 
						|
		}
 | 
						|
	}
 | 
						|
 | 
						|
	if ( !$defaults{'NodeRemoteShell'} ) {
 | 
						|
		my $dsh_context_defaults = xCAT::DSHContext->context_defaults;
 | 
						|
		$defaults{'NodeRemoteShell'} =
 | 
						|
		  $$dsh_context_defaults{'NodeRemoteShell'};
 | 
						|
	}
 | 
						|
 | 
						|
	return \%defaults;
 | 
						|
}
 | 
						|
 | 
						|
=head3
 | 
						|
        context_properties
 | 
						|
 | 
						|
        Configure the user specified context properties for the DSH 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 DSH context.
 | 
						|
                
 | 
						|
        Globals:
 | 
						|
        	None
 | 
						|
    
 | 
						|
        Error:
 | 
						|
        	None
 | 
						|
    
 | 
						|
        Example:
 | 
						|
        	$properties = DSH->config_properties
 | 
						|
 | 
						|
        Comments:
 | 
						|
 | 
						|
=cut
 | 
						|
 | 
						|
sub context_properties {
 | 
						|
	my %properties = ();
 | 
						|
 | 
						|
	$properties{'DCP_DEVICE_OPTS'} = $ENV{'DCP_DEVICE_OPTS'};
 | 
						|
	$properties{'DCP_DEVICE_RCP'}  = $ENV{'DCP_DEVICE_RCP'}
 | 
						|
	  || $ENV{'DCP_DEVICE_COPY_CMD'};
 | 
						|
	$properties{'DCP_NODE_OPTS'} = $ENV{'DCP_NODE_OPTS'};
 | 
						|
	$properties{'DCP_NODE_RCP'}  = $ENV{'DCP_NODE_RCP'} || $ENV{'DCP_COPY_CMD'};
 | 
						|
	$properties{'DSH_CONTEXT'}   = $ENV{'DSH_CONTEXT'};
 | 
						|
	$properties{'DSH_DEVICE_LIST'} = $ENV{'DSH_DEVICE_LIST'};
 | 
						|
	$properties{'DSH_DEVICE_OPTS'} = $ENV{'DSH_DEVICE_OPTS'}
 | 
						|
	  || $ENV{'DSH_DEVICE_REMOTE_OPTS'};
 | 
						|
	$properties{'DSH_DEVICE_RCP'} = $ENV{'DSH_DEVICE_RCP'};
 | 
						|
	$properties{'DSH_DEVICE_RSH'} = $ENV{'DSH_DEVICE_RSH'}
 | 
						|
	  || $ENV{'DSH_DEVICE_REMOTE_CMD'};
 | 
						|
	$properties{'DSH_ENVIRONMENT'}    = $ENV{'DSH_ENVIRONMENT'};
 | 
						|
	$properties{'DSH_FANOUT'}         = $ENV{'DSH_FANOUT'};
 | 
						|
	$properties{'DSH_LOG'}            = $ENV{'DSH_LOG'};
 | 
						|
	$properties{'DSH_NODEGROUP_PATH'} = $ENV{'DSH_NODEGROUP_PATH'};
 | 
						|
	$properties{'DSH_NODE_LIST'}      = $ENV{'DSH_NODE_LIST'}
 | 
						|
	  || $ENV{'DSH_LIST'}
 | 
						|
	  || $ENV{'WCOLL'};
 | 
						|
	$properties{'DSH_NODE_OPTS'} = $ENV{'DSH_NODE_OPTS'}
 | 
						|
	  || $ENV{'DSH_REMOTE_OPTS'};
 | 
						|
	$properties{'DSH_NODE_RCP'} = $ENV{'DSH_NODE_RCP'};
 | 
						|
	$properties{'DSH_NODE_RSH'} = $ENV{'DSH_NODE_RSH'}
 | 
						|
	  || $ENV{'DSH_REMOTE_SHELL'}
 | 
						|
	  || $ENV{'DSH_REMOTE_CMD'};
 | 
						|
	$properties{'DSH_OUTPUT'} = $ENV{'DSH_OUTPUT'};
 | 
						|
	$properties{'DSH_PATH'}   = $ENV{'DSH_PATH'};
 | 
						|
	$properties{'DSH_REPORT'} = $ENV{'DSH_REPORT'}
 | 
						|
	  || $ENV{'DSH_REPORTS_DIRECTORY'};
 | 
						|
	$properties{'DSH_SYNTAX'}  = $ENV{'DSH_SYNTAX'};
 | 
						|
	$properties{'DSH_TIMEOUT'} = $ENV{'DSH_TIMEOUT'};
 | 
						|
	$properties{'RSYNC_RSH'}   = $ENV{'RSYNC_RSH'};
 | 
						|
 | 
						|
	if($ENV{'DSH_ON_HMC'}){
 | 
						|
		$properties{'DSH_NODE_RCP'} = '/usr/hmcrbin/scp';
 | 
						|
		$properties{'DSH_NODE_RSH'} = '/usr/hmcrbin/ssh';
 | 
						|
	}
 | 
						|
	return \%properties;
 | 
						|
}
 | 
						|
 | 
						|
=head3
 | 
						|
        all_nodegroups
 | 
						|
 | 
						|
        Returns an array of all node group names in the DSH context
 | 
						|
 | 
						|
        Arguments:
 | 
						|
        	None
 | 
						|
 | 
						|
        Returns:
 | 
						|
        	An array of node group names
 | 
						|
                
 | 
						|
        Globals:
 | 
						|
        	$nodegroup_path
 | 
						|
    
 | 
						|
        Error:
 | 
						|
        	None
 | 
						|
    
 | 
						|
        Example:
 | 
						|
        	@nodegroups = DSH->all_nodegroups;
 | 
						|
 | 
						|
        Comments:
 | 
						|
 | 
						|
=cut
 | 
						|
 | 
						|
sub all_nodegroups {
 | 
						|
	my @nodegroups = ();
 | 
						|
 | 
						|
	if ($nodegroup_path) {
 | 
						|
		opendir( DIR, $nodegroup_path );
 | 
						|
 | 
						|
		while ( my $nodegroup = readdir(DIR) ) {
 | 
						|
			( $nodegroup !~ /^\./ ) && push @nodegroups, $nodegroup;
 | 
						|
		}
 | 
						|
 | 
						|
		closedir DIR;
 | 
						|
	}
 | 
						|
 | 
						|
	return @nodegroups;
 | 
						|
}
 | 
						|
 | 
						|
=head3
 | 
						|
        nodegroup_members
 | 
						|
 | 
						|
        Given a node group in the DSH context, this routine expands the
 | 
						|
        membership of the node 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 = DSH->nodegroup_members('MyGroup1');
 | 
						|
 | 
						|
        Comments:
 | 
						|
 | 
						|
=cut
 | 
						|
 | 
						|
sub nodegroup_members {
 | 
						|
	my ( $class, $nodegroup ) = @_;
 | 
						|
 | 
						|
	my %resolved_nodes   = ();
 | 
						|
	my %unresolved_nodes = ();
 | 
						|
 | 
						|
	my $nodes = DSH->read_target_file("$nodegroup_path/$nodegroup");
 | 
						|
 | 
						|
	!$nodes && return undef;
 | 
						|
 | 
						|
	my @members = ();
 | 
						|
 | 
						|
	foreach $node (@$nodes) {
 | 
						|
		if ( $node =~ /@/ ) {
 | 
						|
			xCAT::MsgUtils->message("E",
 | 
						|
				"$node is not a valid name for group $nodegroup");
 | 
						|
		}
 | 
						|
 | 
						|
		else {
 | 
						|
			push @members, $node;
 | 
						|
		}
 | 
						|
	}
 | 
						|
 | 
						|
	DSHContext->resolve_hostnames( \%resolved_nodes, \%unresolved_nodes,
 | 
						|
		@members );
 | 
						|
 | 
						|
	@members = keys(%resolved_nodes);
 | 
						|
	return \@members;
 | 
						|
}
 | 
						|
 | 
						|
=head3
 | 
						|
        all_nodes
 | 
						|
 | 
						|
        Returns an array of all node names in the DSH context
 | 
						|
 | 
						|
        Arguments:
 | 
						|
        	None
 | 
						|
 | 
						|
        Returns:
 | 
						|
        	An array of node names
 | 
						|
                
 | 
						|
        Globals:
 | 
						|
        	$nodegroup_path
 | 
						|
    
 | 
						|
        Error:
 | 
						|
        	None
 | 
						|
    
 | 
						|
        Example:
 | 
						|
        	@nodes = DSH->all_nodes;
 | 
						|
 | 
						|
        Comments:
 | 
						|
 | 
						|
=cut
 | 
						|
 | 
						|
sub all_nodes {
 | 
						|
	my $build_cache = undef;
 | 
						|
 | 
						|
	if ( -e "$ENV{'HOME'}/.dsh/$nodegroup_path/AllNodes" ) {
 | 
						|
		my @stat_path     = stat $nodegroup_path;
 | 
						|
		my @stat_allnodes =
 | 
						|
		  stat "$ENV{'HOME'}/.dsh/$nodegroup_path/AllNodes.dsh";
 | 
						|
 | 
						|
		if ( $stat_path[9] > $stat_allnodes[9] ) {
 | 
						|
			$build_cache = 1;
 | 
						|
		}
 | 
						|
 | 
						|
		else {
 | 
						|
			if ($nodegroup_path) {
 | 
						|
				opendir( DIR, $nodegroup_path );
 | 
						|
 | 
						|
				while ( my $nodegroup = readdir(DIR) ) {
 | 
						|
 | 
						|
					if ( $nodegroup !~ /^\./ ) {
 | 
						|
						my @stat_file = stat $nodegroup;
 | 
						|
						( $stat_file[9] > $stat_allnodes[9] )
 | 
						|
						  && ( $build_cache = 1 );
 | 
						|
					}
 | 
						|
 | 
						|
					last if $build_cache;
 | 
						|
				}
 | 
						|
 | 
						|
				closedir DIR;
 | 
						|
			}
 | 
						|
		}
 | 
						|
	}
 | 
						|
 | 
						|
	else {
 | 
						|
		$build_cache = 1;
 | 
						|
	}
 | 
						|
 | 
						|
	if ($build_cache) {
 | 
						|
		my @nodegroups = DSH->all_nodegroups;
 | 
						|
 | 
						|
		my @nodes = ();
 | 
						|
 | 
						|
		foreach $nodegroup (@nodegroups) {
 | 
						|
			push @nodes, @{ DSH->nodegroup_members($nodegroup) };
 | 
						|
		}
 | 
						|
 | 
						|
		if ( !( -d "$ENV{'HOME'}/.dsh/$nodegroup_path" ) ) {
 | 
						|
			eval { mkpath( "$ENV{'HOME'}/.dsh/$nodegroup_path") };
 | 
						|
			if ($@) {
 | 
						|
				 xCAT::MsgUtils->message(
 | 
						|
					"E",
 | 
						|
				" Cannot make directory: $ENV{'HOME'}/.dsh/$nodegroup_path\n");
 | 
						|
				return undef;
 | 
						|
			}
 | 
						|
		}
 | 
						|
 | 
						|
		DSH->write_target_file( "$ENV{'HOME'}/.dsh/$nodegroup_path/AllNodes",
 | 
						|
			@nodes );
 | 
						|
		return @nodes;
 | 
						|
	}
 | 
						|
 | 
						|
	else {
 | 
						|
		my $nodes =
 | 
						|
		  DSH->read_target_file("$ENV{'HOME'}/.dsh/$nodegroup_path/AllNodes");
 | 
						|
		return @$nodes;
 | 
						|
	}
 | 
						|
}
 | 
						|
 | 
						|
=head3
 | 
						|
        read_target_file
 | 
						|
 | 
						|
        Processes the given filename and stores all targets in the file in an
 | 
						|
        array
 | 
						|
 | 
						|
        Arguments:
 | 
						|
        	$filename - file to read target names from
 | 
						|
 | 
						|
        Returns:
 | 
						|
        	A reference to an array of target names
 | 
						|
                
 | 
						|
        Globals:
 | 
						|
        	None
 | 
						|
    
 | 
						|
        Error:
 | 
						|
        	None
 | 
						|
    
 | 
						|
        Example:
 | 
						|
        	DSH->read_target_file('/tmp/target_file');
 | 
						|
 | 
						|
        Comments:
 | 
						|
 | 
						|
=cut
 | 
						|
 | 
						|
sub read_target_file {
 | 
						|
	my ( $class, $filename ) = @_;
 | 
						|
 | 
						|
	my %targets = ();
 | 
						|
 | 
						|
	if ( open( FILE, $filename ) ) {
 | 
						|
 | 
						|
		while ( my $target = <FILE> ) {
 | 
						|
			$target =~ /^\s*#/     && next;
 | 
						|
			$target =~ /^\s*$/     && next;
 | 
						|
			$target =~ /;/         && next;
 | 
						|
			$target =~ /\S+\s+\S+/ && next;
 | 
						|
			$target =~ s/\s+$//;
 | 
						|
			chomp($target);
 | 
						|
			$targets{$target}++;
 | 
						|
		}
 | 
						|
 | 
						|
		close FILE;
 | 
						|
 | 
						|
		my @target_list = keys(%targets);
 | 
						|
		return \@target_list;
 | 
						|
	}
 | 
						|
 | 
						|
	else {
 | 
						|
		xCAT::MsgUtils->message( "E", "Cannot open file: $filename\n"); 
 | 
						|
		return undef;
 | 
						|
	}
 | 
						|
}
 | 
						|
 | 
						|
=head3
 | 
						|
        write_target_file
 | 
						|
 | 
						|
        Writes a list of supplied targets to a specified file.  Each target name
 | 
						|
        is written to one line
 | 
						|
 | 
						|
        Arguments:
 | 
						|
        	$filename - file to write target names
 | 
						|
        	@targets - array of target names to write
 | 
						|
 | 
						|
        Returns:
 | 
						|
        	None
 | 
						|
                
 | 
						|
        Globals:
 | 
						|
        	None
 | 
						|
    
 | 
						|
        Error:
 | 
						|
        	None
 | 
						|
    
 | 
						|
        Example:
 | 
						|
        	DSH->read_target_file('/tmp/target_file');
 | 
						|
 | 
						|
        Comments:
 | 
						|
 | 
						|
=cut
 | 
						|
 | 
						|
sub write_target_file {
 | 
						|
	my ( $class, $filename, @targets ) = @_;
 | 
						|
 | 
						|
	if ( open( FILE, ">$filename" ) ) {
 | 
						|
 | 
						|
		print FILE "#\n";
 | 
						|
		print FILE "# DSH Utilities Target File\n";
 | 
						|
		print FILE "#\n";
 | 
						|
 | 
						|
		foreach $target (@targets) {
 | 
						|
			print FILE "$target\n";
 | 
						|
		}
 | 
						|
 | 
						|
		close FILE;
 | 
						|
	}
 | 
						|
 | 
						|
	else {
 | 
						|
		xCAT::MsgUtils->message("E", "Error writing file $filename");
 | 
						|
	}
 | 
						|
}
 | 
						|
 | 
						|
sub query_node {
 | 
						|
	my ( $class, $node ) = @_;
 | 
						|
	my $res = 0;
 | 
						|
 | 
						|
	$~ = "NODES";
 | 
						|
	NetworkUtils->tryHost( $node, \$res );
 | 
						|
	if ($res) {
 | 
						|
		print("$node : Valid\n");
 | 
						|
	}
 | 
						|
	else {
 | 
						|
		print("$node : Invalid\n");
 | 
						|
	}
 | 
						|
 | 
						|
	format NODES =
 | 
						|
@<<<<<<<<<<<<<<<<<<<<<<<<<<<<<	@<<<<<<<<<<<<<<<<<
 | 
						|
$node, $status
 | 
						|
.
 | 
						|
 | 
						|
}
 | 
						|
 | 
						|
sub query_group {
 | 
						|
	my ( $class, $group ) = @_;
 | 
						|
	my @dsh_groups = all_nodegroups();
 | 
						|
 | 
						|
	$~ = "GROUPS";
 | 
						|
	if ( grep( /^$group$/, @dsh_groups ) ) {
 | 
						|
		print("$group : Valid\n");
 | 
						|
	}
 | 
						|
	else {
 | 
						|
		print("$group : Invalid\n");
 | 
						|
	}
 | 
						|
}
 | 
						|
 | 
						|
1;    #end
 |