git-svn-id: https://svn.code.sf.net/p/xcat/code/xcat-core/trunk@7776 8638fb3e-16cb-4fca-ae20-7b5d299a9bcd
		
			
				
	
	
		
			1095 lines
		
	
	
		
			27 KiB
		
	
	
	
		
			Perl
		
	
	
	
	
	
			
		
		
	
	
			1095 lines
		
	
	
		
			27 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 @nl;
 | 
						|
    if ($nodes) {
 | 
						|
        @nl = @$nodes;
 | 
						|
		foreach my $n (@nl) {
 | 
						|
			push(@nodelist, xCAT::NodeRange::noderange($n));
 | 
						|
		}
 | 
						|
    }
 | 
						|
 | 
						|
	# 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 $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, 
 | 
						|
	my $mcmd = qq~/bin/mkdir -m 644 -p $instrootloc/.default; /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 directories.";
 | 
						|
        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
 | 
						|
 | 
						|
	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;
 | 
						|
 | 
						|
		if (-e $instrootfile) {
 | 
						|
 | 
						|
			if (!grep (/^$instrootfile$/, @copiedfiles)) {
 | 
						|
				# don't copy same file twice
 | 
						|
				push (@copiedfiles, $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
 | 
						|
					$cpcmd = qq~mkdir -p $default$file; cp -r $instrootfile* $default$file~;
 | 
						|
 | 
						|
				} 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 $instrootfile $default$filedir~;
 | 
						|
 | 
						|
				}
 | 
						|
 | 
						|
				my $output = xCAT::Utils->runcmd("$cpcmd", -1);
 | 
						|
				if ($::RUNCMD_RC != 0)
 | 
						|
				{
 | 
						|
					my $rsp;
 | 
						|
					push @{$rsp->{data}}, "Could not copy $instrootfile to $default subdirectory.";
 | 
						|
					if ($::VERBOSE)
 | 
						|
                	{
 | 
						|
                    	push @{$rsp->{data}}, "$output\n";
 | 
						|
                	}
 | 
						|
					xCAT::MsgUtils->message("E", $rsp, $callback);
 | 
						|
				}	
 | 
						|
			}
 | 
						|
	
 | 
						|
		} 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
 | 
						|
				$mkcmd = qq~mkdir -p $default$file~;
 | 
						|
			} else {
 | 
						|
				# create dir and touch file in .default
 | 
						|
				my $dir = dirname($instrootfile);
 | 
						|
				$mkcmd = qq~mkdir -p $dir; touch $default$file~;
 | 
						|
			}
 | 
						|
			my $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";
 | 
						|
				}
 | 
						|
				xCAT::MsgUtils->message("E", $rsp, $callback);
 | 
						|
			}
 | 
						|
			
 | 
						|
		}
 | 
						|
 | 
						|
	}
 | 
						|
 | 
						|
	# 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;
 |