5dbcb3dd65
git-svn-id: https://svn.code.sf.net/p/xcat/code/xcat-core/branches/2.8@15179 8638fb3e-16cb-4fca-ae20-7b5d299a9bcd
2113 lines
62 KiB
Perl
Executable File
2113 lines
62 KiB
Perl
Executable File
#!/usr/bin/perl
|
|
use strict;
|
|
use CGI qw/:standard/;
|
|
#use JSON; # require this dynamically later on so that installations that do not use xcatws.cgi do not need perl-JSON
|
|
use Data::Dumper;
|
|
|
|
#added the line:
|
|
#ScriptAlias /xcatws /var/www/cgi-bin/xcatws.cgi
|
|
#to /etc/httpd/conf/httpd.conf to hid the cgi-bin and .cgi extension in the uri
|
|
#
|
|
# also upgraded CGI to 3.52
|
|
|
|
#take the JSON or XML and put it into a data structure
|
|
#all data input will be done from the common structure
|
|
|
|
#turn on or off the debugging output
|
|
my $DEBUGGING = 0;
|
|
my $VERSION = "2.8";
|
|
|
|
my $q = CGI->new;
|
|
my $url = $q->url;
|
|
my $pathInfo = $q->path_info;
|
|
my $requestType = $ENV{'REQUEST_METHOD'};
|
|
my $queryString = $ENV{'QUERY_STRING'};
|
|
my %queryhash;
|
|
my @path = split(/\//, $pathInfo);
|
|
shift(@path);
|
|
my $resource = $path[0];
|
|
my $pageContent = '';
|
|
my $request = {clienttype => 'ws'};
|
|
|
|
#error status codes
|
|
my $STATUS_BAD_REQUEST = "400 Bad Request";
|
|
my $STATUS_UNAUTH = "401 Unauthorized";
|
|
my $STATUS_FORBIDDEN = "403 Forbidden";
|
|
my $STATUS_NOT_FOUND = "404 Not Found";
|
|
my $STATUS_NOT_ALLOWED = "405 Method Not Allowed";
|
|
my $STATUS_NOT_ACCEPTABLE = "406 Not Acceptable";
|
|
my $STATUS_TIMEOUT = "408 Request Timeout";
|
|
my $STATUS_EXPECT_FAILED = "417 Expectation Failed";
|
|
my $STATUS_TEAPOT = "418 I'm a teapot";
|
|
my $STATUS_SERVICE_UNAVAILABLE = "503 Service Unavailable";
|
|
|
|
#good status codes
|
|
my $STATUS_OK = "200 OK";
|
|
my $STATUS_CREATED = "201 Created";
|
|
|
|
#default format
|
|
my $format = 'html';
|
|
|
|
sub addPageContent {
|
|
my $newcontent = shift;
|
|
$pageContent .= $newcontent;
|
|
}
|
|
|
|
#send the response to client side
|
|
#the http only return once in each request, so all content shoudl save in a global variable,
|
|
#create the response header by status
|
|
sub sendResponseMsg {
|
|
my $code = shift;
|
|
my $tempFormat = '';
|
|
if ('json' eq $format) {
|
|
$tempFormat = 'application/json';
|
|
}
|
|
elsif ('xml' eq $format) {
|
|
$tempFormat = 'text/xml';
|
|
}
|
|
else {
|
|
$tempFormat = 'text/html';
|
|
}
|
|
print $q->header(-status => $code, -type => $tempFormat);
|
|
print $pageContent;
|
|
exit(0);
|
|
}
|
|
|
|
sub unsupportedRequestType {
|
|
addPageContent("request method '$requestType' is not supported on resource '$resource'");
|
|
sendResponseMsg($STATUS_NOT_ALLOWED);
|
|
}
|
|
|
|
use XML::Simple;
|
|
$XML::Simple::PREFERRED_PARSER = 'XML::Parser';
|
|
|
|
sub genRequest {
|
|
if ($DEBUGGING) {
|
|
addPageContent($q->p("request " . Dumper($request)));
|
|
}
|
|
my $xml = XMLout($request, RootName => 'xcatrequest', NoAttr => 1, KeyAttr => []);
|
|
}
|
|
|
|
#data formatters. To add one simple copy the format of an existing one
|
|
# and add it to this hash
|
|
my %formatters = (
|
|
'html' => \&wrapHtml,
|
|
'json' => \&wrapJson,
|
|
'xml' => \&wrapXml,);
|
|
|
|
fetchParameter($queryString);
|
|
|
|
if ($queryhash{'format'}) {
|
|
$format = $queryhash{'format'}->[0];
|
|
if (!exists $formatters{$format}) {
|
|
addPageContent("The format '$format' is not valid");
|
|
sendResponseMsg($STATUS_BAD_REQUEST);
|
|
}
|
|
|
|
if ($format eq 'json') {
|
|
# require JSON dynamically and let them know if it is not installed
|
|
my $jsoninstalled = eval { require JSON; };
|
|
unless ($jsoninstalled) {
|
|
addPageContent('{"data":"JSON perl module missing. Install perl-JSON before using the xCAT REST web services API."}');
|
|
sendResponseMsg($STATUS_SERVICE_UNAVAILABLE);
|
|
}
|
|
}
|
|
}
|
|
|
|
my $XCAT_PATH = '/opt/xcat/bin';
|
|
|
|
#resource handlers
|
|
my %resources = (
|
|
groups => \&groupsHandler,
|
|
images => \&imagesHandler,
|
|
logs => \&logsHandler,
|
|
monitors => \&monitorsHandler,
|
|
networks => \&networksHandler,
|
|
nodes => \&nodesHandler,
|
|
notifications => \¬ificationsHandler,
|
|
policies => \&policiesHandler,
|
|
site => \&siteHandler,
|
|
tables => \&tablesHandler,
|
|
accounts => \&accountsHandler,
|
|
objects => \&objectsHandler,
|
|
vms => \&vmsHandler,
|
|
version => \&versionHandler);
|
|
|
|
#if no resource was specified
|
|
if ($pathInfo =~ /^\/$/ || $pathInfo =~ /^$/) {
|
|
addPageContent($q->p("This is the root page for the xCAT Rest Web Service. Available resources are:"));
|
|
foreach (sort keys %resources) {
|
|
addPageContent($q->p($_));
|
|
}
|
|
sendResponseMsg($STATUS_OK);
|
|
}
|
|
|
|
sub doesResourceExist {
|
|
my $res = shift;
|
|
return exists $resources{$res};
|
|
}
|
|
|
|
if ($DEBUGGING) {
|
|
if (defined $q->param('PUTDATA')) {
|
|
addPageContent("put data " . $q->p($q->param('PUTDATA') . "\n"));
|
|
}
|
|
if (defined $q->param('POSTDATA')) {
|
|
addPageContent("post data " . $q->p($q->param('POSTDATA') . "\n"));
|
|
}
|
|
addPageContent($q->p("Parameters "));
|
|
my @params = $q->param;
|
|
foreach (@params) {
|
|
addPageContent("$_ = " . join(',', $q->param($_)) . "\n");
|
|
}
|
|
addPageContent($q->p("Query String $queryString" . "\n"));
|
|
addPageContent($q->p("Query parameters from the Query String" . Dumper(\%queryhash) . "\n"));
|
|
addPageContent($q->p("HTTP Method $requestType" . "\n"));
|
|
addPageContent($q->p("URI $url" . "\n"));
|
|
addPageContent($q->p("path " . Dumper(@path) . "\n"));
|
|
}
|
|
|
|
#when use put and post, can not fetch the url-parameter, so add this sub to support all kinks of method
|
|
sub fetchParameter {
|
|
my $parstr = shift;
|
|
unless ($parstr) {
|
|
return;
|
|
}
|
|
|
|
my @pairs = split(/&/, $parstr);
|
|
foreach my $pair (@pairs) {
|
|
my ($key, $value) = split(/=/, $pair, 2);
|
|
$value =~ tr/+/ /;
|
|
$value =~ s/%([a-fA-F0-9][a-fA-F0-9])/chr(hex($1))/eg;
|
|
push @{$queryhash{$key}}, $value;
|
|
}
|
|
}
|
|
|
|
#extract the put data or post data into perl hash, easy for retrieve
|
|
sub extractData {
|
|
my $temphash = shift;
|
|
my $parArray = shift;
|
|
my $key;
|
|
my $value;
|
|
my $position;
|
|
|
|
#traversal all element in the array
|
|
foreach (@$parArray) {
|
|
$position = index($_, '=');
|
|
if ($position < 0) {
|
|
$key = $_;
|
|
$value = 1;
|
|
}
|
|
else {
|
|
$key = substr $_, 0, $position;
|
|
$value = substr $_, $position + 1;
|
|
}
|
|
$temphash->{$key} = $value;
|
|
|
|
if ($DEBUGGING) {
|
|
addPageContent($q->p("The parameter extract from put/post data:<br/>" . Dumper($temphash)));
|
|
}
|
|
}
|
|
}
|
|
|
|
my $userName=http('userName');
|
|
my $password=http('password');
|
|
|
|
sub handleRequest {
|
|
if (defined $queryhash{'userName'}) {
|
|
$userName = $queryhash{'userName'}->[0];
|
|
}
|
|
if (defined $queryhash{'password'}) {
|
|
$password = $queryhash{'password'}->[0];
|
|
}
|
|
if ($userName && $password) {
|
|
$request->{becomeuser}->[0]->{username}->[0] = $userName;
|
|
$request->{becomeuser}->[0]->{password}->[0] = $password;
|
|
}
|
|
my @data = $resources{$resource}->();
|
|
wrapData(\@data);
|
|
}
|
|
|
|
my @groupFields = ('groupname', 'grouptype', 'members', 'wherevals', 'comments', 'disable');
|
|
|
|
#get is done
|
|
#post and delete are done but not tested
|
|
#groupfiles4dsh is done but not tested
|
|
sub groupsHandler {
|
|
my @responses;
|
|
my @args;
|
|
my $groupName;
|
|
|
|
#is the group name in the URI?
|
|
if (defined $path[1]) {
|
|
$groupName = $path[1];
|
|
}
|
|
|
|
#in the query string?
|
|
else {
|
|
$groupName = $q->param('groupName');
|
|
}
|
|
|
|
if (isGet()) {
|
|
if (defined $groupName) {
|
|
$request->{command} = 'tabget';
|
|
push @args, "groupname=$groupName";
|
|
if (defined $q->param('field')) {
|
|
foreach ($q->param('field')) {
|
|
push @args, "nodegroup.$_";
|
|
}
|
|
}
|
|
else {
|
|
foreach (@groupFields) {
|
|
push @args, "nodegroup.$_";
|
|
}
|
|
}
|
|
}
|
|
else {
|
|
$request->{command} = 'tabdump';
|
|
push @args, 'nodegroup';
|
|
}
|
|
}
|
|
|
|
#does it make sense to even have this?
|
|
elsif (isPost()) {
|
|
my $nodeRange = $q->param('nodeRange');
|
|
if ((defined $groupName) && (defined $nodeRange)) {
|
|
$request->{command} = 'mkdef';
|
|
push @args, '-t';
|
|
push @args, 'group';
|
|
push @args, '-o';
|
|
push @args, $groupName;
|
|
push @args, "members=$nodeRange";
|
|
}
|
|
else {
|
|
addPageContent("A node range and group name must be specified for creating a group");
|
|
sendResponseMsg($STATUS_BAD_REQUEST);
|
|
}
|
|
}
|
|
elsif (isPut()) {
|
|
|
|
#handle groupfiles4dsh -p /tmp/nodegroupfiles
|
|
if ($q->param('command') eq "4dsh") {
|
|
if ($q->param('path')) {
|
|
$request->{command} = 'groupfiles4dsh';
|
|
push @args, "p=$q->param('path')";
|
|
}
|
|
else {
|
|
addPageContent("The path must be specified for creating directories for dsh");
|
|
sendResponseMsg($STATUS_BAD_REQUEST);
|
|
}
|
|
}
|
|
else {
|
|
if (defined $groupName && defined $q->param('fields')) {
|
|
$request->{command} = 'nodegrpch';
|
|
push @args, $groupName;
|
|
push @args, $q->param('field');
|
|
}
|
|
else {
|
|
addPageContent("The group and fields must be specified to update groups");
|
|
sendResponseMsg($STATUS_BAD_REQUEST);
|
|
}
|
|
}
|
|
}
|
|
elsif (isDelete()) {
|
|
if (defined $groupName) {
|
|
$request->{command} = 'rmdef';
|
|
push @args, '-d';
|
|
push @args, 'group';
|
|
push @args, '-o';
|
|
push @args, $groupName;
|
|
}
|
|
else {
|
|
addPageContent("The group must be specified to delete a group");
|
|
sendResponseMsg($STATUS_BAD_REQUEST);
|
|
}
|
|
}
|
|
else {
|
|
unsupportedRequestType();
|
|
exit();
|
|
}
|
|
|
|
push @{$request->{arg}}, @args;
|
|
my $req = genRequest();
|
|
@responses = sendRequest($req);
|
|
|
|
return @responses;
|
|
}
|
|
|
|
my @imageFields = (
|
|
'imagename', 'profile', 'imagetype', 'provmethod', 'osname', 'osvers',
|
|
'osdistro', 'osarch', 'synclists', 'comments', 'disable');
|
|
|
|
#get is done, nothing else
|
|
sub imagesHandler {
|
|
my @responses;
|
|
my @args;
|
|
my $image;
|
|
my $subResource;
|
|
|
|
if (defined($path[1])) {
|
|
$image = $path[1];
|
|
}
|
|
|
|
if (isGet()) {
|
|
$request->{command} = 'lsdef';
|
|
push @args, '-t', 'osimage';
|
|
if (defined $image) {
|
|
push @args, '-o', $image;
|
|
}
|
|
if (defined($q->param('field'))) {
|
|
push @args, '-i';
|
|
push @args, join(',', $q->param('field'));
|
|
}
|
|
}
|
|
elsif (isPost()) {
|
|
my $operationname = $image;
|
|
my $entries;
|
|
my %entryhash;
|
|
|
|
#check the post data
|
|
unless (defined($q->param('POSTDATA'))) {
|
|
addPageContent("Invalid Parameters");
|
|
sendResponseMsg($STATUS_BAD_REQUEST);
|
|
}
|
|
$entries = JSON::decode_json($q->param('POSTDATA'));
|
|
if (scalar(@$entries) < 1) {
|
|
addPageContent("No set attribute was supplied.");
|
|
sendResponseMsg($STATUS_BAD_REQUEST);
|
|
}
|
|
|
|
extractData(\%entryhash, $entries);
|
|
|
|
#for image capture
|
|
if ($operationname eq 'capture') {
|
|
$request->{command} = 'imgcapture';
|
|
if (defined($entryhash{'nodename'})) {
|
|
$request->{noderange} = $entryhash{'nodename'};
|
|
}
|
|
else {
|
|
addPageContent('No node range.');
|
|
sendResponseMsg($STATUS_BAD_REQUEST);
|
|
}
|
|
|
|
if (defined($entryhash{'profile'})) {
|
|
push @args, '-p';
|
|
push @args, $entryhash{'profile'};
|
|
}
|
|
if (defined($entryhash{'osimage'})) {
|
|
push @args, '-o';
|
|
push @args, $entryhash{'osimage'};
|
|
}
|
|
if (defined($entryhash{'bootinterface'})) {
|
|
push @args, '-i';
|
|
push @args, $entryhash{'bootinterface'};
|
|
}
|
|
if (defined($entryhash{'netdriver'})) {
|
|
push @args, '-n';
|
|
push @args, $entryhash{'netdriver'};
|
|
}
|
|
}
|
|
}
|
|
elsif (isPut()) {
|
|
|
|
#check the operation type
|
|
unless (defined $path[2]) {
|
|
addPageContent("The subResource $subResource does not exist");
|
|
sendResponseMsg($STATUS_BAD_REQUEST);
|
|
}
|
|
|
|
$subResource = $path[2];
|
|
|
|
#check the image name
|
|
unless (defined $image) {
|
|
addPageContent("The image name is required to clean an os image");
|
|
sendResponseMsg($STATUS_BAD_REQUEST);
|
|
}
|
|
|
|
if ($subResource eq 'check') {
|
|
$request->{command} = 'chkosimage';
|
|
if (defined($q->param('PUTDATA'))) {
|
|
push @args, '-c';
|
|
}
|
|
push @args, $image;
|
|
}
|
|
else {
|
|
addPageContent("The subResource $subResource does not exist");
|
|
sendResponseMsg($STATUS_BAD_REQUEST);
|
|
}
|
|
}
|
|
elsif (isDelete()) {
|
|
if (defined $image) {
|
|
$request->{command} = 'rmimage';
|
|
if (defined $q->param('verbose')) {
|
|
push @args, '-v';
|
|
}
|
|
push @args, $image;
|
|
}
|
|
elsif (defined $q->param('os') && defined $q->param('arch') && defined $q->param('profile')) {
|
|
push @args, '-o';
|
|
push @args, $q->param('os');
|
|
push @args, '-a';
|
|
push @args, $q->param('arch');
|
|
push @args, '-p';
|
|
push @args, $q->param('profile');
|
|
}
|
|
else {
|
|
addPageContent(
|
|
"Either the image name or the os, architecture and profile must be specified to remove an image");
|
|
sendResponseMsg($STATUS_BAD_REQUEST);
|
|
}
|
|
}
|
|
else {
|
|
unsupportedRequestType();
|
|
exit();
|
|
}
|
|
|
|
push @{$request->{arg}}, @args;
|
|
my $req = genRequest();
|
|
@responses = sendRequest($req);
|
|
|
|
return @responses;
|
|
}
|
|
|
|
#complete
|
|
sub logsHandler {
|
|
my @responses;
|
|
my @args;
|
|
my $logType;
|
|
|
|
if (defined $path[1]) {
|
|
$logType = $path[1];
|
|
}
|
|
|
|
#in the query string?
|
|
else {
|
|
$logType = $q->param('logType');
|
|
}
|
|
my $nodeRange = $q->param('nodeRange');
|
|
|
|
#no real output unless the log type is defined
|
|
if (!defined $logType) {
|
|
addPageContent("Current logs available are auditlog and eventlog");
|
|
sendResponseMsg($STATUS_BAD_REQUEST);
|
|
exit(0);
|
|
}
|
|
|
|
if (isGet()) {
|
|
if ($logType eq "reventLog") {
|
|
if (defined $nodeRange) {
|
|
$request->{command} = 'reventlog';
|
|
push @args, $nodeRange;
|
|
if (defined $q->param('count')) {
|
|
push @args, $q->param('count');
|
|
}
|
|
}
|
|
else {
|
|
addPageContent("nodeRange must be specified to GET remote event logs");
|
|
sendResponseMsg($STATUS_BAD_REQUEST);
|
|
}
|
|
}
|
|
else {
|
|
$request->{command} = 'tabdump';
|
|
push @args, $logType;
|
|
}
|
|
}
|
|
|
|
#this clears the log
|
|
elsif (isPut()) {
|
|
if ($logType eq "reventlog") {
|
|
if (defined $nodeRange) {
|
|
$request->{command} = 'reventlog';
|
|
push @args, $nodeRange;
|
|
push @args, 'clear';
|
|
}
|
|
else {
|
|
addPageContent("nodeRange must be specified to clean remote event logs");
|
|
sendResponseMsg($STATUS_BAD_REQUEST);
|
|
}
|
|
}
|
|
else {
|
|
|
|
#should it return the removed entries?
|
|
if (defined $q->param('showRemoved')) {
|
|
push @args, '-V';
|
|
}
|
|
if (defined $q->param('count') || defined $q->param('percent') || defined $q->param('lastRecord')) {
|
|
|
|
#remove some of the entries
|
|
$request->{command} = 'tabprune';
|
|
|
|
#remove a certain number of records
|
|
if (defined $q->param('count')) {
|
|
push @args, ('-n', $q->param('count'));
|
|
}
|
|
|
|
#remove a percentage of the records
|
|
if (defined $q->param('percent')) {
|
|
push @args, ('-p', $q->param('percent'));
|
|
}
|
|
|
|
#remove all records before this record
|
|
if (defined $q->param('lastRecord')) {
|
|
push @args, ('-i', $q->param('lastRecord'));
|
|
}
|
|
}
|
|
else {
|
|
$request->{command} = 'tabprune';
|
|
|
|
#-a removes all
|
|
push @args, '-a';
|
|
}
|
|
}
|
|
}
|
|
else {
|
|
unsupportedRequestType();
|
|
exit();
|
|
}
|
|
|
|
push @{$request->{arg}}, @args;
|
|
my $req = genRequest();
|
|
@responses = sendRequest($req);
|
|
|
|
return @responses;
|
|
}
|
|
|
|
#complete
|
|
sub monitorsHandler {
|
|
my @responses;
|
|
my @args;
|
|
my $monitor;
|
|
|
|
if (defined $path[1]) {
|
|
$monitor = $path[1];
|
|
}
|
|
|
|
#in the query string?
|
|
elsif (defined $q->param('monitor')) {
|
|
push @args, $q->param('monitor');
|
|
}
|
|
if (defined $monitor) {
|
|
push @args, $monitor;
|
|
}
|
|
|
|
if (isGet()) {
|
|
$request->{command} = 'monls';
|
|
}
|
|
elsif (isPost()) {
|
|
$request->{command} = 'monadd';
|
|
if ($q->param('nodeStatMon')) {
|
|
push @args, '-n';
|
|
}
|
|
|
|
#get the plug-in specific settings array
|
|
foreach ($q->param('pluginSetting')) {
|
|
push @args, '-s';
|
|
push @args, $_;
|
|
}
|
|
}
|
|
elsif (isDelete()) {
|
|
$request->{command} = 'monrm';
|
|
}
|
|
elsif (isPut() || isPatch()) {
|
|
my $action = $q->param('action');
|
|
if ($action eq "start") {
|
|
$request->{command} = 'monstart';
|
|
}
|
|
elsif ($action eq "stop") {
|
|
$request->{command} = 'monstop';
|
|
}
|
|
elsif ($action eq "config") {
|
|
$request->{command} = 'moncfg';
|
|
}
|
|
elsif ($action eq "deconfig") {
|
|
$request->{command} = 'mondeconfig';
|
|
}
|
|
else {
|
|
unsupportedRequestType();
|
|
}
|
|
if (!defined $q->param('nodeRange')) {
|
|
|
|
#error
|
|
}
|
|
else {
|
|
push @args, $q->param('nodeRange');
|
|
}
|
|
if (defined $q->param('remote')) {
|
|
push @args, '-r';
|
|
}
|
|
}
|
|
else {
|
|
unsupportedRequestType();
|
|
exit();
|
|
}
|
|
|
|
push @{$request->{arg}}, @args;
|
|
my $req = genRequest();
|
|
@responses = sendRequest($req);
|
|
|
|
return @responses;
|
|
}
|
|
|
|
sub networksHandler {
|
|
my @responses;
|
|
my @args;
|
|
my $netname = '';
|
|
|
|
if (isGet()) {
|
|
$request->{command} = 'lsdef';
|
|
push @{$request->{arg}}, '-t', 'network';
|
|
if (defined($path[1])) {
|
|
push @{$request->{arg}}, '-o', $path[1];
|
|
}
|
|
my @temparray = $q->param('field');
|
|
|
|
#add the field name to get
|
|
if (scalar(@temparray) > 0) {
|
|
push @{$request->{arg}}, '-i';
|
|
push @{$request->{arg}}, join(',', @temparray),;
|
|
}
|
|
}
|
|
elsif (isPut() || isPost()) {
|
|
my $entries;
|
|
if (isPut()) {
|
|
$request->{command} = 'chdef';
|
|
}
|
|
else {
|
|
$request->{command} = 'mkdef';
|
|
}
|
|
|
|
if (defined $path[1]) {
|
|
$netname = $path[1];
|
|
}
|
|
|
|
if ($netname eq '') {
|
|
addPageContent('A network name must be specified.');
|
|
sendResponseMsg($STATUS_BAD_REQUEST);
|
|
}
|
|
|
|
push @{$request->{arg}}, '-t', 'network', '-o', $netname;
|
|
if (defined($q->param('PUTDATA'))) {
|
|
$entries = JSON::decode_json($q->param('PUTDATA'));
|
|
}
|
|
elsif (defined($q->param('POSTDATA'))) {
|
|
$entries = JSON::decode_json($q->param('PUTDATA'));
|
|
}
|
|
else {
|
|
addPageContent("No Field and Value map was supplied.");
|
|
sendResponseMsg($STATUS_BAD_REQUEST);
|
|
}
|
|
|
|
if (scalar($entries) < 1) {
|
|
addPageContent("No Field and Value map was supplied.");
|
|
sendResponseMsg($STATUS_BAD_REQUEST);
|
|
}
|
|
foreach (@$entries) {
|
|
push @{$request->{arg}}, $_;
|
|
}
|
|
}
|
|
elsif (isDelete()) {
|
|
$request->{command} = 'rmdef';
|
|
|
|
if (defined $path[1]) {
|
|
$netname = $path[1];
|
|
}
|
|
if ($netname eq '') {
|
|
addPageContent('A network name must be specified.');
|
|
sendResponseMsg($STATUS_BAD_REQUEST);
|
|
}
|
|
push @{$request->{arg}}, '-t', 'network', '-o', $netname;
|
|
}
|
|
else {
|
|
unsupportedRequestType();
|
|
exit(0);
|
|
}
|
|
@responses = sendRequest(genRequest());
|
|
|
|
return @responses;
|
|
}
|
|
|
|
sub nodesHandler {
|
|
my @responses;
|
|
my @args;
|
|
my $noderange;
|
|
|
|
if (defined $path[1]) {
|
|
$noderange = $path[1];
|
|
}
|
|
|
|
if (isGet()) {
|
|
my $subResource;
|
|
if (defined $path[2]) {
|
|
$subResource = $path[2];
|
|
unless (defined($noderange)) {
|
|
addPageContent("Invalid nodes and/or groups in noderange");
|
|
sendResponseMsg($STATUS_BAD_REQUEST);
|
|
}
|
|
$request->{noderange} = $noderange;
|
|
|
|
#use the corresponding command by the subresource name
|
|
if ($subResource eq "power") {
|
|
$request->{command} = 'rpower';
|
|
push @args, 'stat';
|
|
}
|
|
elsif ($subResource eq "energy") {
|
|
$request->{command} = 'renergy';
|
|
|
|
#no fields will default to 'all'
|
|
if (defined $q->param('field')) {
|
|
push @args, $q->param('field');
|
|
}
|
|
else {
|
|
push @args, 'all';
|
|
}
|
|
}
|
|
elsif ($subResource eq "status") {
|
|
$request->{command} = 'nodestat';
|
|
}
|
|
elsif ($subResource eq "inventory") {
|
|
$request->{command} = 'rinv';
|
|
if (defined $q->param('field')) {
|
|
push @args, $q->param('field');
|
|
}
|
|
else {
|
|
push @args, 'all';
|
|
}
|
|
}
|
|
elsif ($subResource eq "vitals") {
|
|
$request->{command} = 'rvitals';
|
|
if (defined $q->param('field')) {
|
|
push @args, $q->param('field');
|
|
}
|
|
else {
|
|
push @args, 'all';
|
|
}
|
|
}
|
|
else {
|
|
addPageContent("Unspported operation on nodes object.");
|
|
sendResponseMsg($STATUS_BAD_REQUEST);
|
|
}
|
|
}
|
|
else {
|
|
$request->{command} = 'lsdef';
|
|
push @args, "-t", "node";
|
|
|
|
#add the nodegroup into args
|
|
if (defined($noderange)) {
|
|
push @args, "-o", $noderange;
|
|
}
|
|
|
|
#maybe it's specified in the parameters
|
|
my @temparray = $q->param('field');
|
|
if (scalar(@temparray) > 0) {
|
|
push @args, "-i";
|
|
push @args, join(',', @temparray);
|
|
}
|
|
}
|
|
}
|
|
elsif (isPut()) {
|
|
my $subResource;
|
|
my @entries;
|
|
if (defined $path[2]) {
|
|
$subResource = $path[2];
|
|
|
|
unless (defined($noderange)) {
|
|
addPageContent("Invalid nodes and/or groups in noderange");
|
|
sendResponseMsg($STATUS_BAD_REQUEST);
|
|
}
|
|
$request->{noderange} = $noderange;
|
|
|
|
unless ($q->param('PUTDATA')) {
|
|
#temporary allowance for the put data to be contained in the queryString
|
|
unless ($queryhash{'putData'}) {
|
|
addPageContent("No set attribute was supplied.");
|
|
sendResponseMsg($STATUS_BAD_REQUEST);
|
|
}
|
|
else {
|
|
foreach my $put (@{$queryhash{'putData'}}) {
|
|
my ($key, $value) = split(/=/, $put, 2);
|
|
if ($key eq 'field' && $value) {
|
|
push @entries, $value;
|
|
}
|
|
}
|
|
}
|
|
|
|
|
|
}
|
|
else {
|
|
@entries = JSON::decode_json($q->param('PUTDATA'));
|
|
if (scalar(@entries) < 1) {
|
|
addPageContent("No set attribute was supplied.");
|
|
sendResponseMsg($STATUS_BAD_REQUEST);
|
|
}
|
|
}
|
|
|
|
if (($subResource ne "dsh") && ($subResource ne "dcp")) {
|
|
foreach (@entries) {
|
|
push @args, $_;
|
|
}
|
|
}
|
|
if ($subResource eq "power") {
|
|
$request->{command} = "rpower";
|
|
}
|
|
elsif ($subResource eq "energy") {
|
|
$request->{command} = "renergy";
|
|
}
|
|
elsif ($subResource eq "bootstat") {
|
|
$request->{command} = "nodeset";
|
|
}
|
|
elsif ($subResource eq "bootseq") {
|
|
$request->{command} = "rbootseq";
|
|
}
|
|
elsif ($subResource eq "setboot") {
|
|
$request->{command} = "rsetboot";
|
|
}
|
|
elsif ($subResource eq "dsh") {
|
|
$request->{command} = "xdsh";
|
|
my %elements;
|
|
extractData(\%elements, @entries);
|
|
if (defined($elements{'devicetype'})) {
|
|
push @args, '--devicetype';
|
|
push @args, $elements{'devicetype'};
|
|
}
|
|
if (defined($elements{'execute'})) {
|
|
push @args, '-e';
|
|
}
|
|
if (defined($elements{'environment'})) {
|
|
push @args, '-E';
|
|
push @args, $elements{'environment'};
|
|
}
|
|
if (defined($elements{'fanout'})) {
|
|
push @args, '-f';
|
|
push @args, $elements{'fanout'};
|
|
}
|
|
if (defined($elements{'nolocale'})) {
|
|
push @args, '-L';
|
|
}
|
|
if (defined($elements{'userid'})) {
|
|
push @args, '-l';
|
|
push @args, $elements{'userid'};
|
|
}
|
|
if (defined($elements{'monitor'})) {
|
|
push @args, '-m';
|
|
}
|
|
if (defined($elements{'options'})) {
|
|
push @args, '-o';
|
|
push @args, $elements{'options'};
|
|
}
|
|
if (defined($elements{'showconfig'})) {
|
|
push @args, '-q';
|
|
}
|
|
if (defined($elements{'silent'})) {
|
|
push @args, '-Q';
|
|
}
|
|
if (defined($elements{'remoteshell'})) {
|
|
push @args, '-r';
|
|
push @args, $elements{'remoteshell'};
|
|
}
|
|
if (defined($elements{'syntax'})) {
|
|
push @args, '-S';
|
|
push @args, $elements{'syntax'};
|
|
}
|
|
if (defined($elements{'timeout'})) {
|
|
push @args, '-t';
|
|
push @args, $elements{'timeout'};
|
|
}
|
|
if (defined($elements{'envlist'})) {
|
|
push @args, '-X';
|
|
push @args, $elements{'envlist'};
|
|
}
|
|
if (defined($elements{'sshsetup'})) {
|
|
push @args, '-K';
|
|
push @args, $elements{'sshsetup'};
|
|
}
|
|
if (defined($elements{'rootimg'})) {
|
|
push @args, '-i';
|
|
push @args, $elements{'rootimg'};
|
|
}
|
|
if (defined($elements{'command'})) {
|
|
push @args, $elements{'command'};
|
|
}
|
|
}
|
|
elsif ($subResource eq "dcp") {
|
|
$request->{command} = "xdcp";
|
|
my %elements;
|
|
extractData(\%elements, @entries);
|
|
if (defined($elements{'fanout'})) {
|
|
push @args, '-f';
|
|
push @args, $elements{'fanout'};
|
|
}
|
|
if (defined($elements{'rootimg'})) {
|
|
push @args, '-i';
|
|
push @args, $elements{'rootimg'};
|
|
}
|
|
if (defined($elements{'options'})) {
|
|
push @args, '-o';
|
|
push @args, $elements{'options'};
|
|
}
|
|
if (defined($elements{'rsyncfile'})) {
|
|
push @args, '-F';
|
|
push @args, $elements{'rsyncfile'};
|
|
}
|
|
if (defined($elements{'preserve'})) {
|
|
push @args, '-p';
|
|
}
|
|
if (defined($elements{'pull'})) {
|
|
push @args, '-P';
|
|
}
|
|
if (defined($elements{'showconfig'})) {
|
|
push @args, '-q';
|
|
}
|
|
if (defined($elements{'remotecopy'})) {
|
|
push @args, '-r';
|
|
push @args, $elements{'remotecopy'};
|
|
}
|
|
if (defined($elements{'recursive'})) {
|
|
push @args, '-R';
|
|
}
|
|
if (defined($elements{'timeout'})) {
|
|
push @args, '-t';
|
|
push @args, $elements{'timeout'};
|
|
}
|
|
if (defined($elements{'source'})) {
|
|
push @args, $elements{'source'};
|
|
}
|
|
if (defined($elements{'target'})) {
|
|
push @args, $elements{'target'};
|
|
}
|
|
}
|
|
}
|
|
else {
|
|
#sendErrorMessage($STATUS_BAD_REQUEST, "The subResource \'$request->{subResource}\' does not exist");
|
|
sendResponseMsg($STATUS_BAD_REQUEST, "The subResource \'$request->{subResource}\' does not exist");
|
|
}
|
|
}
|
|
elsif (isPost()) {
|
|
$request->{command} = 'mkdef';
|
|
push @args, "-t", "node";
|
|
|
|
unless (defined($noderange)) {
|
|
addPageContent("No nodename was supplied.");
|
|
sendResponseMsg($STATUS_BAD_REQUEST);
|
|
}
|
|
|
|
push @args, "-o", $noderange;
|
|
|
|
if ($q->param('POSTDATA')) {
|
|
my $entries = JSON::decode_json($q->param('POSTDATA'));
|
|
if (scalar($entries) < 1) {
|
|
addPageContent("No Field and Value map was supplied.");
|
|
sendResponseMsg($STATUS_BAD_REQUEST);
|
|
}
|
|
foreach (@$entries) {
|
|
push @args, $_;
|
|
}
|
|
}
|
|
}
|
|
elsif (isDelete()) {
|
|
|
|
#FYI: the nodeRange for delete has to be specified in the URI
|
|
$request->{command} = 'rmdef';
|
|
push @args, "-t", "node";
|
|
unless (defined($noderange)) {
|
|
addPageContent("No nodename was supplied.");
|
|
sendResponseMsg($STATUS_BAD_REQUEST);
|
|
}
|
|
push @args, "-o", $noderange;
|
|
}
|
|
else {
|
|
unsupportedRequestType();
|
|
exit();
|
|
}
|
|
|
|
push @{$request->{arg}}, @args;
|
|
my $req = genRequest();
|
|
@responses = sendRequest($req);
|
|
|
|
return @responses;
|
|
}
|
|
|
|
my @notificationFields = ('filename', 'tables', 'tableops', 'comments', 'disable');
|
|
|
|
#complete, unless there is some way to alter existing notifications
|
|
sub notificationsHandler {
|
|
my @responses;
|
|
my @args;
|
|
|
|
#does not support using the notification fileName in the URI
|
|
|
|
if (isGet()) {
|
|
if (defined $q->param('fileName')) {
|
|
$request->{command} = 'gettab';
|
|
push @args, "filename" . $q->param('fileName');
|
|
|
|
#if they specified the fields, just get those
|
|
if (defined $q->param('field')) {
|
|
foreach ($q->param('field')) {
|
|
push @args, $_;
|
|
}
|
|
}
|
|
|
|
#else show all of the fields
|
|
else {
|
|
foreach (@notificationFields) {
|
|
push @args, "notification.$_";
|
|
}
|
|
}
|
|
}
|
|
else {
|
|
$request->{command} = 'tabdump';
|
|
push @args, "notification";
|
|
}
|
|
}
|
|
elsif (isPost()) {
|
|
$request->{command} = 'regnotif';
|
|
if (!defined $q->param('fileName') || !defined $q->param('table') || !defined $q->param('operation')) {
|
|
addPageContent("fileName, table and operation must be specified for a POST on /notifications");
|
|
sendResponseMsg($STATUS_BAD_REQUEST);
|
|
}
|
|
else {
|
|
push @args, $q->param('fileName');
|
|
my $tables;
|
|
foreach ($q->param('table')) {
|
|
$tables .= "$_,";
|
|
}
|
|
|
|
#get rid of the extra comma
|
|
chop($tables);
|
|
push @args, $tables;
|
|
push @args, '-o';
|
|
my $operations;
|
|
foreach ($q->param('operation')) {
|
|
$operations .= "$_,";
|
|
}
|
|
|
|
#get rid of the extra comma
|
|
chop($operations);
|
|
push @args, $q->param('operation');
|
|
}
|
|
}
|
|
elsif (isDelete()) {
|
|
$request->{command} = 'unregnotif';
|
|
if (defined $q->param('fileName')) {
|
|
push @args, $q->param('fileName');
|
|
}
|
|
else {
|
|
addPageContent("fileName must be specified for a DELETE on /notifications");
|
|
sendResponseMsg($STATUS_BAD_REQUEST);
|
|
}
|
|
}
|
|
else {
|
|
unsupportedRequestType();
|
|
exit();
|
|
}
|
|
|
|
push @{$request->{arg}}, @args;
|
|
addPageContent("request is " . Dumper($request));
|
|
my $req = genRequest();
|
|
@responses = sendRequest($req);
|
|
|
|
return @responses;
|
|
}
|
|
|
|
my @policyFields =
|
|
('priority', 'name', 'host', 'commands', 'noderange', 'parameters', 'time', 'rule', 'comments', 'disable');
|
|
|
|
#complete
|
|
sub policiesHandler {
|
|
my @responses;
|
|
my @args;
|
|
my $priority;
|
|
|
|
#does it specify the prioirty in the URI?
|
|
if (defined $path[1]) {
|
|
$priority = $path[1];
|
|
}
|
|
|
|
#in the query string?
|
|
elsif (defined $q->param('priority')) {
|
|
$priority = $q->param('priority');
|
|
}
|
|
|
|
if (isGet()) {
|
|
if (defined $priority) {
|
|
$request->{command} = 'gettab';
|
|
push @args, "priority=$priority";
|
|
my @fields = $q->param('field');
|
|
|
|
#if they specified fields to retrieve
|
|
if (@fields) {
|
|
push @args, @fields;
|
|
}
|
|
|
|
#give them everything if nothing is specified
|
|
else {
|
|
foreach (@policyFields) {
|
|
push @args, "policy.$_";
|
|
}
|
|
}
|
|
}
|
|
else {
|
|
$request->{command} = 'tabdump';
|
|
push @args, 'policy';
|
|
}
|
|
}
|
|
elsif (isPost()) {
|
|
if (defined $priority) {
|
|
$request->{command} = 'tabch';
|
|
push @args, "priority=$priority";
|
|
for ($q->param) {
|
|
if ($_ ne /priority/) {
|
|
push @args, "policy.$_=" . $q->param($_);
|
|
}
|
|
}
|
|
}
|
|
|
|
#some response about the priority being required
|
|
else {
|
|
addPageContent("The priority must be specified when creating a policy");
|
|
sendResponseMsg($STATUS_BAD_REQUEST);
|
|
}
|
|
}
|
|
elsif (isDelete()) {
|
|
|
|
#just allowing a delete by priority at the moment, could expand this to anything
|
|
if (defined $priority) {
|
|
$request->{command} = 'tabch';
|
|
push @args, '-d';
|
|
push @args, "priority=$priority";
|
|
push @args, "policy";
|
|
}
|
|
}
|
|
elsif (isPut() || isPatch()) {
|
|
if (defined $priority) {
|
|
$request->{command} = 'tabch';
|
|
push @args, "priority=$priority";
|
|
for ($q->param) {
|
|
if ($_ ne /priority/) {
|
|
push @args, "policy.$_=" . $q->param($_);
|
|
}
|
|
}
|
|
}
|
|
|
|
#some response about the priority being required
|
|
else {
|
|
addPageContent("The priority must be specified when updating a policy");
|
|
sendResponseMsg($STATUS_BAD_REQUEST);
|
|
}
|
|
}
|
|
else {
|
|
unsupportedRequestType();
|
|
exit();
|
|
}
|
|
|
|
push @{$request->{arg}}, @args;
|
|
addPageContent("request is " . Dumper($request));
|
|
my $req = genRequest();
|
|
@responses = sendRequest($req);
|
|
|
|
return @responses;
|
|
}
|
|
|
|
#complete
|
|
sub siteHandler {
|
|
my @data;
|
|
my @responses;
|
|
my @args;
|
|
|
|
if (isGet()) {
|
|
$request->{command} = 'lsdef';
|
|
push @{$request->{arg}}, '-t', 'site', '-o', 'clustersite';
|
|
my @temparray = $q->param('field');
|
|
|
|
#add the field name to get
|
|
if (scalar(@temparray) > 0) {
|
|
push @{$request->{arg}}, '-i';
|
|
push @{$request->{arg}}, join(',', @temparray);
|
|
}
|
|
}
|
|
elsif (isPut()) {
|
|
$request->{command} = 'chdef';
|
|
push @{$request->{arg}}, '-t', 'site', '-o', 'clustersite';
|
|
unless ($q->param('PUTDATA')) {
|
|
#temporary allowance for the put data to be contained in the queryString
|
|
unless ($queryhash{'putData'}) {
|
|
addPageContent("No set attribute was supplied.");
|
|
sendResponseMsg($STATUS_BAD_REQUEST);
|
|
}
|
|
else {
|
|
foreach my $put (@{$queryhash{'putData'}}) {
|
|
my ($key, $value) = split(/=/, $put, 2);
|
|
if ($key eq 'field' && $value) {
|
|
push @{$request->{arg}}, $value;
|
|
}
|
|
}
|
|
}
|
|
} else {
|
|
if ($q->param('PUTDATA')) {
|
|
my $entries = JSON::decode_json($q->param('PUTDATA'));
|
|
foreach (@$entries) {
|
|
push @{$request->{arg}}, $_;
|
|
}
|
|
}
|
|
else {
|
|
addPageContent("No Field and Value map was supplied.");
|
|
sendResponseMsg($STATUS_BAD_REQUEST);
|
|
}
|
|
}
|
|
}
|
|
else {
|
|
unsupportedRequestType();
|
|
}
|
|
|
|
my $req = genRequest();
|
|
@responses = sendRequest($req);
|
|
return @responses;
|
|
}
|
|
|
|
my $formatType;
|
|
|
|
#provide direct table access
|
|
#complete and tested on the site table
|
|
#use of the actual DELETE doesn't seem to fit here, since a resource would not be deleted
|
|
#using PUT or PATCH instead, though it doesn't feel all that correct either
|
|
sub tablesHandler {
|
|
my @responses;
|
|
my $table;
|
|
my @args;
|
|
|
|
#is the table name specified in the URI?
|
|
if (defined $path[1]) {
|
|
$table = $path[1];
|
|
}
|
|
|
|
#handle all gets
|
|
if (isGet()) {
|
|
|
|
#table was specified
|
|
if (defined $table) {
|
|
if (defined($q->param('col'))) {
|
|
$request->{command} = 'gettab';
|
|
push @args, $q->param('col') . '=' . $q->param('value');
|
|
my @temparray = $q->param('attribute');
|
|
foreach (@temparray) {
|
|
push @args, $table . '.' . $_;
|
|
}
|
|
}
|
|
else {
|
|
$request->{command} = 'tabdump';
|
|
push @args, $table;
|
|
if (!defined $q->param('desc')) {
|
|
$formatType = 'splitCommas';
|
|
}
|
|
}
|
|
}
|
|
else {
|
|
$request->{command} = 'tabdump';
|
|
}
|
|
}
|
|
elsif (isPut() || isPatch()) {
|
|
my $condition = $q->param('condition');
|
|
my @vals;
|
|
if (!defined $condition) {
|
|
foreach my $put (@{$queryhash{'putData'}}) {
|
|
my ($key, $value) = split(/=/, $put, 2);
|
|
if ($key eq 'condition' && $value) {
|
|
$condition = $value;
|
|
}
|
|
}
|
|
foreach my $put (@{$queryhash{'putData'}}) {
|
|
my ($key, $value) = split(/=/, $put, 2);
|
|
if ($key eq 'value') {
|
|
push(@vals, $value);
|
|
}
|
|
}
|
|
}
|
|
|
|
if (!defined $table || !defined $condition) {
|
|
addPageContent("The table and condition must be specified when adding, changing or deleting an entry");
|
|
sendResponseMsg($STATUS_BAD_REQUEST);
|
|
}
|
|
$request->{command} = 'tabch';
|
|
my $del;
|
|
if (!defined $q->param('delete')) {
|
|
foreach my $put (@{$queryhash{'putData'}}) {
|
|
my ($key, $value) = split(/=/, $put, 2);
|
|
if ($key eq 'delete') {
|
|
$del = 1;
|
|
}
|
|
}
|
|
}
|
|
|
|
if (defined $q->param('delete') || defined $del) {
|
|
push @args, '-d';
|
|
push @args, $condition;
|
|
push @args, $table;
|
|
}
|
|
else {
|
|
push @args, $condition;
|
|
if ($q->param('value')) {
|
|
for ($q->param('value')) {
|
|
push @args, "$table.$_";
|
|
}
|
|
}
|
|
else {
|
|
@args = (@args, @vals);
|
|
}
|
|
}
|
|
}
|
|
else {
|
|
unsupportedRequestType();
|
|
exit();
|
|
}
|
|
|
|
push @{$request->{arg}}, @args;
|
|
my $req = genRequest();
|
|
@responses = sendRequest($req);
|
|
return @responses;
|
|
}
|
|
|
|
my @accountFields = ('key', 'username', 'password', 'cryptmethod', 'comments', 'disable');
|
|
|
|
#done aside from being able to change cluster users, which xcat can't do yet
|
|
sub accountsHandler {
|
|
my @responses;
|
|
my @args;
|
|
my $key = $q->param('key');
|
|
|
|
if (isGet()) {
|
|
|
|
#passwd table
|
|
if (!defined $q->param('clusterUser')) {
|
|
if (defined $key) {
|
|
$request->{command} = 'tabget';
|
|
push @args, "key=$key";
|
|
if (defined $q->param('field')) {
|
|
foreach ($q->param('field')) {
|
|
push @args, "passwd.$_";
|
|
}
|
|
}
|
|
else {
|
|
foreach (@accountFields) {
|
|
push @args, "passwd.$_";
|
|
}
|
|
}
|
|
}
|
|
else {
|
|
$request->{command} = 'tabdump';
|
|
push @args, 'passwd';
|
|
}
|
|
}
|
|
|
|
#cluster user list
|
|
else {
|
|
$request->{command} = 'xcatclientnnr';
|
|
push @args, 'clusteruserlist';
|
|
push @args, '-p';
|
|
}
|
|
}
|
|
elsif (isPost()) {
|
|
if (!defined $q->param('clusterUser')) {
|
|
if (defined $key) {
|
|
$request->{command} = 'tabch';
|
|
push @args, "key=$key";
|
|
for ($q->param) {
|
|
if ($_ !~ /key/) {
|
|
push @args, "passwd.$_=" . $q->param($_);
|
|
}
|
|
}
|
|
}
|
|
else {
|
|
addPageContent("The key must be specified when creating a non-cluster user");
|
|
sendResponseMsg($STATUS_BAD_REQUEST);
|
|
}
|
|
}
|
|
|
|
#active directory user
|
|
else {
|
|
if (defined $q->param('userName') && defined $q->param('userPass')) {
|
|
$request->{command} = 'xcatclientnnr';
|
|
push @args, 'clusteruseradd';
|
|
push @args, $q->param('userName');
|
|
push @{$request->{arg}}, @args;
|
|
$request->{environment} = {XCAT_USERPASS => $q->param('userPass')};
|
|
}
|
|
else {
|
|
addPageContent("The key must be specified when creating a cluster user");
|
|
sendResponseMsg($STATUS_BAD_REQUEST);
|
|
}
|
|
}
|
|
}
|
|
elsif (isDelete()) {
|
|
if (!defined $q->param('clusterUser')) {
|
|
|
|
#just allowing a delete by key at the moment, could expand this to anything
|
|
if (defined $key) {
|
|
$request->{command} = 'tabch';
|
|
push @args, '-d';
|
|
push @args, "key=$key";
|
|
push @args, "passwd";
|
|
}
|
|
else {
|
|
addPageContent("The key must be specified when deleting a non-cluster user");
|
|
sendResponseMsg($STATUS_BAD_REQUEST);
|
|
}
|
|
}
|
|
else {
|
|
if (defined $q->param('userName')) {
|
|
$request->{command} = 'xcatclientnnr';
|
|
push @args, 'clusteruserdel';
|
|
push @args, $q->param('userName');
|
|
}
|
|
else {
|
|
addPageContent("The userName must be specified when deleting a cluster user");
|
|
sendResponseMsg($STATUS_BAD_REQUEST);
|
|
}
|
|
}
|
|
}
|
|
elsif (isPut() || isPatch()) {
|
|
if (!defined $q->param('clusterUser')) {
|
|
if (defined $key) {
|
|
$request->{command} = 'tabch';
|
|
push @args, "key=$key";
|
|
for ($q->param) {
|
|
if ($_ !~ /key/) {
|
|
push @args, "passwd.$_=" . $q->param($_);
|
|
}
|
|
}
|
|
}
|
|
else {
|
|
addPageContent("The key must be specified when updating a non-cluster user");
|
|
sendResponseMsg($STATUS_BAD_REQUEST);
|
|
}
|
|
}
|
|
|
|
#TODO: there isn't currently a way to update cluster users
|
|
else {
|
|
|
|
}
|
|
}
|
|
else {
|
|
unsupportedRequestType();
|
|
exit(0);
|
|
}
|
|
|
|
push @{$request->{arg}}, @args;
|
|
my $req = genRequest();
|
|
@responses = sendRequest($req);
|
|
return @responses;
|
|
}
|
|
|
|
sub objectsHandler {
|
|
my @responses;
|
|
my @args;
|
|
my @objectTypeList = (
|
|
"auditlog", "boottarget", "eventlog", "firmware", "group", "monitoring",
|
|
"network", "node", "notification", "osimage", "policy", "route",
|
|
"site");
|
|
|
|
#my %objectTypes;
|
|
#foreach my $item (@objectTypeList) { $objectTypes{$item} = 1 }
|
|
my @objectTypes;
|
|
my @objects;
|
|
if (defined $path[1]) {
|
|
$objectTypes[0] = $path[1];
|
|
if (defined $path[2]) {
|
|
$objects[0] = $path[2];
|
|
}
|
|
}
|
|
if (defined $q->param('objectType')) {
|
|
@objectTypes = $q->param('objectType');
|
|
}
|
|
if (defined $q->param('object')) {
|
|
@objects = $q->param('object');
|
|
}
|
|
|
|
if ($q->param('verbose')) {
|
|
push @args, '-v';
|
|
}
|
|
|
|
if (isGet()) {
|
|
if (defined $objectTypes[0]) {
|
|
$request->{command} = 'lsdef';
|
|
push @args, '-l';
|
|
push @args, '-t';
|
|
push @args, join(',', @objectTypes);
|
|
if (defined $objects[0]) {
|
|
push @args, '-o';
|
|
push @args, join(',', @objects);
|
|
}
|
|
if ($q->param('info')) {
|
|
push @args, '-h';
|
|
}
|
|
}
|
|
else {
|
|
if ($q->param('info')) {
|
|
push @args, '-h';
|
|
}
|
|
else {
|
|
|
|
#couldn't find a way to do this through xcatd, so shortcutting the request
|
|
my %resp = (data => \@objectTypeList);
|
|
return (\%resp);
|
|
}
|
|
}
|
|
}
|
|
elsif (isPut()) {
|
|
$request->{command} = 'chdef';
|
|
if ($q->param('verbose')) {
|
|
push @args, '-v';
|
|
}
|
|
if (!defined $q->param('objectType')) {
|
|
addPageContent("The object must be specified.");
|
|
sendResponseMsg($STATUS_BAD_REQUEST);
|
|
}
|
|
else {
|
|
push @args, '-t';
|
|
push @args, join(',', $q->param('objectType'));
|
|
}
|
|
if ($q->param('objectName')) {
|
|
push @args, join(',', $q->param('objectName'));
|
|
}
|
|
if ($q->param('dynamic')) {
|
|
push @args, '-d';
|
|
}
|
|
if ($q->param('minus')) {
|
|
push @args, '-m';
|
|
}
|
|
if ($q->param('plus')) {
|
|
push @args, '-p';
|
|
}
|
|
if (defined $q->param('field')) {
|
|
foreach ($q->param('field')) {
|
|
|
|
#if it has ==, !=. =~ or !~ operators in the field, use the -w option
|
|
if (/==|!=|=~|!~/) {
|
|
push @args, '-w';
|
|
}
|
|
push @args, $_;
|
|
}
|
|
}
|
|
if ($q->param('nodeRange')) {
|
|
push @args, $q->param('nodeRange');
|
|
}
|
|
|
|
}
|
|
elsif (isPost()) {
|
|
$request->{command} = 'mkdef';
|
|
if ($q->param('verbose')) {
|
|
push @args, '-v';
|
|
}
|
|
if (!defined $q->param('objectType')) {
|
|
addPageContent("The object must be specified.");
|
|
sendResponseMsg($STATUS_BAD_REQUEST);
|
|
}
|
|
else {
|
|
push @args, '-t';
|
|
push @args, join(',', $q->param('objectType'));
|
|
}
|
|
if ($q->param('objectName')) {
|
|
push @args, join(',', $q->param('objectName'));
|
|
}
|
|
if ($q->param('dynamic')) {
|
|
push @args, '-d';
|
|
}
|
|
if ($q->param('force')) {
|
|
push @args, '-f';
|
|
}
|
|
if (defined $q->param('field')) {
|
|
foreach ($q->param('field')) {
|
|
|
|
#if it has ==, !=. =~ or !~ operators in the field, use the -w option
|
|
if (/==|!=|=~|!~/) {
|
|
push @args, '-w';
|
|
}
|
|
push @args, $_;
|
|
}
|
|
}
|
|
if ($q->param('nodeRange')) {
|
|
push @args, $q->param('nodeRange');
|
|
}
|
|
|
|
}
|
|
elsif (isDelete()) {
|
|
$request->{command} = 'rmdef';
|
|
if (defined $q->param('info')) {
|
|
push @args, '-h';
|
|
}
|
|
elsif (defined $q->param('all')) {
|
|
push @args, '-a';
|
|
}
|
|
elsif (defined $objectTypes[0]) {
|
|
push @args, '-t';
|
|
push @args, join(',', @objectTypes);
|
|
if (defined $objects[0]) {
|
|
push @args, '-o';
|
|
push @args, join(',', @objects);
|
|
}
|
|
}
|
|
else {
|
|
addPageContent(
|
|
"Either the help info must be requested or the object must be specified or the flag that indicates everything should be removed."
|
|
);
|
|
sendResponseMsg($STATUS_BAD_REQUEST);
|
|
}
|
|
if (defined $q->param('nodeRange')) {
|
|
push @args, $q->param('nodeRange');
|
|
}
|
|
}
|
|
else {
|
|
unsupportedRequestType();
|
|
exit();
|
|
}
|
|
|
|
push @{$request->{arg}}, @args;
|
|
my $req = genRequest();
|
|
@responses = sendRequest($req);
|
|
return @responses;
|
|
}
|
|
|
|
#complete i think, tho chvm could handle args better
|
|
sub vmsHandler {
|
|
my @args;
|
|
my $noderange;
|
|
if (defined $path[1]) {
|
|
$noderange = $path[1];
|
|
$request->{noderange} = $noderange;
|
|
}
|
|
else {
|
|
addPageContent("Invalid nodes and/or groups in noderange");
|
|
sendResponseMsg($STATUS_BAD_REQUEST);
|
|
}
|
|
|
|
if (isGet()) {
|
|
$request->{command} = 'lsvm';
|
|
if (defined $q->param('all')) {
|
|
push @args, '-a';
|
|
}
|
|
}
|
|
elsif (isPost()) {
|
|
my $entries;
|
|
my %entryhash;
|
|
my $position;
|
|
$request->{command} = 'mkvm';
|
|
unless ($q->param('POSTDATA')) {
|
|
addPageContent("Invalid Parameters");
|
|
sendResponseMsg($STATUS_BAD_REQUEST);
|
|
}
|
|
|
|
#collect all parameters from the postdata
|
|
my $entries = JSON::decode_json($q->param('PUTDATA'));
|
|
if (scalar(@$entries) < 1) {
|
|
addPageContent("No set attribute was supplied.");
|
|
sendResponseMsg($STATUS_BAD_REQUEST);
|
|
}
|
|
|
|
extractData(\%entryhash, $entries);
|
|
|
|
#for system p
|
|
if (defined $entryhash{'cec'}) {
|
|
push @args, '-c';
|
|
push @args, $entryhash{'cec'};
|
|
}
|
|
|
|
if (defined $entryhash{'startId'}) {
|
|
push @args, '-i';
|
|
push @args, $entryhash{'startId'};
|
|
}
|
|
|
|
if (defined $entryhash{'source'}) {
|
|
push @args, '-l';
|
|
push @args, $entryhash{'source'};
|
|
}
|
|
|
|
if (defined $entryhash{'profile'}) {
|
|
push @args, '-p';
|
|
push @args, $entryhash{'profile'};
|
|
}
|
|
|
|
if (defined $entryhash{'full'}) {
|
|
push @args, '--full';
|
|
}
|
|
|
|
#for KVM & Vmware
|
|
if (defined $entryhash{'master'}) {
|
|
push @args, '-m';
|
|
push @args, $entryhash{'master'};
|
|
}
|
|
|
|
if (defined $entryhash{'disksize'}) {
|
|
push @args, '-s';
|
|
push @args, $entryhash{'disksize'};
|
|
}
|
|
|
|
if (defined $entryhash{'memory'}) {
|
|
push @args, '--mem';
|
|
push @args, $entryhash{'memory'};
|
|
}
|
|
|
|
if (defined $entryhash{'cpu'}) {
|
|
push @args, '--cpus';
|
|
push @args, $entryhash{'cpu'};
|
|
}
|
|
|
|
if (defined $entryhash{'force'}) {
|
|
push @args, '-f';
|
|
}
|
|
}
|
|
elsif (isPut()) {
|
|
$request->{command} = 'chvm';
|
|
if ($q->param('PUTDATA')) {
|
|
my $entries = JSON::decode_json($q->param('PUTDATA'));
|
|
if (scalar(@$entries) < 1) {
|
|
addPageContent("No Field and Value map was supplied.");
|
|
sendResponseMsg($STATUS_BAD_REQUEST);
|
|
}
|
|
foreach (@$entries) {
|
|
push @args, $_;
|
|
}
|
|
}
|
|
else {
|
|
addPageContent("No Field and Value map was supplied.");
|
|
sendResponseMsg($STATUS_BAD_REQUEST);
|
|
}
|
|
}
|
|
elsif (isDelete()) {
|
|
$request->{command} = 'rmvm';
|
|
if (defined $q->param('retain')) {
|
|
push @args, '-r';
|
|
}
|
|
if (defined $q->param('service')) {
|
|
push @args, '--service';
|
|
}
|
|
}
|
|
else {
|
|
unsupportedRequestType();
|
|
exit();
|
|
}
|
|
|
|
push @{$request->{arg}}, @args;
|
|
my $req = genRequest();
|
|
my @responses = sendRequest($req);
|
|
return @responses;
|
|
}
|
|
|
|
sub versionHandler {
|
|
addPageContent($q->p("API version is $VERSION"));
|
|
sendResponseMsg($STATUS_OK);
|
|
exit(0);
|
|
}
|
|
|
|
#for operations that take a 'long' time to finish, this will provide the interface to check their status
|
|
sub jobsHandler {
|
|
|
|
}
|
|
|
|
#all data wrapping and writing is funneled through here
|
|
sub wrapData {
|
|
my $data = shift;
|
|
my $errorInformation = '';
|
|
|
|
#trim the serverdone message off
|
|
if (exists $data->[0]->{serverdone} && exists $data->[0]->{error}) {
|
|
$errorInformation = $data->[0]->{error}->[0];
|
|
addPageContent($q->p($errorInformation));
|
|
if (($errorInformation =~ /Permission denied/) || ($errorInformation =~ /Authentication failure/)) {
|
|
sendResponseMsg($STATUS_UNAUTH);
|
|
}
|
|
else {
|
|
sendResponseMsg($STATUS_FORBIDDEN);
|
|
}
|
|
exit 1;
|
|
}
|
|
else {
|
|
pop @{$data};
|
|
}
|
|
if (exists $formatters{$format}) {
|
|
$formatters{$format}->($data);
|
|
}
|
|
|
|
#all information were add into the global varibale, call the response funcion
|
|
if (exists $data->[0]->{info} && $data->[0]->{info}->[0] =~ /Could not find an object/) {
|
|
sendResponseMsg($STATUS_NOT_FOUND);
|
|
}
|
|
elsif (isPost()) {
|
|
sendResponseMsg($STATUS_CREATED);
|
|
}
|
|
else {
|
|
sendResponseMsg($STATUS_OK);
|
|
}
|
|
}
|
|
|
|
sub wrapJson {
|
|
my $data = shift;
|
|
my $json;
|
|
$json->{'data'} = $data;
|
|
addPageContent(JSON::to_json($json));
|
|
}
|
|
|
|
sub wrapHtml {
|
|
my $item;
|
|
my $response = shift;
|
|
my $baseUri = $url . $pathInfo;
|
|
if ($baseUri !~ /\/^/) {
|
|
$baseUri .= "/";
|
|
}
|
|
|
|
foreach my $element (@$response) {
|
|
|
|
#foreach my $element (@$data){
|
|
#if($element->{error}){
|
|
if ($element->{node}) {
|
|
addPageContent("<table border=1>");
|
|
foreach $item (@{$element->{node}}) {
|
|
|
|
#my $url = $baseUri.$item->{name}[0];
|
|
addPageContent("<tr><td>$item->{name}[0]</td>");
|
|
if (exists $item->{data} && exists $item->{data}[0]) {
|
|
if (ref($item->{data}[0]) eq 'HASH') {
|
|
if (exists $item->{data}[0]->{desc} && exists $item->{data}[0]->{desc}[0]) {
|
|
addPageContent("<td>$item->{data}[0]->{desc}[0]</td>");
|
|
}
|
|
if (ref($item->{data}[0]) eq 'HASH' && exists $item->{data}[0]->{contents}[0]) {
|
|
addPageContent("<td>$item->{data}[0]->{contents}[0]</td>");
|
|
}
|
|
}
|
|
else {
|
|
addPageContent("<td>$item->{data}[0]</td>");
|
|
}
|
|
}
|
|
elsif (exists $item->{error}) {
|
|
addPageContent("<td>$item->{error}[0]</td>");
|
|
}
|
|
addPageContent("</tr>");
|
|
}
|
|
addPageContent("</table>");
|
|
}
|
|
if ($element->{data}) {
|
|
addPageContent("<table border=1>");
|
|
foreach $item (@{$element->{data}}) {
|
|
my @values = split(/:/, $item, 2);
|
|
addPageContent("<tr>");
|
|
foreach (@values) {
|
|
if ($formatType =~ /splitCommas/) {
|
|
my @fields = split(/,/, $_, -1);
|
|
foreach (@fields) {
|
|
addPageContent("<td>$_</td>");
|
|
}
|
|
}
|
|
else {
|
|
addPageContent("<td>$_</td>");
|
|
}
|
|
}
|
|
addPageContent("</tr>\n");
|
|
}
|
|
addPageContent("</table>");
|
|
}
|
|
if ($element->{info}) {
|
|
addPageContent("<table border=1>");
|
|
foreach $item (@{$element->{info}}) {
|
|
addPageContent("<tr>");
|
|
my $fieldname = '';
|
|
my $fieldvalue = '';
|
|
|
|
#strip whitespace in the string
|
|
$item =~ s/^\s+//;
|
|
$item =~ s/\s+$//;
|
|
if ($item =~ /Object/) {
|
|
($fieldname, $fieldvalue) = split(/:/, $item);
|
|
}
|
|
elsif ($item =~ /.*=.*/) {
|
|
my $position = index $item, '=';
|
|
$fieldname = substr $item, 0, $position;
|
|
$fieldvalue = substr $item, $position + 1;
|
|
}
|
|
else {
|
|
$fieldname = $item;
|
|
}
|
|
addPageContent("<td>" . $fieldname . "</td>");
|
|
if ($fieldvalue ne '') {
|
|
addPageContent("<td>" . $fieldvalue . "</td>");
|
|
}
|
|
addPageContent("</tr>\n");
|
|
}
|
|
addPageContent("</table>");
|
|
}
|
|
if ($element->{error}) {
|
|
addPageContent("<table border=1>");
|
|
foreach $item (@{$element->{error}}) {
|
|
addPageContent("<tr><td>" . $item . "</td></tr>");
|
|
}
|
|
addPageContent("</table>");
|
|
}
|
|
}
|
|
}
|
|
|
|
sub wrapXml {
|
|
my @data = shift;
|
|
foreach (@data) {
|
|
foreach (@$_) {
|
|
addPageContent(XMLout($_, RootName => '', NoAttr => 1, KeyAttr => []));
|
|
}
|
|
}
|
|
}
|
|
|
|
#general tests for valid requests and responses with HTTP codes here
|
|
if (!doesResourceExist($resource)) {
|
|
addPageContent("Resource '$resource' does not exist");
|
|
sendResponseMsg($STATUS_NOT_FOUND);
|
|
}
|
|
else {
|
|
if ($DEBUGGING) {
|
|
addPageContent($q->p("resource is $resource"));
|
|
}
|
|
handleRequest();
|
|
}
|
|
|
|
#talk to the server
|
|
use Socket;
|
|
use IO::Socket::INET;
|
|
use IO::Socket::SSL;
|
|
use lib "/opt/xcat/lib/perl";
|
|
use xCAT::Table;
|
|
|
|
# The database initialization may take some time in the system boot scenario
|
|
# wait for a while for the database initialization
|
|
#do we really need to do this for the web service?
|
|
sub sendRequest {
|
|
my $request = shift;
|
|
my $sitetab;
|
|
my $retries = 0;
|
|
|
|
if ($DEBUGGING) {
|
|
my $preXml = $request;
|
|
|
|
#$preXml =~ s/</<br>< /g;
|
|
#$preXml =~ s/>/><br>/g;
|
|
addPageContent($q->p("request XML<br>" . $preXml));
|
|
}
|
|
|
|
#hardcoded port for now
|
|
my $port = 3001;
|
|
my $xcatHost = "localhost:$port";
|
|
|
|
#temporary, will be using username and password
|
|
my $homedir = "/root";
|
|
my $keyfile = $homedir . "/.xcat/client-cred.pem";
|
|
my $certfile = $homedir . "/.xcat/client-cred.pem";
|
|
my $cafile = $homedir . "/.xcat/ca.pem";
|
|
|
|
my $client;
|
|
if (-r $keyfile and -r $certfile and -r $cafile) {
|
|
$client = IO::Socket::SSL->new(
|
|
PeerAddr => $xcatHost,
|
|
SSL_key_file => $keyfile,
|
|
SSL_cert_file => $certfile,
|
|
SSL_ca_file => $cafile,
|
|
SSL_use_cert => 1,
|
|
Timeout => 15,);
|
|
}
|
|
else {
|
|
$client = IO::Socket::SSL->new(
|
|
PeerAddr => $xcatHost,
|
|
Timeout => 15,);
|
|
}
|
|
unless ($client) {
|
|
if ($@ =~ /SSL Timeout/) {
|
|
addPageContent("Connection failure: SSL Timeout or incorrect certificates in ~/.xcat");
|
|
sendResponseMsg($STATUS_TIMEOUT);
|
|
}
|
|
else {
|
|
addPageContent("Connection failurexx: $@");
|
|
sendResponseMsg($STATUS_SERVICE_UNAVAILABLE);
|
|
}
|
|
}
|
|
|
|
print $client $request;
|
|
|
|
my $response;
|
|
my $rsp;
|
|
my @fullResponse;
|
|
my $cleanexit = 0;
|
|
while (<$client>) {
|
|
$response .= $_;
|
|
if (m/<\/xcatresponse>/) {
|
|
|
|
#replace ESC with xxxxESCxxx because XMLin cannot handle it
|
|
if ($DEBUGGING) {
|
|
addPageContent($response . "\n");
|
|
}
|
|
$response =~ s/\e/xxxxESCxxxx/g;
|
|
|
|
#print "responseXML is ".$response;
|
|
$rsp = XMLin($response, SuppressEmpty => undef, ForceArray => 1);
|
|
|
|
#add ESC back
|
|
foreach my $key (keys %$rsp) {
|
|
if (ref($rsp->{$key}) eq 'ARRAY') {
|
|
foreach my $text (@{$rsp->{$key}}) {
|
|
next unless defined $text;
|
|
$text =~ s/xxxxESCxxxx/\e/g;
|
|
}
|
|
}
|
|
else {
|
|
$rsp->{$key} =~ s/xxxxESCxxxx/\e/g;
|
|
}
|
|
}
|
|
|
|
$response = '';
|
|
push(@fullResponse, $rsp);
|
|
if ($rsp->{serverdone}) {
|
|
$cleanexit = 1;
|
|
last;
|
|
}
|
|
}
|
|
}
|
|
unless ($cleanexit) {
|
|
addPageContent("ERROR/WARNING: communication with the xCAT server seems to have been ended prematurely");
|
|
sendResponseMsg($STATUS_SERVICE_UNAVAILABLE);
|
|
exit(0);
|
|
}
|
|
|
|
if ($DEBUGGING) {
|
|
addPageContent($q->p("response " . Dumper(@fullResponse)));
|
|
}
|
|
return @fullResponse;
|
|
}
|
|
|
|
sub isGet {
|
|
return uc($requestType) eq "GET";
|
|
}
|
|
|
|
sub isPut {
|
|
return uc($requestType) eq "PUT";
|
|
}
|
|
|
|
sub isPost {
|
|
return uc($requestType) eq "POST";
|
|
}
|
|
|
|
sub isPatch {
|
|
return uc($requestType) eq "PATCH";
|
|
}
|
|
|
|
sub isDelete {
|
|
return uc($requestType) eq "DELETE";
|
|
}
|
|
|
|
#check to see if this is a valid user. userName and password are already set
|
|
sub isAuthenticUser {
|
|
$request->{command} = 'authcheck';
|
|
my $req = genRequest();
|
|
my @responses = sendRequest($req);
|
|
if ($responses[0]->{data}[0] eq "Authenticated") {
|
|
|
|
#user is authenticated
|
|
return 1;
|
|
}
|
|
|
|
#authentication failure
|
|
addPageContent($responses[0]->{error}[0]);
|
|
sendResponseMsg($STATUS_UNAUTH);
|
|
}
|
|
|
|
|