2
0
mirror of https://github.com/xcat2/xcat-core.git synced 2025-09-04 01:08:18 +00:00
Files
xcat-core/xCAT-server/lib/xcat/plugins/onie.pm
yangsong 7b7d9ab675 merge master to 2.14 branch (#5546)
* 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
2018-08-21 18:38:08 +08:00

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;