#!/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) { unshift(@INC, qw(/usr/opt/perl5/lib/5.8.2/aix-thread-multi /usr/opt/perl5/lib/5.8.2 /usr/opt/perl5/lib/site_perl/5.8.2/aix-thread-multi /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; use xCAT::TableUtils; #require Data::Dumper; #use Data::Dumper; require xCAT::NodeRange; require DBI; #------------------------------------------------------------------------------- =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::TableUtils->get_site_Master(); #my $sitetab = xCAT::Table->new('site'); #(my $et) = $sitetab->getAttribs({key => "nimprime"}, 'value'); my @nimprimes = xCAT::TableUtils->get_site_attribute("nimprime"); my $tmp = $nimprimes[0]; if (defined($tmp)) { $nimprime = $tmp; } 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); # make sure xcatd is running - & db is available # this routine is called during initial install of xCAT my $cmd="lsxcatd -d > /dev/null 2>&1"; my $outref = []; @$outref = `$cmd`; my $rc = $? >> 8; if ($rc == 0) { if (xCAT::Utils->isMN()) { # read the site table, master attrib my $hostname = xCAT::TableUtils->get_site_Master(); if (($hostname =~ /\d+\.\d+\.\d+\.\d+/) || ($hostname =~ /:/)) { $name = xCAT::NetworkUtils->gethostname($hostname); } else { $name = $hostname; } } elsif (xCAT::Utils->isServiceNode()) { my $filename; # get any files with the format myxcatpost_* my $lscmd = qq~/bin/ls /xcatpost/myxcatpost_* 2>/dev/null~; my $output = `$lscmd`; my $rc = $? >> 8; if ($rc == 0) { foreach my $line ( split(/\n/, $output)) { my ($junk, $hostname) = split('myxcatpost_', $line); if (xCAT::InstUtils->is_me($hostname)) { $filename="/xcatpost/myxcatpost_$hostname"; last; } } if ( -e $filename ) { my $catcmd = qq~/bin/cat $filename | grep '^NODE=' 2>/dev/null~; my $string = `$catcmd`; if ($rc == 0) { ($junk, $name) = split('=', $string); } } } } } if (!$name) { $name = hostname(); } 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; # shut off verbose - just for this routine my $verb = $::VERBOSE; $::VERBOSE = 0; # split into octets #my ($b1, $b2, $b3, $b4) = split /\./, $nameIP; # get all the possible IPs for the node I'm running on # this is a common subroutine for both AIX and Linux, # AIX does not have ip command my $ipcmd; if ( -f "/sbin/ip" ) { $ipcmd = "ip addr | grep 'inet'"; } else { $ipcmd = "ifconfig -a | grep 'inet'"; } my $result = xCAT::Utils->runcmd($ipcmd, -1, 1); if ($::RUNCMD_RC != 0) { my $str="Error running ipcmd"; xCAT::MsgUtils->message("S", $str); $::VERBOSE = $verb; 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) { $::VERBOSE = $verb; return 1; } } $::VERBOSE = $verb; 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*.*)$/; 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) { return undef; } # The command output may have the xdsh prefix "target:" 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::NetworkUtils->my_ip_facing($node); } chomp $serv; if (xCAT::NetworkUtils->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; } # get name as known by xCAT my $Sname = xCAT::InstUtils->myxCATname(); chomp $Sname; my $nimprime = xCAT::InstUtils->getnimprime(); my $target; if (xCAT::Utils->isSN($Sname)) { $target=$Sname; } else { $target=$nimprime; } 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. @nodelist= xCAT::DBobjUtils->getObjectsOfType('node'); my $noderange; if (scalar(@nodelist) > 0) { $noderange = join(',',@nodelist); } else { my $rsp; push @{$rsp->{data}}, "Could not get list of xCAT nodes. No statelite configuration will be done.\n"; xCAT::MsgUtils->message("E", $rsp, $callback); return 2; } # get spot inst_root loc my $spotloc = xCAT::InstUtils->get_nim_attr_val($imghash{$imagename}{spot}, 'location', $callback, $target, $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 $litetreetable) { my $rc = xCAT::Utils->runcmd("rm $litetreetable", -1); if ($::RUNCMD_RC != 0) { my $rsp; push @{$rsp->{data}}, "Could not remove existing $litetreetable 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; } # create the statelite table file my $foundentry=0; my $stateHash = $statelitetab->getNodesAttribs(\@nodelist, ['statemnt', 'mntopts']); 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=""; my $mntopts; if (exists($stateHash->{$node})) { $mntopts = $stateHash->{$node}->[0]->{mntopts}; $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~; if ($mntopts) { $entry = qq~$node|$statemnt|$mntopts~; } $entry =~ s/\s*//g; #remove blanks if ($statemnt) { print STATELITE $entry . "\n"; $foundentry++; } } close(STATELITE); if (!$foundentry) { # don't leave empty file my $rc = xCAT::Utils->runcmd("rm $statelitetable", -1); if ($::RUNCMD_RC != 0) { my $rsp; push @{$rsp->{data}}, "Could not remove $statelitetable file."; xCAT::MsgUtils->message("E", $rsp, $callback); return 1; } } 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); if (scalar(@filelist) > 0) { 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); } else { close(LITEFILE); # remove empty files my $rc = xCAT::Utils->runcmd("rm $litefiletable", -1); if ($::RUNCMD_RC != 0) { my $rsp; push @{$rsp->{data}}, "Could not remove $litefiletable file."; xCAT::MsgUtils->message("E", $rsp, $callback); return 1; } } # need list for just this set of nodes!!! my $nrange; my @flist; my @litef; if (scalar(@nodel) > 0) { $nrange = join(',',@nodel); } @flist = xCAT::Utils->runcmd("/opt/xcat/bin/litefile $nrange", -1); if (scalar(@flist) > 0) { foreach my $l (@flist) { my ($j1, $j2, $file) = split /\s+/, $l; push (@litef, $file); } } my $foundras; if (scalar(@litef) > 0) { foreach my $f (@litef) { chomp $f; if (($f eq "/var/adm/ras/") || ($f eq "/var/adm/ras/conslog")) { $foundras++; } } } if ($foundras) { my $rsp; push @{$rsp->{data}}, "One or more nodes is using a persistent \/var\/adm\/ras\/ directory. \nWhen the nodes boot up you will then have to move the conslog file to a \nlocation outside of the persistent directory. (Leaving the conslog \nfile in a persistent directory can occasionally lead to a deadlock situation.) \nThis can be done by using the xdsh command to run swcons on the \ncluster nodes. \n(Ex. xdsh \'\/usr\/sbin\/swcons -p \/tmp\/conslog\') \n"; xCAT::MsgUtils->message("W", $rsp, $callback); } 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); if (scalar(@treelist) > 0) { foreach my $l (@treelist) { my ($p, $serv, $dir, $mopts) = split (/:/, $l); $p =~ s/\s*//g; $serv =~ s/\s*//g; $dir =~ s/\s*//g; $mopts =~ s/\s*//g; my $serverIP = xCAT::NetworkUtils->getipaddr($serv); my $entry = "$p|$serverIP|$dir|$mopts"; print LITETREE $entry . "\n"; $foundstatelite++; } close(LITETREE); } else { close(LITETREE); # don't leave empty file my $rc = xCAT::Utils->runcmd("rm $litetreetable", -1); if ($::RUNCMD_RC != 0) { my $rsp; push @{$rsp->{data}}, "Could not remove $litetreetable file."; xCAT::MsgUtils->message("E", $rsp, $callback); return 1; } } # if there is no statelite info then just return if (!$foundstatelite) { if ($::VERBOSE) { my $rsp; push @{$rsp->{data}}, "Please update statlite,litefile,litetree tables if you want to use AIX statelite support.\n"; xCAT::MsgUtils->message("I", $rsp, $callback); } return 2; } # # 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); if (!$file) { next; } # 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); # entry must be an absolute path unless ($file =~ m{^/}) { my $rsp; push @{$rsp->{data}}, "The litefile entry \'$file\' is not an absolute path name.\n"; xCAT::MsgUtils->message("E", $rsp, $callback); return 1; } # 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~; $output = xCAT::Utils->runcmd("$cpcmd", -1); } } 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::TableUtils->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, $Sname, $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"; if (-e $statelitetable) { $ccmd .= " $statelitetable"; } if (-e $litefiletable) { $ccmd .= " $litefiletable"; } if (-e $litetreetable) { $ccmd .= " $litetreetable"; } $ccmd .= " $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; } # also copy $instrootloc/.default contents $ccmd = "/usr/bin/cp -p -r $instrootloc/.default $SRloc"; $out = xCAT::Utils->runcmd("$ccmd", -1); if ($::RUNCMD_RC != 0) { my $rsp; push @{$rsp->{data}}, "Could not copy $instrootloc/.default to $SRloc."; xCAT::MsgUtils->message("E", $rsp, $callback); return 1; } # also copy $instrootloc/.statelite contents $ccmd = "/usr/bin/cp -p -r $instrootloc/.statelite $SRloc"; $out = xCAT::Utils->runcmd("$ccmd", -1); if ($::RUNCMD_RC != 0) { my $rsp; push @{$rsp->{data}}, "Could not copy $instrootloc/.statelite to $SRloc."; xCAT::MsgUtils->message("E", $rsp, $callback); return 1; } } } } return 0; } #---------------------------------------------------------------------------- =head3 convert_xcatmaster Convert the keyword of nameservers attr in site/networks table to IP address. (Either the management node or a service node) =cut #----------------------------------------------------------------------------- sub convert_xcatmaster { my $shorthost = xCAT::InstUtils->myxCATname(); my $selfip = xCAT::NetworkUtils->getipaddr($shorthost); return $selfip; } 1;