xcat-core/perl-xCAT/xCAT/InstUtils.pm

508 lines
12 KiB
Perl
Raw Normal View History

#!/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 strict;
require xCAT::Schema;
#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+/) {
my $packedaddr = inet_aton($nimprime);
$hostname = gethostbyaddr($packedaddr, AF_INET);
} 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+/) {
my $packedaddr = inet_aton($hostname);
$name = gethostbyaddr($packedaddr, AF_INET);
} 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 = inet_ntoa(inet_aton($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;
# Split the two ip addresses up into octets
my ($a1, $a2, $a3, $a4) = split /\./, $myIP;
if ( ($a1 == $b1) && ($a2 == $b2) && ($a3 == $b3) && ($a4 == $b4) ) {
return 1;
}
}
return 0;
}
#----------------------------------------------------------------------------
=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;
}
my ($junk, $junk, $junk, $loc) = split(/:/, $nout);
chomp $loc;
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 = 0;
if ($doarray) {
$returnformat = $doarray;
}
my $output;
if (xCAT::InstUtils->is_me($target)) {
$output=xCAT::Utils->runcmd($cmd, $exitcode, $returnformat);
} else {
# need xdsh or xdcp
my @snodes;
push( @snodes, $target );
$output=xCAT::Utils->runxcmd(
{
command => [$xdcmd],
node => \@snodes,
arg => [ $cmd ]
},
$sub_req,
$exitcode, $returnformat
);
}
if ($doarray) {
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);
# open the file
unless (open(BNDFILE, "<$bnd_file_name")) {
return (1);
}
# get the names of the packages
while (my $l = <BNDFILE>) {
chomp $l;
# skip blank and comment lines
next if ($l =~ /^\s*$/ || $l =~ /^\s*#/);
push (@pkglist, $l);
}
close(BNDFILE);
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. This assumes that the "os"
attribute of AIX nodes will always be set!
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) {
if ( ($os->{$n}->[0]->{os} ne "AIX") && ($os->{$n}->[0]->{os} ne "aix")) {
push(@linuxnodes, $n);
$rc = 0;
} else {
push(@aixnodes, $n);
}
}
$nodetab->close;
return ($rc, \@aixnodes, \@linuxnodes);
}
1;