mirror of
				https://github.com/xcat2/xcat-core.git
				synced 2025-10-31 19:32:31 +00:00 
			
		
		
		
	Add perl files of openbmc2
This commit is contained in:
		| @@ -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; | ||||
		Reference in New Issue
	
	Block a user