mirror of
https://github.com/xcat2/xcat-core.git
synced 2025-09-04 01:08:18 +00:00
* To fix issue that lose activation success log * update onie doc to add rspconfig sshcfg command (#5539) * fix osarch missing from copycds (#5543) * Modify release information for 2.14.3 release * update goconserver quickstart document * Enhancement for using site cache in plugin (#5535) * site cache when run plugin does not work very well - using cache from plugin when getNodesAttribs/getNodeAttribs (pass it into DB process from plugin process) - Site cache is a whole hash, so to use cache when by the hash is there, instead of the specified key is there. It is because that there might be no key defined in site table. * with XCATBYPASS, to populate site hash before scan_plugins. Then only 1 query for site table to do whole things. * cache site when init plugins on service nodes * missing to comment the old codes query from xCAT DB process
424 lines
13 KiB
Perl
424 lines
13 KiB
Perl
#!/usr/bin/env perl
|
|
## IBM(c) 20013 EPL license http://www.eclipse.org/legal/epl-v10.html
|
|
#
|
|
# This plugin is used to handle the command requests for cumulus OS support
|
|
#
|
|
|
|
|
|
package xCAT_plugin::onie;
|
|
|
|
BEGIN
|
|
{
|
|
$::XCATROOT = $ENV{'XCATROOT'} ? $ENV{'XCATROOT'} : '/opt/xcat';
|
|
}
|
|
use lib "$::XCATROOT/lib/perl";
|
|
|
|
use strict;
|
|
use Getopt::Long;
|
|
use Expect;
|
|
use File::Path;
|
|
use File::Basename;
|
|
|
|
use xCAT::Utils;
|
|
use xCAT::MsgUtils;
|
|
use xCAT::TableUtils;
|
|
use xCAT::SvrUtils;
|
|
use xCAT::Table;
|
|
my $xcatdebugmode = 0;
|
|
$::VERBOSE = 0;
|
|
|
|
sub handled_commands {
|
|
return {
|
|
nodeset => 'nodehm:mgt=switch',
|
|
copydata => 'onie',
|
|
rspconfig => 'switches:switchtype',
|
|
}
|
|
}
|
|
|
|
my $CALLBACK; # used to hanel the output from xdsh
|
|
|
|
sub preprocess_request {
|
|
my $request = shift;
|
|
my $callback = shift;
|
|
|
|
if ($request->{command}->[0] eq 'copydata')
|
|
{
|
|
return [$request];
|
|
}
|
|
|
|
# if already preprocessed, go straight to request
|
|
if ((defined($request->{_xcatpreprocessed}->[0]))
|
|
&& ($request->{_xcatpreprocessed}->[0] == 1)) {
|
|
return [$request];
|
|
}
|
|
|
|
my $nodes = $request->{node};
|
|
my $command = $request->{command}->[0];
|
|
my $extraargs = $request->{arg};
|
|
|
|
if ($extraargs) {
|
|
@ARGV = @{$extraargs};
|
|
my ($verbose, $help, $ver);
|
|
GetOptions("V" => \$verbose, 'h|help' => \$help, 'v|version' => \$ver);
|
|
if ($help) {
|
|
my $usage_string = xCAT::Usage->getUsage($command);
|
|
my $rsp;
|
|
push @{ $rsp->{data} }, $usage_string;
|
|
xCAT::MsgUtils->message("I", $rsp, $callback);
|
|
return ();
|
|
}
|
|
if ($ver) {
|
|
my $ver_string = xCAT::Usage->getVersion($command);
|
|
my $rsp;
|
|
push @{ $rsp->{data} }, $ver_string;
|
|
xCAT::MsgUtils->message("I", $rsp, $callback);
|
|
return ();
|
|
}
|
|
|
|
if ($verbose) {
|
|
$::VERBOSE = 1;
|
|
}
|
|
}
|
|
|
|
return [$request];
|
|
}
|
|
|
|
sub process_request {
|
|
my $request = shift;
|
|
my $callback = shift;
|
|
my $subreq = shift;
|
|
|
|
my $nodes = $request->{node};
|
|
my $command = $request->{command}->[0];
|
|
my $args = $request->{arg};
|
|
my @exargs = ($request->{arg});
|
|
if (ref($args)) {
|
|
@exargs = @$args;
|
|
}
|
|
|
|
|
|
if ($::XCATSITEVALS{xcatdebugmode} != 0) { $::VERBOSE = 1}
|
|
|
|
if ($command eq "copydata") {
|
|
copydata($request, $callback);
|
|
} elsif ($command eq "nodeset") {
|
|
nodeset($request, $callback, $subreq);
|
|
} elsif ($command eq "rspconfig") {
|
|
my $subcmd = $exargs[0];
|
|
if ($subcmd eq 'sshcfg') {
|
|
process_sshcfg($nodes, $callback);
|
|
} else {
|
|
xCAT::MsgUtils->message("I", { data => ["The rspconfig command $subcmd is not supported"] }, $callback);
|
|
}
|
|
}
|
|
|
|
}
|
|
|
|
# build cumulus OS image
|
|
sub copydata {
|
|
my $request = shift;
|
|
my $callback = shift;
|
|
my $file;
|
|
my $inspection = undef;
|
|
my $noosimage = undef;
|
|
my $nooverwrite = undef;
|
|
|
|
# get arguments
|
|
my $args = $request->{arg};
|
|
if ($args) {
|
|
@ARGV = @{$args};
|
|
GetOptions(
|
|
'w' => \$nooverwrite,
|
|
'o' => \$noosimage,
|
|
'i' => \$inspection,
|
|
'f=s' => \$file
|
|
);
|
|
}
|
|
|
|
if (!(-x $file)) {
|
|
xCAT::MsgUtils->message("E", { error => ["$file is not executable, will not process"], errorcode => ["1"] }, $callback);
|
|
return;
|
|
}
|
|
|
|
#get install dir
|
|
my $installroot = "/install";
|
|
my $sitetab = xCAT::Table->new('site');
|
|
my @ents = xCAT::TableUtils->get_site_attribute("installdir");
|
|
my $site_ent = $ents[0];
|
|
if (defined($site_ent))
|
|
{
|
|
$installroot = $site_ent;
|
|
}
|
|
|
|
my $arch;
|
|
my $desc;
|
|
my $release;
|
|
my $osname;
|
|
my $filename = basename($file);
|
|
my $output = `$file`;
|
|
if ($inspection) {
|
|
$callback->({ data => "file output: $output" });
|
|
return;
|
|
}
|
|
foreach my $line (split /[\r\n]+/, $output) {
|
|
if ($line =~ /^Architecture/) {
|
|
($desc, $arch) = split /: /, $line ;
|
|
chomp $arch;
|
|
}
|
|
if ($line =~ /^Release/) {
|
|
($desc, $release) = split /: /, $line ;
|
|
chomp $release;
|
|
}
|
|
if ($line =~ /cumulus/) {
|
|
$osname = "cumulus" ;
|
|
}
|
|
}
|
|
unless ($osname) {
|
|
$osname="image";
|
|
}
|
|
|
|
my $distname = $osname . $release;
|
|
my $imagename = $distname . "-" . $arch;
|
|
my $defaultpath = "$installroot/$distname/$arch";
|
|
|
|
#check if file exists
|
|
if ( (-e "$defaultpath/$filename") && ($nooverwrite)){
|
|
$callback->({ data => "$defaultpath/$filename is already exists, will not overwrite" });
|
|
} else {
|
|
$callback->({ data => "Copying media to $defaultpath" });
|
|
mkpath ("$defaultpath");
|
|
system("cp $file $defaultpath");
|
|
$callback->({ data => "Media copy operation successful" });
|
|
}
|
|
|
|
if ($noosimage) {
|
|
$callback->({ data => "Option noosimage is specified, will not create osimage definition" });
|
|
return;
|
|
}
|
|
|
|
# generate the image objects
|
|
my $oitab = xCAT::Table->new('osimage');
|
|
unless ($oitab) {
|
|
xCAT::MsgUtils->message("E", { error => ["Error: Cannot open table osimage."], errorcode => ["1"] }, $callback);
|
|
return 1;
|
|
}
|
|
my $litab = xCAT::Table->new('linuximage');
|
|
unless ($litab) {
|
|
xCAT::MsgUtils->message("E", { error => ["Error: Cannot open table linuximage."], errorcode => ["1"] }, $callback);
|
|
return 1;
|
|
}
|
|
my $pkgdir = "$defaultpath/$filename";
|
|
my $imgdir = $litab->getAttribs({ 'imagename' => $imagename }, 'pkgdir');
|
|
|
|
if ($::VERBOSE) {
|
|
$callback->({ data => "creating image $imagename with osarch=$arch, osvers=$distname" });
|
|
}
|
|
|
|
my %values;
|
|
$values{'imagetype'} = "linux";
|
|
$values{'provmethod'} = "install";
|
|
$values{'description'} = "Cumulus Linux";
|
|
$values{'osname'} = "$osname";
|
|
$values{'osvers'} = "$distname";
|
|
$values{'osarch'} = "$arch";
|
|
|
|
$oitab->setAttribs({ 'imagename' => $imagename }, \%values);
|
|
|
|
# set a default package list
|
|
$litab->setAttribs({ 'imagename' => $imagename }, { 'pkgdir' => $pkgdir });
|
|
if ($::VERBOSE) {
|
|
$callback->({ data => "setting pkgdir=$pkgdir for image $imagename" });
|
|
}
|
|
|
|
#Need to update osdistro table?
|
|
my @ret = xCAT::SvrUtils->update_osdistro_table($distname, $arch, $defaultpath, $imagename);
|
|
if ($ret[0] != 0) {
|
|
xCAT::MsgUtils->message("E", { error => ["Error when updating the osdistro tables."], errorcode => ["1"] }, $callback);
|
|
}
|
|
|
|
xCAT::MsgUtils->message("I", { data => ["The image $imagename is created."] }, $callback);
|
|
}
|
|
|
|
|
|
# run the nodeset to updatenode provmethod
|
|
sub nodeset {
|
|
my $request = shift;
|
|
my $callback = shift;
|
|
my $subreq = shift;
|
|
|
|
my $switches = $request->{'node'};
|
|
my $args = $request->{arg};
|
|
my $provmethod;
|
|
my $image_pkgdir;
|
|
|
|
my $setosimg;
|
|
foreach (@$args) {
|
|
if (/osimage=(.*)/) {
|
|
$setosimg = $1;
|
|
}
|
|
}
|
|
|
|
my $switchestab = xCAT::Table->new('switches');
|
|
my $switcheshash = $switchestab->getNodesAttribs($switches, ['switchtype']);
|
|
|
|
my $nodetab = xCAT::Table->new('nodetype');
|
|
my $nodehash = $nodetab->getNodesAttribs($switches, [ 'provmethod' ]);
|
|
|
|
foreach my $switch (@$switches) {
|
|
if ($switcheshash->{$switch}->[0]->{switchtype} ne "onie") {
|
|
xCAT::MsgUtils->message("E", { error => ["nodeset command is not processed for $switch, only supports switchtype=onie"], errorcode => ["1"] }, $callback);
|
|
next;
|
|
}
|
|
|
|
|
|
if ($setosimg) {
|
|
$provmethod = $setosimg;
|
|
} else {
|
|
$provmethod = $nodehash->{$switch}->[0]->{provmethod};
|
|
}
|
|
if ($::VERBOSE) {
|
|
xCAT::MsgUtils->message("I", { data => ["$switch has provmethod=$provmethod"] }, $callback);
|
|
}
|
|
|
|
#get pkgdir from osimage
|
|
my $linuximagetab = xCAT::Table->new('linuximage');
|
|
my $osimagetab = xCAT::Table->new('osimage');
|
|
my $imagetab = $linuximagetab->getAttribs({ imagename => $provmethod },'pkgdir');
|
|
my $osimghash = $osimagetab->getAttribs({ imagename => $provmethod },'osvers','osarch');
|
|
unless($imagetab and $osimghash){
|
|
xCAT::MsgUtils->message("E", { error => ["cannot find osimage \"$provmethod\" for $switch, please make sure the osimage specified in command line or node.provmethod exists!"], errorcode => ["1"] }, $callback);
|
|
next;
|
|
}
|
|
|
|
|
|
my %attribs=('provmethod' => $provmethod,'os'=>$osimghash->{'osvers'},'arch'=>$osimghash->{'osarch'} );
|
|
$nodetab->setAttribs({ 'node' => $switch }, \%attribs);
|
|
$image_pkgdir = $imagetab->{'pkgdir'};
|
|
|
|
#validate the image pkgdir
|
|
my $flag=0;
|
|
if (-r $image_pkgdir) {
|
|
my @filestat = `file $image_pkgdir`;
|
|
if (grep /$image_pkgdir: data/, @filestat) {
|
|
$flag=1;
|
|
}
|
|
}
|
|
unless ($flag) {
|
|
xCAT::MsgUtils->message("E", { error => ["The image '$image_pkgdir' is invalid"], errorcode => ["1"] }, $callback);
|
|
next;
|
|
}
|
|
if ($::VERBOSE) {
|
|
xCAT::MsgUtils->message("I", { data => ["osimage=$provmethod, pkgdir=$image_pkgdir"] }, $callback);
|
|
}
|
|
|
|
#updateing DHCP entries
|
|
my $ret = xCAT::Utils->runxcmd({ command => ["makedhcp"], node => [$switch] }, $subreq, 0, 1);
|
|
if ($::RUNCMD_RC) {
|
|
xCAT::MsgUtils->message("E", { error => ["Failed to run 'makedhcp' command"], errorcode => ["$::RUNCMD_RC"] }, $callback);
|
|
}
|
|
|
|
xCAT::MsgUtils->message("I", { data => ["$switch: install $provmethod"] }, $callback);
|
|
}
|
|
return;
|
|
}
|
|
|
|
|
|
sub process_sshcfg {
|
|
my $noderange = shift;
|
|
my $callback = shift;
|
|
|
|
my $password = "CumulusLinux!";
|
|
my $userid = "cumulus";
|
|
my $timeout = 30;
|
|
my $keyfile = "/root/.ssh/id_rsa.pub";
|
|
my $rootkey = `cat /root/.ssh/id_rsa.pub`;
|
|
|
|
foreach my $switch (@$noderange) {
|
|
my $ip = xCAT::NetworkUtils->getipaddr($switch);
|
|
|
|
#remove old host key from /root/.ssh/known_hosts
|
|
my $cmd = "ssh-keygen -R $switch";
|
|
xCAT::Utils->runcmd($cmd, 0);
|
|
$cmd = "ssh-keygen -R $ip";
|
|
xCAT::Utils->runcmd($cmd, 0);
|
|
|
|
my ($exp, $errstr) = cumulus_connect($ip, $userid, $password, $timeout);
|
|
if (!defined $exp) {
|
|
xCAT::MsgUtils->message("E", { data => ["Failed to connect to $switch"] }, $callback);
|
|
next;
|
|
}
|
|
|
|
my $ret;
|
|
my $err;
|
|
|
|
($ret, $err) = cumulus_exec($exp, "mkdir -p /root/.ssh");
|
|
($ret, $err) = cumulus_exec($exp, "chmod 700 /root/.ssh");
|
|
($ret, $err) = cumulus_exec($exp, "echo \"$rootkey\" >/root/.ssh/authorized_keys");
|
|
($ret, $err) = cumulus_exec($exp, "chmod 644 /root/.ssh/authorized_keys");
|
|
if (!defined $ret) {
|
|
xCAT::MsgUtils->message("E", { data => ["Failed to run command on $switch"] }, $callback);
|
|
next;
|
|
}
|
|
xCAT::MsgUtils->message("I", { data => ["$switch: SSH enabled"] }, $callback);
|
|
}
|
|
}
|
|
|
|
sub cumulus_connect {
|
|
my $server = shift;
|
|
my $userid = shift;
|
|
my $password = shift;
|
|
my $timeout = shift;
|
|
|
|
my $ssh = Expect->new;
|
|
my $command = 'ssh';
|
|
my @parameters = ($userid . "@" . $server);
|
|
|
|
$ssh->debug(0);
|
|
$ssh->log_stdout(0); # suppress stdout output..
|
|
$ssh->slave->stty(qw(sane -echo));
|
|
|
|
unless ($ssh->spawn($command, @parameters))
|
|
{
|
|
my $err = $!;
|
|
$ssh->soft_close();
|
|
my $rsp;
|
|
return(undef, "unable to run command $command $err\n");
|
|
}
|
|
|
|
$ssh->expect($timeout,
|
|
[ "-re", qr/WARNING: REMOTE HOST IDENTIFICATION HAS CHANGED/, sub {die "WARNING: REMOTE HOST IDENTIFICATION HAS CHANGED!\n"; } ],
|
|
[ "-re", qr/\(yes\/no\)\?\s*$/, sub { $ssh->send("yes\n"); exp_continue; } ],
|
|
[ "-re", qr/ password:/, sub {$ssh->send("$password\n"); exp_continue; } ],
|
|
[ "-re", qr/:~\$/, sub { $ssh->send("sudo su\n"); exp_continue; } ],
|
|
[ "-re", qr/ password for cumulus:/, sub { $ssh->send("$password\n"); exp_continue; } ],
|
|
[ "-re", qr/.*\/home\/cumulus#/, sub { $ssh->clear_accum(); } ],
|
|
[ timeout => sub { die "No login.\n"; } ]
|
|
);
|
|
$ssh->clear_accum();
|
|
return ($ssh);
|
|
}
|
|
|
|
sub cumulus_exec {
|
|
my $exp = shift;
|
|
my $cmd = shift;
|
|
my $timeout = shift;
|
|
my $prompt = shift;
|
|
|
|
$timeout = 10 unless defined $timeout;
|
|
$prompt = qr/.*\/home\/cumulus#/ unless defined $prompt;
|
|
|
|
|
|
$exp->clear_accum();
|
|
$exp->send("$cmd\n");
|
|
my ($mpos, $merr, $mstr, $mbmatch, $mamatch) = $exp->expect(6, "-re", $prompt);
|
|
|
|
if (defined $merr) {
|
|
return(undef,$merr);
|
|
}
|
|
return($mbmatch);
|
|
}
|
|
|
|
|
|
|
|
1;
|