2
0
mirror of https://github.com/xcat2/xcat-core.git synced 2025-05-22 03:32:04 +00:00

466 lines
10 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{'DSH_VERIFY'} = $ENV{'DSH_VERIFY'};
$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