xcat-core/xCAT-server/lib/xcat/dsh/Context/DSH.pm

465 lines
9.5 KiB
Perl
Raw Normal View History

#!/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