mirror of
https://github.com/xcat2/xcat-core.git
synced 2025-08-22 11:10:24 +00:00
Merge pull request #1537 from chenglch/restservice
Add rest api helper interface to access non-xcat resource
This commit is contained in:
211
xCAT-server/lib/xcat/plugins/localrest.pm
Normal file
211
xCAT-server/lib/xcat/plugins/localrest.pm
Normal file
@@ -0,0 +1,211 @@
|
||||
# IBM(c) 2007 EPL license http://www.eclipse.org/legal/epl-v10.html
|
||||
#-------------------------------------------------------
|
||||
|
||||
=head1
|
||||
xCAT plugin package to non xcat resource
|
||||
|
||||
=cut
|
||||
|
||||
#-------------------------------------------------------
|
||||
package xCAT_plugin::localrest;
|
||||
|
||||
BEGIN {
|
||||
$::XCATROOT = $ENV{'XCATROOT'} ? $ENV{'XCATROOT'} : -d '/opt/xcat' ? '/opt/xcat' : '/usr';
|
||||
}
|
||||
use lib "$::XCATROOT/lib/perl";
|
||||
|
||||
use xCAT::Utils;
|
||||
use xCAT::MsgUtils;
|
||||
use File::Basename;
|
||||
use strict;
|
||||
|
||||
#-------------------------------------------------------
|
||||
|
||||
=head3 handled_commands
|
||||
|
||||
Return list of commands handled by this plugin
|
||||
|
||||
=cut
|
||||
|
||||
#-------------------------------------------------------
|
||||
|
||||
sub handled_commands
|
||||
{
|
||||
return {
|
||||
localrest => "localrest",
|
||||
};
|
||||
}
|
||||
|
||||
#-------------------------------------------------------
|
||||
|
||||
=head3 process_request
|
||||
|
||||
Process the command.
|
||||
|
||||
=cut
|
||||
|
||||
#-------------------------------------------------------
|
||||
sub process_request
|
||||
{
|
||||
my $request = shift;
|
||||
$::callback = shift;
|
||||
my $subreq = shift;
|
||||
my $command = $request->{command}->[0];
|
||||
|
||||
if ($command eq "localrest") {
|
||||
return handle_rest_request($request, $subreq);
|
||||
}
|
||||
}
|
||||
|
||||
#-------------------------------------------------------
|
||||
|
||||
=head3 handle_rest_request
|
||||
|
||||
This function check the command option, then call the
|
||||
related function to complete the request.
|
||||
|
||||
Usage example:
|
||||
This function is called from process_request,
|
||||
do not call it directly.
|
||||
=cut
|
||||
|
||||
#-------------------------------------------------------
|
||||
|
||||
sub handle_rest_request {
|
||||
my ($request, $subreq) = @_;
|
||||
my ($method, $resource, @params, $subroutine, $rsp, $rc);
|
||||
require JSON;
|
||||
my $JSON = JSON->new();
|
||||
|
||||
my @args = @{ $request->{arg} };
|
||||
if (scalar(@args) < 2) {
|
||||
$rsp->{data}->[0] = "Local rest api take at least two parameter.";
|
||||
xCAT::MsgUtils->message("E", $rsp, $::callback);
|
||||
return 1;
|
||||
}
|
||||
$method = shift @args;
|
||||
$resource = shift @args;
|
||||
$subroutine = $method . '_' . $resource;
|
||||
@params = @args;
|
||||
|
||||
# if related subroutine found, call it
|
||||
# subroutine for rest handler must return a ref to HASH or ARRAY
|
||||
# comtaining the data that should be return to the CGI
|
||||
if (__PACKAGE__->can({$subroutine})) {
|
||||
$rsp->{data}->[0] = "Unsupported request: $subroutine.";
|
||||
xCAT::MsgUtils->message("E", $rsp, $::callback);
|
||||
return 1;
|
||||
}
|
||||
no strict 'refs';
|
||||
my $result = $subroutine->(@params);
|
||||
|
||||
# handle the result from the rest subroutine
|
||||
if (ref($result) eq 'HASH') {
|
||||
if (defined($result->{'type'}) && $result->{'type'} eq 'stream'
|
||||
&& defined($result->{'filename'})) {
|
||||
$rsp->{data}->[0] = "stream";
|
||||
$rsp->{data}->[1] = $result->{'filename'};
|
||||
$rsp->{data}->[2] = $result->{'data'};
|
||||
} else {
|
||||
my $json = $JSON->encode($result);
|
||||
$rsp->{data}->[0] = "json";
|
||||
$rsp->{data}->[1] = $json;
|
||||
}
|
||||
xCAT::MsgUtils->message("I", $rsp, $::callback);
|
||||
$rc = 0;
|
||||
} elsif (ref($result) eq 'ARRAY') {
|
||||
my $json = $JSON->encode($result);
|
||||
$rsp->{data}->[0] = "json";
|
||||
$rsp->{data}->[1] = $json;
|
||||
xCAT::MsgUtils->message("I", $rsp, $::callback);
|
||||
$rc = 0;
|
||||
} elsif ($result == 1 || $result == 0) {
|
||||
$rc = $result;
|
||||
} else {
|
||||
$rc = 1;
|
||||
$rsp->{data}->[0] = "Internal error, result value is unacceptable";
|
||||
xCAT::MsgUtils->message("E", $rsp, $::callback);
|
||||
}
|
||||
return $rc;
|
||||
}
|
||||
|
||||
#-------------------------------------------------------
|
||||
|
||||
=head3 handler to list network adapters
|
||||
|
||||
Subroutine to handle rest request
|
||||
GET /localres/adapter/
|
||||
|
||||
Usage example:
|
||||
This function is called from handle_rest_request,
|
||||
do not call it directly.
|
||||
=cut
|
||||
|
||||
#-------------------------------------------------------
|
||||
sub list_adapter {
|
||||
my ($rsp, $result, $i);
|
||||
if (!opendir DIR, "/sys/class/net") {
|
||||
$rsp->{data}->[0] = "Unable open /sys/class/net dir.";
|
||||
xCAT::MsgUtils->message("E", $rsp, $::callback);
|
||||
return 1;
|
||||
}
|
||||
my @dir = readdir(DIR);
|
||||
closedir(DIR);
|
||||
$i = 0;
|
||||
foreach my $item (@dir) {
|
||||
if ($item eq '.' || $item eq '..') {
|
||||
next;
|
||||
}
|
||||
$result->[ $i++ ] = $item;
|
||||
}
|
||||
return $result;
|
||||
}
|
||||
|
||||
#-------------------------------------------------------
|
||||
|
||||
=head3 handler to download credential files
|
||||
|
||||
Subroutine to handle rest request
|
||||
GET /localres/credential/conserver/file
|
||||
GET /localres/credential/ca/file
|
||||
|
||||
Usage example:
|
||||
This function is called from handle_rest_request,
|
||||
do not call it directly.
|
||||
=cut
|
||||
|
||||
#-------------------------------------------------------
|
||||
sub download_credential {
|
||||
my @params = @_;
|
||||
my ($rsp, $buf, $fpath, $fd, $data, $result, $n);
|
||||
if (!@params) {
|
||||
$rsp->{data}->[0] = "Argmument error.";
|
||||
xCAT::MsgUtils->message("E", $rsp, $::callback);
|
||||
return 1;
|
||||
}
|
||||
my %filemap = (
|
||||
'conserver' => "/home/conserver/.xcat/client-cred.pem",
|
||||
'ca' => "/home/conserver/.xcat/ca.pem",
|
||||
);
|
||||
$fpath = $filemap{ $params[0] };
|
||||
if (!$fpath || !-e $fpath) {
|
||||
$rsp->{data}->[0] = "File resource for " . $params[0] . " unavailable.";
|
||||
xCAT::MsgUtils->message("E", $rsp, $::callback);
|
||||
return 1;
|
||||
}
|
||||
|
||||
if (!($n = open($fd, '<', $fpath))) {
|
||||
$rsp->{data}->[0] = "Coundn't open file $fpath.";
|
||||
xCAT::MsgUtils->message("E", $rsp, $::callback);
|
||||
return 1;
|
||||
}
|
||||
while ($n = read($fd, $buf, 8192)) {
|
||||
$data .= $buf;
|
||||
}
|
||||
close($fd);
|
||||
$result->{'type'} = 'stream';
|
||||
$result->{'filename'} = basename($fpath);
|
||||
$result->{'data'} = $data;
|
||||
return $result;
|
||||
}
|
||||
1;
|
@@ -448,12 +448,6 @@ if ($::INITIALINSTALL || $::FORCE || $::UPDATEINSTALL || $::genCredentials)
|
||||
}
|
||||
else
|
||||
{
|
||||
#since the xcatd service unit file is updated on xcat upgrade
|
||||
#"systemctl daemon-reload" need to be run to update the service unit
|
||||
if ($::UPDATEINSTALL){
|
||||
$xcmd="type systemctl >/dev/null 2>&1 && systemctl daemon-reload";
|
||||
xCAT::Utils->runcmd("$xcmd", 0);
|
||||
}
|
||||
#$xcmd = "/etc/init.d/xcatd restart";
|
||||
xCAT::Utils->restartservice("xcatd");
|
||||
}
|
||||
@@ -1507,8 +1501,30 @@ sub checkotherpkgs
|
||||
#-----------------------------------------------------------------------------
|
||||
|
||||
sub genCredentials
|
||||
|
||||
{
|
||||
my $add_user_func = sub {
|
||||
my $user = shift;
|
||||
my ($cmd, $outref, $rc);
|
||||
$rc = getgrnam($user);
|
||||
if (!$rc) {
|
||||
$cmd = "groupadd $user";
|
||||
$outref = xCAT::Utils->runcmd("$cmd", 0);
|
||||
if ($::RUNCMD_RC != 0) {
|
||||
xCAT::MsgUtils->message('E',"$cmd failed");
|
||||
return;
|
||||
}
|
||||
}
|
||||
$rc = getpwnam($user);
|
||||
if (!$rc) {
|
||||
$cmd = "useradd -g $user -s /bin/bash -d /home/$user -m $user";
|
||||
$outref = xCAT::Utils->runcmd("$cmd", 0);
|
||||
if ($::RUNCMD_RC != 0) {
|
||||
xCAT::MsgUtils->message('E',"$cmd failed");
|
||||
return;
|
||||
}
|
||||
}
|
||||
};
|
||||
|
||||
my $hname = `hostname`;
|
||||
chomp $hname;
|
||||
if ((!-d "/etc/xcat/ca") || $::FORCE || $::genCredentials)
|
||||
@@ -1616,6 +1632,24 @@ sub genCredentials
|
||||
}
|
||||
}
|
||||
|
||||
if ((!-r "/home/conserver/.xcat/client-key.pem") || $::FORCE || $::genCredentials)
|
||||
{
|
||||
$add_user_func->('conserver');
|
||||
my $cmd =
|
||||
"echo 'y\ny\ny\ny' |$::XCATROOT/share/xcat/scripts/setup-local-client.sh conserver";
|
||||
verbose("Running $cmd");
|
||||
my $rc = system($cmd);
|
||||
if ($rc >> 8)
|
||||
{
|
||||
xCAT::MsgUtils->message('E',
|
||||
"Could not create xCAT certificate in /home/conserver/.xcat/client-key.pem.");
|
||||
}
|
||||
else
|
||||
{
|
||||
xCAT::MsgUtils->message('I', "Created xCAT certificate.");
|
||||
}
|
||||
}
|
||||
|
||||
# copy to postscript directory
|
||||
$cmd = "/bin/rm -rf $::INSTALLDIR/postscripts/_xcat >/dev/null 2>&1";
|
||||
$outref = xCAT::Utils->runcmd("$cmd", 0);
|
||||
|
@@ -1230,6 +1230,24 @@ my %URIdef = (
|
||||
},
|
||||
},
|
||||
},
|
||||
|
||||
### interface to access local system resource which is not managed by xcat directly
|
||||
### localres can be looked as a top level non-xcat resource pool
|
||||
### rest operation will trasfer the target resource to xcatd plugin to handle the non-xcat resource
|
||||
localres => {
|
||||
localres => {
|
||||
desc => "[URI:/localres/*] - The local non-xcat resource.",
|
||||
matcher => '^/localres(/[^/]*)+$',
|
||||
GET => {
|
||||
desc => "List information for the target system resource.",
|
||||
usage => "||For target resource can match any resource type which can be proccssed by the resthelper plugin.|",
|
||||
example => qq(|List adapters on MN machine|GET|/localres/interface/|{\n \"interfaces\":[\n\"eth0\",\n \"eth1\",\n]"|),
|
||||
cmd => "localrest",
|
||||
fhandler => \&localreshdl,
|
||||
outhdler => \&localresout,
|
||||
},
|
||||
}
|
||||
}
|
||||
);
|
||||
|
||||
# supported formats
|
||||
@@ -1288,6 +1306,7 @@ my @path = split(/\//, $pathInfo); # The uri path like /nodes/node1/...
|
||||
|
||||
# Define the golbal variables which will be used through the handling process
|
||||
my $pageContent = ''; # Global var containing the ouptut back to the rest client
|
||||
my %header_info; #Global var containing the extra info to the http header
|
||||
my $request = {clienttype => 'ws'}; # Global var that holds the request to send to xcatd
|
||||
my $format = 'json'; # The output format for a request invoke
|
||||
my $xmlinstalled; # Global var to speicfy whether the xml modules have been loaded
|
||||
@@ -1649,6 +1668,17 @@ sub defout_remove_appended_info {
|
||||
}
|
||||
|
||||
|
||||
sub localresout {
|
||||
my $data = shift;
|
||||
my $json;
|
||||
if ($data->[0]->{info}->[0] eq 'stream') {
|
||||
$format = 'stream';
|
||||
$header_info{'attachment'} = $data->[0]->{info}->[1];
|
||||
addPageContent($data->[0]->{info}->[2]);
|
||||
} elsif ($data->[0]->{info}->[0] eq 'json') {
|
||||
addPageContent($data->[0]->{info}->[1]);
|
||||
}
|
||||
}
|
||||
|
||||
# hanlde the output which has the node irrelevant message (e.g. the output for updatenode command)
|
||||
# handle the input like
|
||||
@@ -2148,6 +2178,39 @@ sub actionhdl {
|
||||
return $responses;
|
||||
}
|
||||
|
||||
sub localreshdl {
|
||||
my $params = shift;
|
||||
my @args;
|
||||
my @urilayers = @{$params->{'layers'}};
|
||||
|
||||
# set the command name
|
||||
$request->{command} = $params->{'cmd'};
|
||||
|
||||
if (isGET() && scalar(@urilayers) > 1 && $urilayers[-1] eq "detail") {
|
||||
push @args, "show";
|
||||
} elsif (isGET() && scalar(@urilayers) > 1 && $urilayers[-1] eq "file") {
|
||||
push @args, "download";
|
||||
} elsif (isGET()) {
|
||||
push @args, "list";
|
||||
} elsif (isPost()) {
|
||||
push @args, "create";
|
||||
} elsif (isPut()) {
|
||||
push @args, "update";
|
||||
} elsif (isDelete()) {
|
||||
push @args, "delete";
|
||||
}
|
||||
shift @urilayers;
|
||||
foreach my $item (@urilayers) {
|
||||
push @args, $item if $item ne 'detail' && $item ne 'file';
|
||||
}
|
||||
push @{$request->{arg}}, @args;
|
||||
# localrest is single plugin handler, use sequntial to avoid of multi-level processes
|
||||
$request->{'sequential'}->[0] = 1;
|
||||
my $req = genRequest();
|
||||
my $responses = sendRequest($req);
|
||||
return $responses;
|
||||
}
|
||||
|
||||
# The operation callback subroutine for node irrelevant commands like makedns -n and makedhcp -n
|
||||
# assembe the xcat request, send it to xcatd and get response
|
||||
sub nonobjhdl {
|
||||
@@ -2965,11 +3028,22 @@ sub sendResponseMsg {
|
||||
elsif ('xml' eq $format) {
|
||||
$tempFormat = 'text/xml';
|
||||
}
|
||||
elsif ('stream' eq $format) {
|
||||
$tempFormat = 'application/octet-stream';
|
||||
}
|
||||
else {
|
||||
$tempFormat = 'text/html';
|
||||
}
|
||||
print $q->header(-status => $code, -type => $tempFormat);
|
||||
if ($pageContent) { $pageContent .= "\n"; } # if there is any content, append a newline
|
||||
|
||||
if ($header_info{attachment}) {
|
||||
print $q->header(-status => $code,
|
||||
-type => $tempFormat,
|
||||
-attachment => $header_info{attachment},
|
||||
-Content_length => length($pageContent));
|
||||
} else {
|
||||
print $q->header(-status => $code, -type => $tempFormat);
|
||||
if ($pageContent) { $pageContent .= "\n"; } # if there is any content, append a newline
|
||||
}
|
||||
print $pageContent;
|
||||
exit(0);
|
||||
}
|
||||
|
Reference in New Issue
Block a user