mirror of
https://github.com/xcat2/xcat-core.git
synced 2025-05-22 03:32:04 +00:00
Add perl files of openbmc2
This commit is contained in:
parent
a41e138fc0
commit
26ccc9fabd
@ -16,6 +16,20 @@ use HTTP::Request;
|
||||
use HTTP::Headers;
|
||||
use HTTP::Cookies;
|
||||
use Data::Dumper;
|
||||
use Time::HiRes qw(sleep time);
|
||||
use JSON;
|
||||
use File::Path;
|
||||
use Fcntl ":flock";
|
||||
use IO::Socket::UNIX qw( SOCK_STREAM );
|
||||
use xCAT_monitoring::monitorctrl;
|
||||
|
||||
my $LOCK_DIR = "/var/lock/xcat/";
|
||||
my $LOCK_PATH = "/var/lock/xcat/agent.lock";
|
||||
my $AGENT_SOCK_PATH = "/var/run/xcat/agent.sock";
|
||||
my $PYTHON_LOG_PATH = "/var/log/xcat/agent.log";
|
||||
my $MSG_TYPE = "message";
|
||||
my $DB_TYPE = "db";
|
||||
my $lock_fd;
|
||||
|
||||
my $header = HTTP::Headers->new('Content-Type' => 'application/json');
|
||||
|
||||
@ -43,4 +57,140 @@ sub send_request {
|
||||
return $id;
|
||||
}
|
||||
|
||||
# if lock is released unexpectedly, python side would aware of the error after
|
||||
# getting this lock
|
||||
sub acquire_lock {
|
||||
mkpath($LOCK_DIR);
|
||||
# always create a new lock file
|
||||
unlink($LOCK_PATH);
|
||||
open($lock_fd, ">>", $LOCK_PATH) or return undef;
|
||||
flock($lock_fd, LOCK_EX) or return undef;
|
||||
return $lock_fd;
|
||||
}
|
||||
sub start_python_agent {
|
||||
my $agent_file = "/opt/xcat/lib/python/agent/agent.py";
|
||||
if (! -e $agent_file) {
|
||||
xCAT::MsgUtils->message("S", "Error: '/opt/xcat/lib/python/agent/agent.py' does not exist");
|
||||
return undef;
|
||||
}
|
||||
|
||||
if (!defined(acquire_lock())) {
|
||||
xCAT::MsgUtils->message("S", "Error: Faild to require lock");
|
||||
return undef;
|
||||
}
|
||||
my $fd;
|
||||
open($fd, '>', $AGENT_SOCK_PATH) && close($fd);
|
||||
my $pid = fork;
|
||||
if (!defined $pid) {
|
||||
xCAT::MsgUtils->message("S", "Error: Unable to fork process");
|
||||
return undef;
|
||||
}
|
||||
$SIG{CHLD} = 'DEFAULT';
|
||||
if (!$pid) {
|
||||
# child
|
||||
open($fd, ">>", $PYTHON_LOG_PATH) && close($fd);
|
||||
open(STDOUT, '>>', $PYTHON_LOG_PATH) or die("open: $!");
|
||||
open(STDERR, '>>&', \*STDOUT) or die("open: $!");
|
||||
my $ret = exec ("/opt/xcat/lib/python/agent/agent.py");
|
||||
if (!defined($ret)) {
|
||||
xCAT::MsgUtils->message("S", "Error: Failed to start python agent");
|
||||
}
|
||||
}
|
||||
return $pid;
|
||||
}
|
||||
|
||||
sub handle_message {
|
||||
my ($data, $callback) = @_;
|
||||
if($data->{type} eq $MSG_TYPE) {
|
||||
my $msg = $data->{msg};
|
||||
if ($msg->{type} eq 'info') {
|
||||
xCAT::MsgUtils->message("I", { data => [$msg->{data}] }, $callback);
|
||||
} elsif ($msg->{type} eq 'warning') {
|
||||
xCAT::MsgUtils->message("W", { data => [$msg->{data}] }, $callback);
|
||||
} elsif ($msg->{type} eq 'error'){
|
||||
xCAT::MsgUtils->message("E", { data => [$msg->{data}] }, $callback);
|
||||
} elsif ($msg->{type} eq 'syslog'){
|
||||
xCAT::MsgUtils->message("S", $msg->{data});
|
||||
}
|
||||
} elsif ($data->{type} eq $DB_TYPE) {
|
||||
my $attribute = $data->{attribute};
|
||||
if ($attribute->{name} eq 'status' and $attribute->{method} eq 'set' and $attribute->{type} eq 'node') {
|
||||
my %new_status = ($attribute->{value} => [$attribute->{node}]);
|
||||
xCAT_monitoring::monitorctrl::setNodeStatusAttributes(\%new_status, 1)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
sub submit_agent_request {
|
||||
my ($pid, $req, $nodeinfo, $callback) = @_;
|
||||
my $sock;
|
||||
my $retry = 0;
|
||||
while($retry < 30) {
|
||||
$sock = IO::Socket::UNIX->new(Peer => $AGENT_SOCK_PATH, Type => SOCK_STREAM, Timeout => 10, Blocking => 1);
|
||||
if (!defined($sock)) {
|
||||
sleep(0.1);
|
||||
} else {
|
||||
last;
|
||||
}
|
||||
$retry++;
|
||||
}
|
||||
if (!defined($sock)) {
|
||||
xCAT::MsgUtils->message("E", { data => ["Failed to connect to the agent"] }, $callback);
|
||||
kill('TERM', $pid);
|
||||
return;
|
||||
}
|
||||
my $xcatdebugmode = 0;
|
||||
if ($::XCATSITEVALS{xcatdebugmode}) { $xcatdebugmode = $::XCATSITEVALS{xcatdebugmode} }
|
||||
my %env_hash = ();
|
||||
$env_hash{debugmode} = $xcatdebugmode;
|
||||
my ($data, $sz, $ret, $buf);
|
||||
$data->{module} = 'openbmc';
|
||||
$data->{command} = $req->{command}->[0];
|
||||
$data->{args} = $req->{arg};
|
||||
$data->{cwd} = $req->{cwd};
|
||||
$data->{nodes} = $req->{node};
|
||||
$data->{nodeinfo} = $nodeinfo;
|
||||
$data->{envs} = \%env_hash;
|
||||
$buf = encode_json($data);
|
||||
$sz = pack('i', length($buf));
|
||||
$ret = $sock->send($sz);
|
||||
if (!$ret) {
|
||||
xCAT::MsgUtils->message("E", { data => ["Failed to send message to the agent"] }, $callback);
|
||||
$sock->close();
|
||||
kill('TERM', $pid);
|
||||
return;
|
||||
}
|
||||
$ret = $sock->send($buf);
|
||||
if (!$ret) {
|
||||
xCAT::MsgUtils->message("E", { data => ["Failed to send message to the agent"] }, $callback);
|
||||
$sock->close();
|
||||
kill('TERM', $pid);
|
||||
return;
|
||||
}
|
||||
while(1) {
|
||||
$ret = $sock->recv($buf, 4);
|
||||
if (!$ret) {
|
||||
last;
|
||||
}
|
||||
$sz = unpack('i', $buf);
|
||||
$ret = $sock->recv($buf, $sz);
|
||||
if (!$ret) {
|
||||
xCAT::MsgUtils->message("E", { data => ["receive data from python agent unexpectedly"] }, $callback);
|
||||
last;
|
||||
}
|
||||
$data = decode_json($buf);
|
||||
handle_message($data, $callback);
|
||||
}
|
||||
# no message received, the socket on the agent side should be closed.
|
||||
$sock->close();
|
||||
}
|
||||
|
||||
sub wait_agent {
|
||||
my ($pid, $callback) = @_;
|
||||
waitpid($pid, 0);
|
||||
if ($? >> 8 != 0) {
|
||||
xCAT::MsgUtils->message("E", { data => ["python agent exited unexpectedly"] }, $callback);
|
||||
}
|
||||
}
|
||||
|
||||
1;
|
||||
|
@ -679,6 +679,21 @@ sub preprocess_request {
|
||||
}
|
||||
##############################################
|
||||
|
||||
# Provide a way to change to python code before formal release
|
||||
if (ref($request->{environment}) eq 'ARRAY' and ref($request->{environment}->[0]->{XCAT_OPENBMC_PYTHON}) eq 'ARRAY') {
|
||||
$::OPENBMC_PYTHON = $request->{environment}->[0]->{XCAT_OPENBMC_PYTHON}->[0];
|
||||
} elsif (ref($request->{environment}) eq 'ARRAY') {
|
||||
$::OPENBMC_PYTHON = $request->{environment}->[0]->{XCAT_OPENBMC_PYTHON};
|
||||
} else {
|
||||
$::OPENBMC_PYTHON = $request->{environment}->{XCAT_OPENBMC_PYTHON};
|
||||
}
|
||||
##############################################
|
||||
|
||||
if (defined($::OPENBMC_PYTHON) and $::OPENBMC_PYTHON eq "YES") {
|
||||
$request = {};
|
||||
return;
|
||||
}
|
||||
|
||||
$callback = shift;
|
||||
|
||||
if ($::XCATSITEVALS{xcatdebugmode}) { $xcatdebugmode = $::XCATSITEVALS{xcatdebugmode} }
|
||||
|
229
xCAT-server/lib/xcat/plugins/openbmc2.pm
Normal file
229
xCAT-server/lib/xcat/plugins/openbmc2.pm
Normal file
@ -0,0 +1,229 @@
|
||||
#!/usr/bin/perl
|
||||
### IBM(c) 2017 EPL license http://www.eclipse.org/legal/epl-v10.html
|
||||
|
||||
package xCAT_plugin::openbmc2;
|
||||
|
||||
BEGIN
|
||||
{
|
||||
$::XCATROOT = $ENV{'XCATROOT'} ? $ENV{'XCATROOT'} : '/opt/xcat';
|
||||
}
|
||||
use lib "$::XCATROOT/lib/perl";
|
||||
use strict;
|
||||
use warnings "all";
|
||||
|
||||
use JSON;
|
||||
use Getopt::Long;
|
||||
use xCAT::Utils;
|
||||
use xCAT::Usage;
|
||||
use xCAT::SvrUtils;
|
||||
use xCAT::OPENBMC;
|
||||
|
||||
#-------------------------------------------------------
|
||||
|
||||
=head3 handled_commands
|
||||
|
||||
Return list of commands handled by this plugin
|
||||
|
||||
=cut
|
||||
|
||||
#-------------------------------------------------------
|
||||
|
||||
sub handled_commands {
|
||||
return {
|
||||
rpower => 'nodehm:mgt=openbmc',
|
||||
};
|
||||
}
|
||||
|
||||
my %node_info = ();
|
||||
my $callback;
|
||||
|
||||
#-------------------------------------------------------
|
||||
|
||||
=head3 preprocess_request
|
||||
|
||||
preprocess the command
|
||||
|
||||
=cut
|
||||
|
||||
#-------------------------------------------------------
|
||||
sub preprocess_request {
|
||||
my $request = shift;
|
||||
$callback = shift;
|
||||
|
||||
# if $::OPENBMC_PYTHON is 'YES', will run this script
|
||||
if (ref($request->{environment}) eq 'ARRAY' and ref($request->{environment}->[0]->{XCAT_OPENBMC_PYTHON}) eq 'ARRAY') {
|
||||
$::OPENBMC_PYTHON = $request->{environment}->[0]->{XCAT_OPENBMC_PYTHON}->[0];
|
||||
} elsif (ref($request->{environment}) eq 'ARRAY') {
|
||||
$::OPENBMC_PYTHON = $request->{environment}->[0]->{XCAT_OPENBMC_PYTHON};
|
||||
} else {
|
||||
$::OPENBMC_PYTHON = $request->{environment}->{XCAT_OPENBMC_PYTHON};
|
||||
}
|
||||
|
||||
if (! (defined($::OPENBMC_PYTHON) and $::OPENBMC_PYTHON eq "YES")) {
|
||||
$request = {};
|
||||
return;
|
||||
}
|
||||
|
||||
my $command = $request->{command}->[0];
|
||||
my $noderange = $request->{node};
|
||||
my $extrargs = $request->{arg};
|
||||
my @exargs = ($request->{arg});
|
||||
my @requests;
|
||||
|
||||
if (ref($extrargs)) {
|
||||
@exargs = @$extrargs;
|
||||
}
|
||||
my $usage_string = xCAT::Usage->parseCommand($command, @exargs);
|
||||
if ($usage_string) {
|
||||
$callback->({ data => [$usage_string] });
|
||||
$request = {};
|
||||
return;
|
||||
}
|
||||
|
||||
my $parse_result = parse_args($command, $extrargs, $noderange);
|
||||
if (ref($parse_result) eq 'ARRAY') {
|
||||
my $error_data;
|
||||
foreach my $node (@$noderange) {
|
||||
$error_data .= "\n" if ($error_data);
|
||||
$error_data .= "$node: Error: " . "$parse_result->[1]";
|
||||
}
|
||||
$callback->({ errorcode => [$parse_result->[0]], data => [$error_data] });
|
||||
$request = {};
|
||||
return;
|
||||
}
|
||||
|
||||
my $sn = xCAT::ServiceNodeUtils->get_ServiceNode($noderange, "xcat", "MN");
|
||||
foreach my $snkey (keys %$sn) {
|
||||
my $reqcopy = {%$request};
|
||||
$reqcopy->{node} = $sn->{$snkey};
|
||||
$reqcopy->{'_xcatdest'} = $snkey;
|
||||
$reqcopy->{_xcatpreprocessed}->[0] = 1;
|
||||
push @requests, $reqcopy;
|
||||
}
|
||||
|
||||
return \@requests;
|
||||
}
|
||||
|
||||
#-------------------------------------------------------
|
||||
|
||||
=head3 process_request
|
||||
|
||||
Process the command
|
||||
|
||||
=cut
|
||||
|
||||
#-------------------------------------------------------
|
||||
sub process_request {
|
||||
my $request = shift;
|
||||
$callback = shift;
|
||||
my $noderange = $request->{node};
|
||||
my $check = parse_node_info($noderange);
|
||||
$callback->({ errorcode => [$check] }) if ($check);
|
||||
my $pid = xCAT::OPENBMC::start_python_agent();
|
||||
if (!defined($pid)) {
|
||||
xCAT::MsgUtils->message("E", { data => ["Failed to start python agent"] }, $callback);
|
||||
return;
|
||||
}
|
||||
|
||||
xCAT::OPENBMC::submit_agent_request($pid, $request, \%node_info, $callback);
|
||||
xCAT::OPENBMC::wait_agent($pid, $callback);
|
||||
}
|
||||
|
||||
#-------------------------------------------------------
|
||||
|
||||
=head3 parse_args
|
||||
|
||||
Parse the command line options and operands
|
||||
|
||||
=cut
|
||||
|
||||
#-------------------------------------------------------
|
||||
sub parse_args {
|
||||
my $command = shift;
|
||||
my $extrargs = shift;
|
||||
my $noderange = shift;
|
||||
my $subcommand = undef;
|
||||
|
||||
if (scalar(@ARGV) != 2 and ($command =~ /rpower/)) {
|
||||
return ([ 1, "Only one option is supported at the same time for $command" ]);
|
||||
} else {
|
||||
$subcommand = $ARGV[0];
|
||||
}
|
||||
|
||||
if ($command eq "rpower") {
|
||||
unless ($subcommand =~ /^on$|^off$|^softoff$|^reset$|^boot$|^bmcreboot$|^bmcstate$|^status$|^stat$|^state$/) {
|
||||
return ([ 1, "Unsupported command: $command $subcommand" ]);
|
||||
}
|
||||
} else {
|
||||
return ([ 1, "Unsupported command: $command" ]);
|
||||
}
|
||||
}
|
||||
|
||||
#-------------------------------------------------------
|
||||
|
||||
=head3 parse_node_info
|
||||
|
||||
Parse the node information: bmc, bmcip, username, password
|
||||
|
||||
=cut
|
||||
|
||||
#-------------------------------------------------------
|
||||
sub parse_node_info {
|
||||
my $noderange = shift;
|
||||
my $rst = 0;
|
||||
|
||||
my $passwd_table = xCAT::Table->new('passwd');
|
||||
my $passwd_hash = $passwd_table->getAttribs({ 'key' => 'openbmc' }, qw(username password));
|
||||
|
||||
my $openbmc_table = xCAT::Table->new('openbmc');
|
||||
my $openbmc_hash = $openbmc_table->getNodesAttribs(\@$noderange, ['bmc', 'username', 'password']);
|
||||
|
||||
foreach my $node (@$noderange) {
|
||||
if (defined($openbmc_hash->{$node}->[0])) {
|
||||
if ($openbmc_hash->{$node}->[0]->{'bmc'}) {
|
||||
$node_info{$node}{bmc} = $openbmc_hash->{$node}->[0]->{'bmc'};
|
||||
$node_info{$node}{bmcip} = xCAT::NetworkUtils::getNodeIPaddress($openbmc_hash->{$node}->[0]->{'bmc'});
|
||||
}
|
||||
unless($node_info{$node}{bmc}) {
|
||||
xCAT::SvrUtils::sendmsg("Error: Unable to get attribute bmc", $callback, $node);
|
||||
$rst = 1;
|
||||
next;
|
||||
}
|
||||
unless($node_info{$node}{bmcip}) {
|
||||
xCAT::SvrUtils::sendmsg("Error: Unable to resolve ip address for bmc: $node_info{$node}{bmc}", $callback, $node);
|
||||
delete $node_info{$node};
|
||||
$rst = 1;
|
||||
next;
|
||||
}
|
||||
if ($openbmc_hash->{$node}->[0]->{'username'}) {
|
||||
$node_info{$node}{username} = $openbmc_hash->{$node}->[0]->{'username'};
|
||||
} elsif ($passwd_hash and $passwd_hash->{username}) {
|
||||
$node_info{$node}{username} = $passwd_hash->{username};
|
||||
} else {
|
||||
xCAT::SvrUtils::sendmsg("Error: Unable to get attribute username", $callback, $node);
|
||||
delete $node_info{$node};
|
||||
$rst = 1;
|
||||
next;
|
||||
}
|
||||
|
||||
if ($openbmc_hash->{$node}->[0]->{'password'}) {
|
||||
$node_info{$node}{password} = $openbmc_hash->{$node}->[0]->{'password'};
|
||||
} elsif ($passwd_hash and $passwd_hash->{password}) {
|
||||
$node_info{$node}{password} = $passwd_hash->{password};
|
||||
} else {
|
||||
xCAT::SvrUtils::sendmsg("Error: Unable to get attribute password", $callback, $node);
|
||||
delete $node_info{$node};
|
||||
$rst = 1;
|
||||
next;
|
||||
}
|
||||
} else {
|
||||
xCAT::SvrUtils::sendmsg("Error: Unable to get information from openbmc table", $callback, $node);
|
||||
$rst = 1;
|
||||
next;
|
||||
}
|
||||
}
|
||||
|
||||
return $rst;
|
||||
}
|
||||
|
||||
1;
|
Loading…
x
Reference in New Issue
Block a user