xcat-core/xCAT-server/lib/xcat/plugins/boottarget.pm

210 lines
6.0 KiB
Perl

# IBM(c) 2007 EPL license http://www.eclipse.org/legal/epl-v10.html
package xCAT_plugin::boottarget;
BEGIN
{
$::XCATROOT = $ENV{'XCATROOT'} ? $ENV{'XCATROOT'} : '/opt/xcat';
}
use lib "$::XCATROOT/lib/perl";
use Storable qw(dclone);
use Sys::Syslog;
use Thread qw(yield);
use POSIX qw(WNOHANG nice);
use xCAT::Table;
use xCAT::Utils;
use xCAT::MsgUtils;
use xCAT::Template;
#use xCAT::Postage;
use Data::Dumper;
use Getopt::Long;
Getopt::Long::Configure("bundling");
Getopt::Long::Configure("pass_through");
use File::Path;
use File::Copy;
sub handled_commands
{
return {
mknetboot => "nodetype:os=(boottarget)|(target)|(bt)",
mkinstall => "nodetype:os=(boottarget)|(target)|(bt)"
};
}
sub preprocess_request
{
my $req = shift;
my $callback = shift;
#if already preprocessed, go straight to request
if ($req->{_xcatpreprocessed}->[0] == 1) { return [$req]; }
if ($req->{command}->[0] eq 'copycd')
{ #don't farm out copycd
return [$req];
}
my $stab = xCAT::Table->new('site');
my $sent;
($sent) = $stab->getAttribs({key => 'sharedtftp'}, 'value');
unless ( $sent
and defined($sent->{value})
and ($sent->{value} =~ /no/i or $sent->{value} =~ /0/))
{
#unless requesting no sharedtftp, don't make hierarchical call
return [$req];
}
my %localnodehash;
my %dispatchhash;
my $nrtab = xCAT::Table->new('noderes');
my $nrents = $nrtab->getNodesAttribs($req->{node},[qw(tftpserver servicenode)]);
foreach my $node (@{$req->{node}})
{
my $nodeserver;
my $tent = $nrents->{$node}->[0]; #$nrtab->getNodeAttribs($node, ['tftpserver']);
if ($tent) { $nodeserver = $tent->{tftpserver} }
unless ($tent and $tent->{tftpserver})
{
$tent = $nrents->{$node}->[0]; #$nrtab->getNodeAttribs($node, ['servicenode']);
if ($tent) { $nodeserver = $tent->{servicenode} }
}
if ($nodeserver)
{
$dispatchhash{$nodeserver}->{$node} = 1;
}
else
{
$localnodehash{$node} = 1;
}
}
my @requests;
my $reqc = {%$req};
$reqc->{node} = [keys %localnodehash];
if (scalar(@{$reqc->{node}})) { push @requests, $reqc }
foreach my $dtarg (keys %dispatchhash)
{ #iterate dispatch targets
my $reqcopy = {%$req}; #deep copy
$reqcopy->{'_xcatdest'} = $dtarg;
$reqcopy->{_xcatpreprocessed}->[0] = 1;
$reqcopy->{node} = [keys %{$dispatchhash{$dtarg}}];
push @requests, $reqcopy;
}
return \@requests;
}
sub process_request
{
my $request = shift;
my $callback = shift;
my $doreq = shift;
my $distname = undef;
my $arch = undef;
my $path = undef;
return mknetboot($request, $callback, $doreq);
}
sub mknetboot
{
my $req = shift;
my $callback = shift;
my $doreq = shift;
my $tftpdir = "/tftpboot";
my $nodes = @{$request->{node}};
my @args = @{$req->{arg}};
my @nodes = @{$req->{node}};
my $ostab = xCAT::Table->new('nodetype');
my $sitetab = xCAT::Table->new('site');
my $installroot;
$installroot = "/install";
if ($sitetab)
{
(my $ref) = $sitetab->getAttribs({key => installdir}, value);
if ($ref and $ref->{value})
{
$installroot = $ref->{value};
}
}
my %donetftp=();
my %oents = %{$ostab->getNodesAttribs(\@nodes,[qw(os arch profile)])};
my $restab = xCAT::Table->new('noderes');
my $bptab = xCAT::Table->new('bootparams',-create=>1);
my $hmtab = xCAT::Table->new('nodehm');
my $ttab = xCAT::Table->new('boottarget');
foreach $node (@nodes)
{
my $ent = $oents{$node}->[0]; #ostab->getNodeAttribs($node, ['os', 'arch', 'profile']);
unless ($ent->{os} and $ent->{profile})
{
$callback->(
{
error => ["Insufficient nodetype entry for $node"],
errorcode => [1]
}
);
next;
}
my $profile = $ent->{profile};
($tent) = $ttab->getAttribs({'bprofile' => $profile}, 'kernel', 'initrd', 'kcmdline'); #TODO: coalesce these queries into one Table query, speed it up
if(! defined($tent)){
my $msg = "$profile in nodetype table was not defined in boottarget table";
$callback->({
error => ["$msg"],
errorcode => [1]
});
}
$kernel = $tent->{kernel};
$initrd = $tent->{initrd};
$kcmdline = $tent->{kcmdline};
#TODO: big todo, cheap and rapid, but should be more like esx.pm implementation, i.e. more scalable
while ($kcmdline =~ /#NODEATTRIB:([^:#]+):([^:#]+)#/) {
my $natab = xCAT::Table->new($1);
my $naent = $natab->getNodeAttribs($node,[$2]);
my $naval = $naent->{$2};
$kcmdline =~ s/#NODEATTRIB:([^:#]+):([^:#]+)#/$naval/;
}
while ($kcmdline =~ /#TABLE:([^:#]+):([^:#]+):([^:#]+)#/) {
if ($2 =~ /THISNODE/ or $2 =~ /\$NODE/) {
my $natab = xCAT::Table->new($1);
my $naent = $natab->getNodeAttribs($node,[$3]);
my $naval = $naent->{$3};
$kcmdline =~ s/#NODEATTRIB:([^:#]+):([^:#]+):([^:#]+)#/$naval/;
} else {
my $msg = "Table key of $2 not yet supported by boottarget mini-template";
$callback->({
error => ["$msg"],
errorcode => [1]
});
}
}
if($initrd eq ''){
$bptab->setNodeAttribs(
$node,
{
kernel => $kernel,
initrd => '',
kcmdline => $kcmdline
}
);
}else{
$bptab->setNodeAttribs(
$node,
{
kernel => $kernel,
initrd => $initrd,
kcmdline => $kcmdline
}
);
}
}
}
1;