b841208705
add two checkpoints in InstUtils.pm and aixlitesetup if the entry in litefile table is one file and the entry in spot is one directory, or the entry in litefile table is one directory and the entry in spot is one file, there will be one error message to indicate the user to update the spot or the litefile table One loop is added to do the check in InstUtils.pm; in aixlitesetup script, two checkpoints are added to make sure the entries in litetree is comatible with the litefile entry Also add one checkpoint in aixinstall.pm to see the return code of dolitesetup git-svn-id: https://svn.code.sf.net/p/xcat/code/xcat-core/trunk@7864 8638fb3e-16cb-4fca-ae20-7b5d299a9bcd
1201 lines
31 KiB
Perl
1201 lines
31 KiB
Perl
#!/usr/bin/env perl
|
|
# IBM(c) 2007 EPL license http://www.eclipse.org/legal/epl-v10.html
|
|
package xCAT::InstUtils;
|
|
|
|
BEGIN
|
|
{
|
|
$::XCATROOT = $ENV{'XCATROOT'} ? $ENV{'XCATROOT'} : '/opt/xcat';
|
|
}
|
|
|
|
# if AIX - make sure we include perl 5.8.2 in INC path.
|
|
# Needed to find perl dependencies shipped in deps tarball.
|
|
if ($^O =~ /^aix/i)
|
|
{
|
|
use lib "/usr/opt/perl5/lib/5.8.2/aix-thread-multi";
|
|
use lib "/usr/opt/perl5/lib/5.8.2";
|
|
use lib "/usr/opt/perl5/lib/site_perl/5.8.2/aix-thread-multi";
|
|
use lib "/usr/opt/perl5/lib/site_perl/5.8.2";
|
|
}
|
|
|
|
use lib "$::XCATROOT/lib/perl";
|
|
require xCAT::Table;
|
|
use POSIX qw(ceil);
|
|
use Socket;
|
|
use Sys::Hostname;
|
|
use File::Basename;
|
|
use File::Path;
|
|
use strict;
|
|
require xCAT::Schema;
|
|
use xCAT::NetworkUtils;
|
|
|
|
#require Data::Dumper;
|
|
use Data::Dumper;
|
|
require xCAT::NodeRange;
|
|
require DBI;
|
|
|
|
our @ISA = qw(Exporter);
|
|
our @EXPORT_OK = qw(genpassword);
|
|
|
|
#-------------------------------------------------------------------------------
|
|
|
|
=head1 xCAT::InstUtils
|
|
|
|
=head2 Package Description
|
|
|
|
This program module file, is a set of utilities used by xCAT install
|
|
related commands.
|
|
|
|
=cut
|
|
|
|
#-------------------------------------------------------------
|
|
|
|
#----------------------------------------------------------------------------
|
|
|
|
=head3 getnimprime
|
|
|
|
Get the name of the primary AIX NIM master
|
|
|
|
Returns:
|
|
|
|
hostname - short hostname of primary NIM master
|
|
undef - could not find primary NIM master
|
|
Example:
|
|
|
|
my $nimprime = xCAT::InstUtils->getnimprime();
|
|
Comments:
|
|
|
|
=cut
|
|
|
|
#-----------------------------------------------------------------------------
|
|
|
|
sub getnimprime
|
|
{
|
|
|
|
# the primary NIM master is either specified in the site table
|
|
# or it is the xCAT management node.
|
|
|
|
my $nimprime = xCAT::Utils->get_site_Master();
|
|
my $sitetab = xCAT::Table->new('site');
|
|
(my $et) = $sitetab->getAttribs({key => "NIMprime"}, 'value');
|
|
if ($et and $et->{value})
|
|
{
|
|
$nimprime = $et->{value};
|
|
}
|
|
|
|
my $hostname;
|
|
if ($nimprime)
|
|
{
|
|
if (($nimprime =~ /\d+\.\d+\.\d+\.\d+/) || ($nimprime =~ /:/))
|
|
{
|
|
$hostname = xCAT::NetworkUtils->gethostname($nimprime);
|
|
}
|
|
else
|
|
{
|
|
$hostname = $nimprime;
|
|
}
|
|
|
|
my $shorthost;
|
|
($shorthost = $hostname) =~ s/\..*$//;
|
|
chomp $shorthost;
|
|
return $shorthost;
|
|
}
|
|
|
|
|
|
return undef;
|
|
}
|
|
|
|
#----------------------------------------------------------------------------
|
|
|
|
=head3 myxCATname
|
|
|
|
Gets the name of the node I'm running on - as known by xCAT
|
|
(Either the management node or a service node)
|
|
|
|
|
|
=cut
|
|
|
|
#-----------------------------------------------------------------------------
|
|
|
|
sub myxCATname
|
|
{
|
|
my ($junk, $name);
|
|
|
|
$name = hostname();
|
|
|
|
if (xCAT::Utils->isMN())
|
|
{
|
|
|
|
# read the site table, master attrib
|
|
my $hostname = xCAT::Utils->get_site_Master();
|
|
if (($hostname =~ /\d+\.\d+\.\d+\.\d+/) || ($hostname =~ /:/))
|
|
{
|
|
$name = xCAT::NetworkUtils->gethostname($hostname);
|
|
}
|
|
else
|
|
{
|
|
$name = $hostname;
|
|
}
|
|
|
|
}
|
|
elsif (xCAT::Utils->isServiceNode())
|
|
{
|
|
|
|
# the myxcatpost_<nodename> file should exist on all nodes!
|
|
my $catcmd = "cat /xcatpost/myxcatpost_* | grep '^NODE='";
|
|
my $output = xCAT::Utils->runcmd("$catcmd", -1);
|
|
if ($::RUNCMD_RC == 0)
|
|
{
|
|
($junk, $name) = split('=', $output);
|
|
}
|
|
}
|
|
|
|
my $shorthost;
|
|
($shorthost = $name) =~ s/\..*$//;
|
|
chomp $shorthost;
|
|
return $shorthost;
|
|
}
|
|
|
|
#----------------------------------------------------------------------------
|
|
|
|
=head3 is_me
|
|
|
|
returns 1 if the hostname is the node I am running on
|
|
|
|
Gets all the interfcaes defined on this node and sees if
|
|
any of them match the IP of the hostname passed in
|
|
|
|
Arguments:
|
|
none
|
|
Returns:
|
|
1 - this is the node I am running on
|
|
0 - this is not the node I am running on
|
|
Globals:
|
|
none
|
|
Error:
|
|
none
|
|
Example:
|
|
if (xCAT::InstUtils->is_me(&somehostname)) { blah; }
|
|
Comments:
|
|
none
|
|
|
|
=cut
|
|
|
|
#-----------------------------------------------------------------------------
|
|
|
|
sub is_me
|
|
{
|
|
my ($class, $name) = @_;
|
|
|
|
# convert to IP
|
|
my $nameIP = xCAT::NetworkUtils->getipaddr($name);
|
|
chomp $nameIP;
|
|
|
|
# split into octets
|
|
#my ($b1, $b2, $b3, $b4) = split /\./, $nameIP;
|
|
|
|
# get all the possible IPs for the node I'm running on
|
|
my $ifcmd = "ifconfig -a | grep 'inet'";
|
|
my $result = xCAT::Utils->runcmd($ifcmd, 0, 1);
|
|
if ($::RUNCMD_RC != 0)
|
|
{
|
|
my $rsp;
|
|
# push @{$rsp->{data}}, "Could not run $ifcmd.\n";
|
|
# xCAT::MsgUtils->message("E", $rsp, $callback);
|
|
return 0;
|
|
}
|
|
|
|
foreach my $int (@$result)
|
|
{
|
|
my ($inet, $myIP, $str) = split(" ", $int);
|
|
chomp $myIP;
|
|
$myIP =~ s/\/.*//; # ipv6 address 4000::99/64
|
|
$myIP =~ s/\%.*//; # ipv6 address ::1%1/128
|
|
|
|
if ($myIP eq $nameIP)
|
|
{
|
|
return 1;
|
|
}
|
|
}
|
|
return 0;
|
|
}
|
|
|
|
#----------------------------------------------------------------------------
|
|
|
|
=head3 get_nim_attrs
|
|
|
|
Use the lsnim command to get the NIM attributes and values of
|
|
a resource.
|
|
|
|
Arguments:
|
|
Returns:
|
|
hash ref - OK
|
|
undef - error
|
|
Globals:
|
|
|
|
Error:
|
|
|
|
Example:
|
|
|
|
$attrvals = xCAT::InstUtils->
|
|
get_nim_attrs($res, $callback, $nimprime, $subreq);
|
|
|
|
|
|
Comments:
|
|
=cut
|
|
|
|
#-----------------------------------------------------------------------------
|
|
sub get_nim_attrs
|
|
{
|
|
my $class = shift;
|
|
my $resname = shift;
|
|
my $callback = shift;
|
|
my $target = shift;
|
|
my $sub_req = shift;
|
|
|
|
my %attrvals = undef;
|
|
|
|
if (!$target)
|
|
{
|
|
$target = xCAT::InstUtils->getnimprime();
|
|
}
|
|
chomp $target;
|
|
|
|
my $cmd = "/usr/sbin/lsnim -l $resname 2>/dev/null";
|
|
|
|
my @nout = xCAT::InstUtils->xcmd($callback, $sub_req, "xdsh", $target, $cmd, 1);
|
|
if ($::RUNCMD_RC != 0)
|
|
{
|
|
my $rsp;
|
|
push @{$rsp->{data}}, "Could not run lsnim command: \'$cmd\'.\n";
|
|
xCAT::MsgUtils->message("E", $rsp, $callback);
|
|
return undef;
|
|
}
|
|
|
|
foreach my $line (@nout) {
|
|
|
|
chomp $line;
|
|
my $junk;
|
|
my $attrval;
|
|
if ($line =~ /.*$target:(.*)/) {
|
|
($junk, $attrval) = split(/:/, $line);
|
|
} else {
|
|
$attrval = $line;
|
|
}
|
|
|
|
if ($attrval =~ /=/) {
|
|
|
|
my ($attr, $val) = $attrval =~ /^\s*(\S+?)\s*=\s*(\S*.*)$/;
|
|
|
|
|
|
#ndebug
|
|
#my $rsp;
|
|
#push @{$rsp->{data}}, "attr= $attr, val= $val.\n";
|
|
#xCAT::MsgUtils->message("I", $rsp, $callback);
|
|
|
|
|
|
if ($attr && $val) {
|
|
# $attrvals{$resname}{$attr} = $val;
|
|
$attrvals{$attr} = $val;
|
|
}
|
|
}
|
|
}
|
|
|
|
if (%attrvals) {
|
|
return \%attrvals;
|
|
} else {
|
|
return undef;
|
|
}
|
|
}
|
|
|
|
#----------------------------------------------------------------------------
|
|
|
|
=head3 get_nim_attr_val
|
|
|
|
Use the lsnim command to find the value of a resource attribute.
|
|
|
|
Arguments:
|
|
Returns:
|
|
0 - OK
|
|
1 - error
|
|
Globals:
|
|
|
|
Error:
|
|
|
|
Example:
|
|
|
|
xCAT::InstUtils->get_nim_attr_val
|
|
|
|
Comments:
|
|
=cut
|
|
|
|
#-----------------------------------------------------------------------------
|
|
sub get_nim_attr_val
|
|
{
|
|
my $class = shift;
|
|
my $resname = shift;
|
|
my $attrname = shift;
|
|
my $callback = shift;
|
|
my $target = shift;
|
|
my $sub_req = shift;
|
|
|
|
if (!$target)
|
|
{
|
|
$target = xCAT::InstUtils->getnimprime();
|
|
}
|
|
chomp $target;
|
|
|
|
my $cmd = "/usr/sbin/lsnim -a $attrname -Z $resname 2>/dev/null";
|
|
my $nout =
|
|
xCAT::InstUtils->xcmd($callback, $sub_req, "xdsh", $target, $cmd, 0);
|
|
if ($::RUNCMD_RC != 0)
|
|
{
|
|
my $rsp;
|
|
push @{$rsp->{data}}, "Could not run lsnim command: \'$cmd\'.\n";
|
|
xCAT::MsgUtils->message("E", $rsp, $callback);
|
|
return undef;
|
|
}
|
|
|
|
# The command output may have the xdsh prefix "target:"
|
|
#my ($junk, $junk, $junk, $loc) = split(/:/, $nout);
|
|
#chomp $loc;
|
|
my $loc;
|
|
if ($nout =~ /.*$resname:(.*):$/)
|
|
{
|
|
$loc = $1;
|
|
}
|
|
|
|
return $loc;
|
|
}
|
|
|
|
#-------------------------------------------------------------------------------
|
|
|
|
=head3 xcmd
|
|
Run command either locally or on a remote system.
|
|
Calls either runcmd or runxcmd and does either xdcp or xdsh.
|
|
|
|
Arguments:
|
|
|
|
Returns:
|
|
Output of runcmd or runxcmd or undef.
|
|
|
|
Comments:
|
|
|
|
ex. xCAT::InstUtils->xcmd($callback, $sub_req, "xdcp", $nimprime, $doarray, $cmd);
|
|
|
|
=cut
|
|
|
|
#-------------------------------------------------------------------------------
|
|
sub xcmd
|
|
{
|
|
my $class = shift;
|
|
my $callback = shift;
|
|
my $sub_req = shift;
|
|
my $xdcmd = shift; # xdcp or xdsh
|
|
my $target = shift; # the node to run it on
|
|
my $cmd = shift; # the actual cmd to run
|
|
my $doarray = shift; # should the return be a string or array ptr?
|
|
|
|
my $returnformat = 0; # default is to return string
|
|
my $exitcode = -1; # don't display error
|
|
if ($doarray)
|
|
{
|
|
$returnformat = $doarray;
|
|
}
|
|
|
|
# runxcmd uses global
|
|
$::CALLBACK = $callback;
|
|
|
|
my $output;
|
|
if (!ref($target))
|
|
{ # must be node name
|
|
if (xCAT::InstUtils->is_me($target))
|
|
{
|
|
$output = xCAT::Utils->runcmd($cmd, $exitcode, $returnformat);
|
|
}
|
|
else
|
|
{
|
|
my @snodes;
|
|
push(@snodes, $target);
|
|
$output =
|
|
xCAT::Utils->runxcmd(
|
|
{
|
|
command => [$xdcmd],
|
|
node => \@snodes,
|
|
arg => ["-s", $cmd]
|
|
},
|
|
$sub_req,
|
|
$exitcode,
|
|
$returnformat
|
|
);
|
|
}
|
|
}
|
|
else
|
|
{
|
|
|
|
# it is an array ref
|
|
my @snodes;
|
|
@snodes = @{$target};
|
|
$output =
|
|
xCAT::Utils->runxcmd(
|
|
{
|
|
command => [$xdcmd],
|
|
node => \@snodes,
|
|
arg => ["-s", $cmd]
|
|
},
|
|
$sub_req,
|
|
$exitcode,
|
|
$returnformat
|
|
);
|
|
}
|
|
if ($returnformat == 1)
|
|
{
|
|
return @$output;
|
|
}
|
|
else
|
|
{
|
|
return $output;
|
|
}
|
|
|
|
return undef;
|
|
}
|
|
|
|
#----------------------------------------------------------------------------
|
|
|
|
=head3 readBNDfile
|
|
|
|
Get the contents of a NIM installp_bundle file based on the name
|
|
of the NIM resource.
|
|
|
|
=cut
|
|
|
|
#-----------------------------------------------------------------------------
|
|
sub readBNDfile
|
|
{
|
|
|
|
my ($class, $callback, $BNDname, $nimprime, $sub_req) = @_;
|
|
|
|
my $junk;
|
|
my @pkglist, my $pkgname;
|
|
|
|
# get the location of the file from the NIM resource definition
|
|
my $bnd_file_name =
|
|
xCAT::InstUtils->get_nim_attr_val($BNDname, 'location', $callback,
|
|
$nimprime, $sub_req);
|
|
|
|
# The boundle file may be on nimprime
|
|
my $ccmd = qq~cat $bnd_file_name~;
|
|
my $output=xCAT::InstUtils->xcmd($callback, $sub_req, "xdsh", $nimprime, $ccmd, 0);
|
|
if ($::RUNCMD_RC != 0) {
|
|
my $rsp;
|
|
push @{$rsp->{data}}, "Command: $ccmd failed.";
|
|
xCAT::MsgUtils->message("E", $rsp, $callback);
|
|
}
|
|
|
|
# get the names of the packages
|
|
#$output =~ s/$nimprime:\s+//g;
|
|
foreach my $line (split(/\n/, $output))
|
|
{
|
|
#May include xdsh prefix $nimprime:
|
|
$line =~ s/$nimprime:\s+//;
|
|
# skip blank and comment lines
|
|
next if ($line =~ /^\s*$/ || $line =~ /^\s*#/);
|
|
push(@pkglist, $line);
|
|
}
|
|
|
|
return (0, \@pkglist, $bnd_file_name);
|
|
}
|
|
|
|
#----------------------------------------------------------------------------
|
|
|
|
=head3 restore_request
|
|
|
|
Restores an xcatd request from a remote management server
|
|
into the proper format by removing arrays that were added by
|
|
XML and removing tags that were added to numeric hash keys.
|
|
|
|
Arguments:
|
|
Returns:
|
|
ptr to hash
|
|
undef
|
|
Globals:
|
|
Example:
|
|
Comments:
|
|
|
|
=cut
|
|
|
|
#-----------------------------------------------------------------------------
|
|
sub restore_request
|
|
{
|
|
my $class = shift;
|
|
my $in_struct = shift;
|
|
my $callback = shift;
|
|
|
|
my $out_struct;
|
|
|
|
if (ref($in_struct) eq "ARRAY")
|
|
{
|
|
|
|
# flatten the array it it has only one element
|
|
# otherwise leave it alone
|
|
if (scalar(@$in_struct) == 1)
|
|
{
|
|
return (xCAT::InstUtils->restore_request($in_struct->[0]));
|
|
}
|
|
else
|
|
{
|
|
return ($in_struct);
|
|
}
|
|
}
|
|
|
|
if (ref($in_struct) eq "HASH")
|
|
{
|
|
foreach my $struct_key (keys %{$in_struct})
|
|
{
|
|
my $stripped_key = $struct_key;
|
|
$stripped_key =~ s/^xxXCATxx(\d)/$1/;
|
|
|
|
# do not flatten the arg or node arrays
|
|
if (($stripped_key =~ /^arg$/) || ($stripped_key =~ /^node$/))
|
|
{
|
|
$out_struct->{$stripped_key} = $in_struct->{$struct_key};
|
|
}
|
|
else
|
|
{
|
|
$out_struct->{$stripped_key} =
|
|
xCAT::InstUtils->restore_request($in_struct->{$struct_key});
|
|
}
|
|
}
|
|
return $out_struct;
|
|
}
|
|
|
|
if ((ref($in_struct) eq "SCALAR") || (ref(\$in_struct) eq "SCALAR"))
|
|
{
|
|
return ($in_struct);
|
|
}
|
|
|
|
print "Unsupported data reference in restore_request().\n";
|
|
return undef;
|
|
}
|
|
|
|
#----------------------------------------------------------------------------
|
|
|
|
=head3 taghash
|
|
|
|
Add a non-numeric tag to any hash keys that are numeric.
|
|
|
|
Arguments:
|
|
Returns:
|
|
0 - OK
|
|
1 - error
|
|
Globals:
|
|
Example:
|
|
Comments:
|
|
XML will choke on numeric values. This happens when including
|
|
a hash in a request to a remote service node.
|
|
|
|
=cut
|
|
|
|
#-----------------------------------------------------------------------
|
|
sub taghash
|
|
{
|
|
my ($class, $hash) = @_;
|
|
|
|
if (ref($hash) eq "HASH")
|
|
{
|
|
foreach my $k (keys %{$hash})
|
|
{
|
|
if ($k =~ /^(\d)./)
|
|
{
|
|
my $tagged_key = "xxXCATxx" . $k;
|
|
$hash->{$tagged_key} = $hash->{$k};
|
|
delete($hash->{$k});
|
|
}
|
|
}
|
|
return 0;
|
|
}
|
|
else
|
|
{
|
|
return 1;
|
|
}
|
|
}
|
|
|
|
#-------------------------------------------------------------------------------
|
|
|
|
=head3 getOSnodes
|
|
Split a noderange into arrays of AIX and Linux nodes.
|
|
|
|
Arguments:
|
|
\@noderange - reference to onde list array
|
|
Returns:
|
|
$rc -
|
|
1 - yes, all the nodes are AIX
|
|
0 - no, at least one node is not AIX
|
|
\@aixnodes - ref to array of AIX nodes
|
|
\@linuxnodes - ref to array of Linux nodes
|
|
|
|
|
|
Comments:
|
|
Based on "os" attr of node definition. If attr is not set,
|
|
defaults to OS of current system.
|
|
|
|
Example:
|
|
my ($rc, $AIXnodes, $Linuxnodes)
|
|
= xCAT::InstUtils->getOSnodes(\@noderange)
|
|
|
|
=cut
|
|
|
|
#-------------------------------------------------------------------------------
|
|
sub getOSnodes
|
|
{
|
|
my ($class, $nodes) = @_;
|
|
|
|
my @nodelist = @$nodes;
|
|
my $rc = 1; # all AIX nodes
|
|
my @aixnodes;
|
|
my @linuxnodes;
|
|
|
|
my $nodetab = xCAT::Table->new('nodetype');
|
|
my $os = $nodetab->getNodesAttribs(\@nodelist, ['node', 'os']);
|
|
foreach my $n (@nodelist)
|
|
{
|
|
my $osname;
|
|
if (defined($os->{$n}->[0]->{os})) {
|
|
$osname = $os->{$n}->[0]->{os};
|
|
} else {
|
|
$osname = $^O;
|
|
}
|
|
if (($osname ne "AIX") && ($osname ne "aix"))
|
|
{
|
|
push(@linuxnodes, $n);
|
|
$rc = 0;
|
|
}
|
|
else
|
|
{
|
|
push(@aixnodes, $n);
|
|
}
|
|
}
|
|
$nodetab->close;
|
|
|
|
return ($rc, \@aixnodes, \@linuxnodes);
|
|
}
|
|
|
|
#-------------------------------------------------------------------------------
|
|
|
|
=head3 get_server_nodes
|
|
|
|
Determines the server node names as known by a lists of nodes.
|
|
|
|
Arguments:
|
|
A list of node names.
|
|
|
|
Returns:
|
|
A hash ref of arrays, the key is the service node pointing to
|
|
an array of nodes that are serviced by that service node
|
|
|
|
Example
|
|
my %servernodes = &get_server_nodes($callback, \@$AIXnodes);
|
|
|
|
Comments:
|
|
- Code runs on MN or SNs
|
|
|
|
=cut
|
|
|
|
#-------------------------------------------------------------------------------
|
|
sub get_server_nodes
|
|
{
|
|
my $class = shift;
|
|
my $callback = shift;
|
|
my $nodes = shift;
|
|
|
|
my @nodelist;
|
|
if ($nodes)
|
|
{
|
|
@nodelist = @$nodes;
|
|
}
|
|
|
|
#
|
|
# get the server name for each node - as known by node
|
|
#
|
|
my $noderestab = xCAT::Table->new('noderes');
|
|
my $xcatmasters = $noderestab->getNodesAttribs(\@nodelist, ['node', 'xcatmaster']);
|
|
$noderestab->close;
|
|
|
|
my %servernodes;
|
|
foreach my $node (@nodelist)
|
|
{
|
|
my $serv;
|
|
if ($xcatmasters->{$node}->[0]->{xcatmaster})
|
|
{
|
|
# get ip of node xcatmaster attribute
|
|
my $xcatmaster = $xcatmasters->{$node}->[0]->{xcatmaster};
|
|
$serv = xCAT::NetworkUtils->getipaddr($xcatmaster);
|
|
}
|
|
else
|
|
{
|
|
# get ip facing node
|
|
$serv = xCAT::Utils->my_ip_facing($node);
|
|
}
|
|
chomp $serv;
|
|
|
|
if (xCAT::Utils->validate_ip($serv)) {
|
|
push (@{$servernodes{$serv}}, $node);
|
|
}
|
|
}
|
|
|
|
return \%servernodes;
|
|
}
|
|
|
|
#----------------------------------------------------------------------------
|
|
|
|
=head3 dolitesetup
|
|
|
|
Update a spot with the statelite configuration
|
|
|
|
Arguments:
|
|
Returns:
|
|
0 - OK
|
|
1 - error
|
|
Globals:
|
|
Example:
|
|
Comments:
|
|
|
|
=cut
|
|
|
|
#-----------------------------------------------------------------------
|
|
sub dolitesetup
|
|
{
|
|
my $class = shift;
|
|
my $imagename = shift;
|
|
my $imagehash = shift;
|
|
my $nodes = shift;
|
|
my $callback = shift;
|
|
my $subreq = shift;
|
|
my @litefiles; # lists of entries in the litefile table
|
|
|
|
my %imghash;
|
|
if ($imagehash)
|
|
{
|
|
%imghash = %$imagehash;
|
|
}
|
|
|
|
my @nodelist;
|
|
my @nodel;
|
|
my @nl;
|
|
if ($nodes) {
|
|
@nl = @$nodes;
|
|
foreach my $n (@nl) {
|
|
push(@nodel, xCAT::NodeRange::noderange($n));
|
|
}
|
|
}
|
|
|
|
#
|
|
# Need to set the "provmethod" attr of the node defs or the litetree
|
|
# cmd wil not get the info we need
|
|
#
|
|
|
|
my %nodeattrs;
|
|
foreach my $node (@nodel)
|
|
{
|
|
chomp $node;
|
|
$nodeattrs{$node}{objtype} = 'node';
|
|
$nodeattrs{$node}{os} = "AIX";
|
|
$nodeattrs{$node}{profile} = $imagename;
|
|
$nodeattrs{$node}{provmethod} = $imagename;
|
|
}
|
|
if (xCAT::DBobjUtils->setobjdefs(\%nodeattrs) != 0)
|
|
{
|
|
my $rsp;
|
|
push @{$rsp->{data}}, "Could not set the \'provmethod\' attribute for nodes.\n";
|
|
xCAT::MsgUtils->message("W", $rsp, $::callback);
|
|
}
|
|
|
|
# the node list is always "all" nodes. There is only one version of the
|
|
# statelite, litefile and litetree files in an image and these files
|
|
# must always contain all the info from the corresponding database
|
|
# table.
|
|
my @nlist = ('all');
|
|
foreach my $n (@nlist) {
|
|
push(@nodelist, xCAT::NodeRange::noderange($n));
|
|
}
|
|
my $noderange = join(',',@nodelist);
|
|
|
|
# get spot inst_root loc
|
|
my $spotloc = xCAT::InstUtils->get_nim_attr_val($imghash{$imagename}{spot}, 'location', $callback, "", $subreq);
|
|
|
|
my $instrootloc = $spotloc . "/lpp/bos/inst_root";
|
|
|
|
# get the statelite info - put each table into it's own file
|
|
my $statelitetab = xCAT::Table->new('statelite', -create=>1);
|
|
my $litefiletab = xCAT::Table->new('litefile');
|
|
my $litetreetab = xCAT::Table->new('litetree');
|
|
|
|
# these will wind up in the root dir on the node ("/")
|
|
my $statelitetable = "$instrootloc/statelite.table";
|
|
my $litefiletable = "$instrootloc/litefile.table";
|
|
my $litetreetable = "$instrootloc/litetree.table";
|
|
|
|
# get rid of any old files
|
|
if (-e $statelitetable) {
|
|
my $rc = xCAT::Utils->runcmd("rm $statelitetable", -1);
|
|
if ($::RUNCMD_RC != 0)
|
|
{
|
|
my $rsp;
|
|
push @{$rsp->{data}}, "Could not remove existing $statelitetable file.";
|
|
xCAT::MsgUtils->message("E", $rsp, $callback);
|
|
return 1;
|
|
}
|
|
}
|
|
|
|
if (-e $litefiletable) {
|
|
my $rc = xCAT::Utils->runcmd("rm $litefiletable", -1);
|
|
if ($::RUNCMD_RC != 0)
|
|
{
|
|
my $rsp;
|
|
push @{$rsp->{data}}, "Could not remove existing $litefiletable file.";
|
|
xCAT::MsgUtils->message("E", $rsp, $callback);
|
|
return 1;
|
|
}
|
|
}
|
|
|
|
if (-e $litetreetab) {
|
|
my $rc = xCAT::Utils->runcmd("rm $litetreetab", -1);
|
|
if ($::RUNCMD_RC != 0)
|
|
{
|
|
my $rsp;
|
|
push @{$rsp->{data}}, "Could not remove existing $litetreetab file.";
|
|
xCAT::MsgUtils->message("E", $rsp, $callback);
|
|
return 1;
|
|
}
|
|
}
|
|
|
|
#
|
|
# create files for each statelite table. add them to the SPOT.
|
|
# use the "|" as a separator, remove all blanks from the entries.
|
|
# put them in $instrootloc location. they will be available as soon
|
|
# as the root dir is mounted during the boot process.
|
|
|
|
my $foundstatelite=0;
|
|
unless (open(STATELITE, ">$statelitetable"))
|
|
{
|
|
my $rsp;
|
|
push @{$rsp->{data}}, "Could not open $statelitetable.\n";
|
|
xCAT::MsgUtils->message("E", $rsp, $callback);
|
|
return 1;
|
|
}
|
|
|
|
my $stateHash = $statelitetab->getNodesAttribs(\@nodelist, ['statemnt']);
|
|
foreach my $node (@nodelist) {
|
|
|
|
# process statelite entry
|
|
# add line to file for each node
|
|
# note: if statement is xcatmn:/nodedata
|
|
# /nodedata is mounted to /.statelite/persistent
|
|
# then - on node - a nodename subdir is created
|
|
|
|
my $statemnt="";
|
|
if (exists($stateHash->{$node})) {
|
|
$statemnt = $stateHash->{$node}->[0]->{statemnt};
|
|
my ($server, $dir) = split(/:/, $statemnt);
|
|
|
|
#if server is blank, then its the directory
|
|
unless($dir) {
|
|
$dir = $server;
|
|
$server = '';
|
|
}
|
|
|
|
$dir = xCAT::SvrUtils->subVars($dir, $node, 'dir', $callback);
|
|
$dir =~ s/\/\//\//g;
|
|
|
|
if($server) {
|
|
$server = xCAT::SvrUtils->subVars($server, $node, 'server', $callback);
|
|
$server =~ s/\///g; # remove "/" - bug in subVars??
|
|
my $serverIP = xCAT::NetworkUtils->getipaddr($server);
|
|
$statemnt = $serverIP . "|" . $dir;
|
|
} else {
|
|
$statemnt = $dir;
|
|
}
|
|
}
|
|
|
|
my $entry = qq~$node|$statemnt~;
|
|
$entry =~ s/\s*//g; #remove blanks
|
|
|
|
if ($statemnt) {
|
|
print STATELITE $entry . "\n";
|
|
}
|
|
}
|
|
close(STATELITE);
|
|
|
|
unless (open(LITEFILE, ">$litefiletable"))
|
|
{
|
|
my $rsp;
|
|
push @{$rsp->{data}}, "Could not open $litefiletable.\n";
|
|
xCAT::MsgUtils->message("E", $rsp, $callback);
|
|
return 1;
|
|
}
|
|
|
|
my @filelist = xCAT::Utils->runcmd("/opt/xcat/bin/litefile $noderange", -1);
|
|
foreach my $l (@filelist) {
|
|
$l =~ s/://g; # remove ":"'s
|
|
$l =~ s/\s+/|/g; # change separator to "|"
|
|
print LITEFILE $l . "\n";
|
|
push (@litefiles, $l);
|
|
$foundstatelite++;
|
|
}
|
|
close(LITEFILE);
|
|
|
|
unless (open(LITETREE, ">$litetreetable"))
|
|
{
|
|
my $rsp;
|
|
push @{$rsp->{data}}, "Could not open $litetreetable.\n";
|
|
xCAT::MsgUtils->message("E", $rsp, $callback);
|
|
return 1;
|
|
}
|
|
my @treelist = xCAT::Utils->runcmd("/opt/xcat/bin/litetree $noderange", -1);
|
|
foreach my $l (@treelist) {
|
|
|
|
my ($p, $serv, $dir) = split (/:/, $l);
|
|
$p =~ s/\s*//g;
|
|
$serv =~ s/\s*//g;
|
|
$dir =~ s/\s*//g;
|
|
my $serverIP = xCAT::NetworkUtils->getipaddr($serv);
|
|
my $entry = "$p|$serverIP|$dir";
|
|
print LITETREE $entry . "\n";
|
|
$foundstatelite++;
|
|
}
|
|
close(LITETREE);
|
|
|
|
# if there is no statelite info then just return
|
|
if (!$foundstatelite) {
|
|
return 1;
|
|
}
|
|
|
|
#
|
|
# ok - do more statelite setup
|
|
#
|
|
|
|
# create some local directories in the SPOT
|
|
# create .default, .statelite,
|
|
if ( ! -d "$instrootloc/.default" ) {
|
|
my $mcmd = qq~/bin/mkdir -m 644 -p $instrootloc/.default ~;
|
|
my $output = xCAT::Utils->runcmd("$mcmd", -1);
|
|
if ($::RUNCMD_RC != 0)
|
|
{
|
|
my $rsp;
|
|
push @{$rsp->{data}}, "Could not create $instrootloc/.default.\n";
|
|
xCAT::MsgUtils->message("E", $rsp, $callback);
|
|
return 1;
|
|
}
|
|
}
|
|
|
|
if ( ! -d "$instrootloc/.statelite" ) {
|
|
my $mcmd = qq~/bin/mkdir -m 644 -p $instrootloc/.statelite ~;
|
|
my $output = xCAT::Utils->runcmd("$mcmd", -1);
|
|
if ($::RUNCMD_RC != 0)
|
|
{
|
|
my $rsp;
|
|
push @{$rsp->{data}}, "Could not create $instrootloc/.statelite.\n";
|
|
xCAT::MsgUtils->message("E", $rsp, $callback);
|
|
return 1;
|
|
}
|
|
}
|
|
|
|
# populate the .defaults dir with files and dirs from the image - if any
|
|
my $default="$instrootloc/.default";
|
|
|
|
# read the litefile and try to copy into $default
|
|
# everything in the litefile command output should be processed
|
|
|
|
foreach my $line (@litefiles) {
|
|
# $file could be full path file name or dir name
|
|
# ex. /foo/bar/ or /etc/lppcfg
|
|
my ($node, $option, $file) = split (/\|/, $line);
|
|
|
|
# ex. .../inst_root/foo/bar/ or .../inst_root/etc/lppcfg
|
|
my $instrootfile = $instrootloc . $file;
|
|
|
|
# there's one scenario to be handled firstly
|
|
# in litefile table, there's one entry: /path/to/file, which is one file
|
|
# however, there's already one directory named "/path/to/file/"
|
|
#
|
|
# Or:
|
|
# the entry in litefile is "/path/to/file/", which is one directory
|
|
# however, there's already one file named "/path/to/file"
|
|
#
|
|
# in these cases,
|
|
# need to indicate the user there's already one existing file/directory in the spot
|
|
# then, exit
|
|
|
|
if ($file =~ m/\/$/ and -f $instrootfile) {
|
|
my $rsp;
|
|
push @{$rsp->{data}}, qq{there is already one file named "$file", but the entry in litefile table is set to one directory, please check it};
|
|
xCAT::MsgUtils->message("E", $rsp, $callback);
|
|
return 1;
|
|
}
|
|
if ($file !~ m/\/$/ and -d $instrootfile) {
|
|
my $rsp;
|
|
push @{$rsp->{data}}, qq{there is already one directory named "$file", but the entry in litefile table is set to one file, please check it};
|
|
xCAT::MsgUtils->message("E", $rsp, $callback);
|
|
return 1;
|
|
}
|
|
}
|
|
|
|
|
|
my @copiedfiles;
|
|
foreach my $line (@litefiles) {
|
|
|
|
# $file could be full path file name or dir name
|
|
# ex. /foo/bar/ or /etc/lppcfg
|
|
my ($node, $option, $file) = split (/\|/, $line);
|
|
|
|
# ex. /foo or /etc
|
|
my $filedir = dirname($file);
|
|
|
|
# ex. .../inst_root/foo/bar/ or .../inst_root/etc/lppcfg
|
|
my $instrootfile = $instrootloc . $file;
|
|
|
|
my $cpcmd;
|
|
my $mkdircmd;
|
|
my $output;
|
|
|
|
if (!grep (/^$instrootfile$/, @copiedfiles)) {
|
|
# don't copy same file twice
|
|
push (@copiedfiles, $instrootfile);
|
|
|
|
if (-e $instrootfile) {
|
|
|
|
if (-d $instrootfile) {
|
|
# it's a dir so copy everything in it
|
|
# ex. mkdir -p ../inst_root/.default/foo/bar
|
|
# ex. cp -r .../inst_root/foo/bar/ ../inst_root/.default/foo/bar
|
|
|
|
if ( ! -e "$default$file" ) { # do mkdir
|
|
$mkdircmd = qq~mkdir -p $default$file 2>/dev/null~;
|
|
$output = xCAT::Utils->runcmd("$mkdircmd", -1);
|
|
if ($::RUNCMD_RC != 0) {
|
|
my $rsp;
|
|
push @{$rsp->{data}}, "Could not copy create $default$file.";
|
|
if ($::VERBOSE)
|
|
{
|
|
push @{$rsp->{data}}, "$output\n";
|
|
}
|
|
xCAT::MsgUtils->message("E", $rsp, $callback);
|
|
}
|
|
}
|
|
|
|
# ok - do copy
|
|
$cpcmd = qq~cp -p -r $instrootfile* $default$file 2>/dev/null~;
|
|
$output = xCAT::Utils->runcmd("$cpcmd", -1);
|
|
|
|
} else {
|
|
# copy file
|
|
# ex. mkdir -p ../inst_root/.default/etc
|
|
# ex. cp .../inst_root/etc/lppcfg ../inst_root/.default/etc
|
|
$cpcmd = qq~mkdir -p $default$filedir; cp -p $instrootfile $default$filedir 2>/dev/null~;
|
|
}
|
|
} else {
|
|
|
|
# could not find file or dir in ../inst_root (spot dir)
|
|
# so create empty file or dir
|
|
my $mkcmd;
|
|
|
|
# check if it's a dir
|
|
if(grep /\/$/, $file) {
|
|
# create dir in .default
|
|
if ( ! -d "$default$file" ) {
|
|
$mkcmd = qq~mkdir -p $default$file~;
|
|
$output = xCAT::Utils->runcmd("$mkcmd", -1);
|
|
if ($::RUNCMD_RC != 0)
|
|
{
|
|
my $rsp;
|
|
push @{$rsp->{data}}, "Could not create $default$file.\n";
|
|
if ($::VERBOSE)
|
|
{
|
|
push @{$rsp->{data}}, "$output\n";
|
|
}
|
|
}
|
|
}
|
|
} else {
|
|
# create dir and touch file in .default
|
|
my $dir = dirname($file);
|
|
if ( ! -d "$default$dir" ) {
|
|
$mkcmd = qq~mkdir -p $default$dir~;
|
|
$output = xCAT::Utils->runcmd("$mkcmd", -1);
|
|
if ($::RUNCMD_RC != 0)
|
|
{
|
|
my $rsp;
|
|
push @{$rsp->{data}}, "Could not create $default$dir.";
|
|
if ($::VERBOSE)
|
|
{
|
|
push @{$rsp->{data}}, "$output\n";
|
|
}
|
|
}
|
|
}
|
|
|
|
# touch the file
|
|
my $tcmd = qq~touch $default$file~;
|
|
$output = xCAT::Utils->runcmd("$tcmd", -1);
|
|
if ($::RUNCMD_RC != 0)
|
|
{
|
|
my $rsp;
|
|
push @{$rsp->{data}}, "Could not create $default$file.\n";
|
|
if ($::VERBOSE)
|
|
{
|
|
push @{$rsp->{data}}, "$output\n";
|
|
}
|
|
xCAT::MsgUtils->message("E", $rsp, $callback);
|
|
}
|
|
}
|
|
} # end - if not exist in spot
|
|
} # end - if not already copied
|
|
} # end - for each line in litefile
|
|
|
|
# add aixlitesetup to ..inst_root/aixlitesetup
|
|
# this will wind up in the root dir on the node ("/")
|
|
my $install_dir = xCAT::Utils->getInstallDir();
|
|
my $cpcmd = "/bin/cp $install_dir/postscripts/aixlitesetup $instrootloc/aixlitesetup; chmod +x $instrootloc/aixlitesetup";
|
|
|
|
my $out = xCAT::Utils->runcmd("$cpcmd", -1);
|
|
if ($::RUNCMD_RC != 0)
|
|
{
|
|
my $rsp;
|
|
push @{$rsp->{data}}, "Could not copy aixlitesetup.";
|
|
xCAT::MsgUtils->message("E", $rsp, $callback);
|
|
return 1;
|
|
}
|
|
|
|
# if this is an update then we need to copy the new files to
|
|
# the shared_root location
|
|
# ??? - maybe we should try this all the time????
|
|
if (1) {
|
|
# if we have a shared_root resource
|
|
if ($imghash{$imagename}{shared_root} ) {
|
|
my $nimprime = xCAT::InstUtils->getnimprime();
|
|
chomp $nimprime;
|
|
# get the location of the shared_root directory
|
|
my $SRloc = xCAT::InstUtils->get_nim_attr_val($imghash{$imagename}{shared_root}, 'location', $callback, $nimprime, $subreq);
|
|
|
|
# copy the statelite table file to the shared root location
|
|
# this will not effect any running nodes that are using
|
|
# this shared_root resource. However the new table will
|
|
# include any info need for existing nodes - for when they
|
|
# need to be rebooted
|
|
|
|
if (-d $SRloc) {
|
|
my $ccmd = "/bin/cp $statelitetable $litefiletable $litetreetable $instrootloc/aixlitesetup $SRloc";
|
|
my $out = xCAT::Utils->runcmd("$ccmd", -1);
|
|
if ($::RUNCMD_RC != 0)
|
|
{
|
|
my $rsp;
|
|
push @{$rsp->{data}}, "Could not copy statelite files to $SRloc.";
|
|
xCAT::MsgUtils->message("E", $rsp, $callback);
|
|
return 1;
|
|
}
|
|
}
|
|
}
|
|
}
|
|
return 0;
|
|
}
|
|
|
|
|
|
1;
|