2
0
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:
zet809
2016-07-20 11:40:34 +08:00
committed by GitHub
3 changed files with 328 additions and 9 deletions

View 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;

View File

@@ -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);

View File

@@ -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);
}