diff --git a/xCAT-server/lib/xcat/plugins/localrest.pm b/xCAT-server/lib/xcat/plugins/localrest.pm new file mode 100644 index 000000000..8474acad3 --- /dev/null +++ b/xCAT-server/lib/xcat/plugins/localrest.pm @@ -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; diff --git a/xCAT-server/sbin/xcatconfig b/xCAT-server/sbin/xcatconfig index 8d9d84b37..ac57971a6 100755 --- a/xCAT-server/sbin/xcatconfig +++ b/xCAT-server/sbin/xcatconfig @@ -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); diff --git a/xCAT-server/xCAT-wsapi/xcatws.cgi b/xCAT-server/xCAT-wsapi/xcatws.cgi index 54e3ca8a9..55a4adbed 100755 --- a/xCAT-server/xCAT-wsapi/xcatws.cgi +++ b/xCAT-server/xCAT-wsapi/xcatws.cgi @@ -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); }