mirror of
				https://github.com/xcat2/xcat-core.git
				synced 2025-10-26 08:55:24 +00:00 
			
		
		
		
	git-svn-id: https://svn.code.sf.net/p/xcat/code/xcat-core/trunk@9802 8638fb3e-16cb-4fca-ae20-7b5d299a9bcd
		
			
				
	
	
		
			1720 lines
		
	
	
		
			42 KiB
		
	
	
	
		
			Perl
		
	
	
		
			Executable File
		
	
	
	
	
			
		
		
	
	
			1720 lines
		
	
	
		
			42 KiB
		
	
	
	
		
			Perl
		
	
	
		
			Executable File
		
	
	
	
	
| #!/usr/bin/perl
 | |
| use strict;
 | |
| use CGI qw/:standard/;
 | |
| use 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 $q = CGI->new;
 | |
| my $url = $q->url;
 | |
| my $pathInfo = $q->path_info;
 | |
| my $requestType = $ENV{'REQUEST_METHOD'};
 | |
| my $queryString = $ENV{'QUERY_STRING'};
 | |
| my @path = split(/\//, $pathInfo);
 | |
| shift(@path);
 | |
| my $resource = $path[0];
 | |
| print $q->header('text/html');
 | |
| 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";
 | |
| 
 | |
| sub sendStatusMsg{
 | |
|   my $code = shift;
 | |
|   my $message = shift;
 | |
|   print $q->header(-status => $code);
 | |
|   print $message;
 | |
| }
 | |
| 
 | |
| sub unsupportedRequestType{
 | |
|   sendStatusMsg($STATUS_NOT_ALLOWED, "request method '$requestType' is not supported on resource '$resource'");
 | |
| }
 | |
| 
 | |
| use XML::Simple;
 | |
| $XML::Simple::PREFERRED_PARSER='XML::Parser';
 | |
| 
 | |
| sub genRequest{
 | |
|   if($DEBUGGING){
 | |
|     print $q->p("request ".Dumper($request));
 | |
|   }
 | |
|   my $xml = XMLout($request, RootName=>'xcatrequest',NoAttr=>1,KeyAttr=>[]);
 | |
| }
 | |
| 
 | |
| #default format
 | |
| my $format = 'html';
 | |
| 
 | |
| #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,
 | |
|                  );
 | |
| 
 | |
| if($q->param('format'))
 | |
| {
 | |
|   $format = $q->param('format');
 | |
|   if(!exists $formatters{$format}){
 | |
|     sendStatusMsg($STATUS_BAD_REQUEST, "The format '$format' is not valid");
 | |
|     exit(0);
 | |
|   }
 | |
| }
 | |
| 
 | |
| 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);
 | |
| 
 | |
| #if no resource was specified
 | |
| if($pathInfo =~ /^\/$/ || $pathInfo =~ /^$/){
 | |
|   print $q->p("This is the root page for the xCAT Rest Web Service.  Available resources are:");
 | |
|   foreach (sort keys %resources){
 | |
|     print $q->p($_);
 | |
|   }
 | |
|   exit(0);
 | |
| }
 | |
| 
 | |
| sub doesResourceExist
 | |
| {
 | |
|   my $res = shift;
 | |
|   return exists $resources{$res};
 | |
| }
 | |
| 
 | |
| if($DEBUGGING){
 | |
|   if(defined $q->param('PUTDATA')){
 | |
|     print "put data ".$q->p($q->param('PUTDATA')."\n");
 | |
|   }
 | |
|   if(defined $q->param('POSTDATA')){
 | |
|     print "post data ".$q->p($q->param('POSTDATA')."\n");
 | |
|   }
 | |
|   print $q->p("Parameters ");
 | |
|   my @params = $q->param;
 | |
|   foreach (@params)
 | |
|   {
 | |
|     print "$_ = ".$q->param($_)."\n";
 | |
|   }
 | |
|   print $q->p("Query String $queryString"."\n");
 | |
|   print $q->p("HTTP Method $requestType"."\n");
 | |
|   print $q->p("URI $url"."\n");
 | |
|   print $q->p("path ".Dumper(@path)."\n");
 | |
| }
 | |
| 
 | |
| my $userName;
 | |
| my $password;
 | |
| 
 | |
| sub handleRequest{
 | |
|   if(defined $q->param('userName')){
 | |
|     $userName = $q->param('userName')
 | |
|   }
 | |
|   if(defined $q->param('password')){
 | |
|     $password = $q->param('password')
 | |
|   }
 | |
|   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{
 | |
|       sendStatusMsg($STATUS_BAD_REQUEST, "A node range and group name must be specified for creating a group");
 | |
|       exit(0);
 | |
|     }
 | |
|   }
 | |
|   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{
 | |
|         sendStatusMsg($STATUS_BAD_REQUEST, "The path must be specified for creating directories for dsh");
 | |
|         exit(0);
 | |
|       }
 | |
|     }
 | |
|     else{
 | |
|       if(defined $groupName && defined $q->param('fields')){
 | |
|          $request->{command} = 'nodegrpch';
 | |
|          push @args, $groupName;
 | |
|          push @args, $q->param('field');
 | |
|       }
 | |
|       else{
 | |
|         sendStatusMsg($STATUS_BAD_REQUEST, "The group and fields must be specified to update groups");
 | |
|         exit(0);
 | |
|       }
 | |
|     }
 | |
|   }
 | |
|   elsif(isDelete()){
 | |
|     if(defined $groupName){
 | |
|       $request->{command} = 'rmdef';
 | |
|       push @args, '-d';
 | |
|       push @args, 'group';
 | |
|       push @args, '-o';
 | |
|       push @args, $groupName;
 | |
|     }
 | |
|     else{
 | |
|       sendStatusMsg($STATUS_BAD_REQUEST, "The group must be specified to delete a group");
 | |
|       exit(0);
 | |
|     }
 | |
|   }
 | |
|   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;
 | |
| 
 | |
|   if(defined($path[1])){
 | |
|     $image = $path[1];
 | |
|   }
 | |
|   else{
 | |
|     $image = $q->param('imageName');
 | |
|   }
 | |
| 
 | |
|   if(isGet()){
 | |
|     if(defined $image){
 | |
|       #call chkosimage, but should only be used for AIX images
 | |
|       if($q->param('checkAixImage')){
 | |
|         $request->{command} = 'chkosimage';
 | |
|         push @args, $image;
 | |
|       }
 | |
|       else{
 | |
|         $request->{command} = 'tabget';
 | |
|         push @args, "imagename=$image";
 | |
|         if(defined $q->param('field')){
 | |
|           foreach ($q->param('field')){
 | |
|             push @args, "osimage.$_";
 | |
|           }
 | |
|         }
 | |
|         else{
 | |
|           foreach (@groupFields){
 | |
|             push @args, "osimage.$_";
 | |
|           }
 | |
|         }
 | |
|       }
 | |
|     }
 | |
|     #no image indicated, so list all
 | |
|     else{
 | |
|       $request->{command} = 'tabdump';
 | |
|       push @args, 'osimage';
 | |
|     }
 | |
|   }
 | |
|   elsif(isPost()){
 | |
| ####genimage and related commands do not go through xcatd....
 | |
| ####not supported at the moment
 | |
|     #if($q->param('type') eq /stateless/){
 | |
|       #if(!defined $image){
 | |
|         #sendStatusMsg($STATUS_BAD_REQUEST, "The image name is required to create a stateless image");
 | |
|         #exit(0);
 | |
|       #}
 | |
|       #$request->{command} = 'genimage';
 | |
|       #foreach(param->{'field'}){
 | |
|       #}
 | |
|     #}
 | |
|     #else{
 | |
|       #if(defined $q->param('path')){
 | |
|         #$request->{command} = 'copycds';
 | |
|         #push @args, $q->param('path');
 | |
|       #}
 | |
|     #}
 | |
|   }
 | |
|   elsif(isPut() || isPatch()){
 | |
|     #use chkosimage to remove any older versions of the rpms.  should only be used for AIX
 | |
|     if($q->param('cleanAixImage')){
 | |
|       if(defined $image){
 | |
|         $request->{command} = 'chkosimage';
 | |
|         push @args, '-c';
 | |
|         push @args, $image;
 | |
|       }
 | |
|       else{
 | |
|         sendStatusMsg($STATUS_BAD_REQUEST, "The image name is required to clean an os image");
 | |
|       }
 | |
|     }
 | |
|   }
 | |
|   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{
 | |
|       sendStatusMsg($STATUS_BAD_REQUEST, "Either the image name or the os, architecture and profile must be specified to remove an image");
 | |
|       exit(0);
 | |
|     }
 | |
|   }
 | |
|   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){
 | |
|     print $q->p("Current logs available are auditlog and eventlog");
 | |
|     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{
 | |
|         sendStatusMsg($STATUS_BAD_REQUEST, "nodeRange must be specified to GET remote event logs");
 | |
|       }
 | |
|     }
 | |
|     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{
 | |
|         sendStatusMsg($STATUS_BAD_REQUEST, "nodeRange must be specified to clean remote event logs");
 | |
|       }
 | |
|     }
 | |
|     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';
 | |
|     push @args, $q->param('name');
 | |
|     if($q->param('nodeStatMon')){
 | |
|       push @args, '-n';
 | |
|     }
 | |
|     #get the plug-in specific settings array
 | |
|     for ($q->param){
 | |
|       if($_ ne /name/ && $_ ne /nodeStatMon/){
 | |
|         push @args, '-s';
 | |
|         push @args, "$_=".$q->param($_);
 | |
|       }
 | |
|     }
 | |
|   }
 | |
|   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;
 | |
| 
 | |
|   if(isGet()){
 | |
|     $request->{command} = 'tabdump';
 | |
|     push @args, 'networks';
 | |
|   }
 | |
|   elsif(isPut() or isPatch()){
 | |
|     my $subResource;
 | |
|     if(defined $path[1]){
 | |
|       $subResource = $path[1];
 | |
|     }
 | |
|     if($subResource eq "hosts"){
 | |
|       $request->{command} = 'makehosts';
 | |
|       #is this needed?
 | |
|       push @args, 'all';
 | |
|     }
 | |
|     elsif($subResource eq "dhcp"){
 | |
|       #allow restarting of the dhcp service.  scary?
 | |
|       if($q->param('command') eq "restart"){
 | |
|         if(isAuthenticUser()){
 | |
|           system('service dhcp restart');
 | |
|         }
 | |
|         else{
 | |
|           exit(0);
 | |
|         }
 | |
|       }
 | |
|       else{
 | |
|         $request->{command} = 'makedhcp';
 | |
|         foreach($q->param('field')){
 | |
|           push @args, $_;
 | |
|         }
 | |
|       }
 | |
|     }
 | |
|     elsif($subResource eq "dns"){
 | |
|       #allow restarting of the named service.  scary?
 | |
|       if($q->param('command') eq "restart"){
 | |
|         if(isAuthenticUser()){
 | |
|           system('service named restart');
 | |
|         }
 | |
|       }
 | |
|       else{
 | |
|         $request->{command} = 'makedns';
 | |
|         foreach($q->param('field')){
 | |
|           push @args, $_;
 | |
|         }
 | |
|       }
 | |
|     }
 | |
|   }
 | |
|   elsif(isPost()){
 | |
| 
 | |
|   }
 | |
|   elsif(isDelete()){
 | |
| 
 | |
|   }
 | |
|   else{
 | |
|     unsupportedRequestType();
 | |
|     exit(0);
 | |
|   }
 | |
| 
 | |
|   return @responses;
 | |
| }
 | |
| 
 | |
| sub nodesHandler{
 | |
|   my @responses;
 | |
|   my @args;
 | |
| 
 | |
|   #does it specify nodes in the URI?
 | |
|   if(defined $path[1]){
 | |
|     $request->{noderange} = $path[1];
 | |
|   }
 | |
|   #in the query string?
 | |
|   elsif(defined $q->param('nodeRange')){
 | |
|     $request->{noderange} = $q->param('nodeRange');
 | |
|   }
 | |
|   
 | |
|   if(isGet()){
 | |
|     my $subResource;
 | |
|     if(defined $path[2]){
 | |
|       $subResource = $path[2];
 | |
|     }
 | |
| 
 | |
|     if($subResource =~ "power"){
 | |
|       $request->{command} = 'rpower';
 | |
|       push @args, 'stat';
 | |
|     }
 | |
|     elsif($subResource =~ "bootState"){
 | |
|       $request->{command} = 'nodeset';
 | |
|       push @args,'stat';
 | |
|     }
 | |
|     elsif($subResource =~ "energy"){
 | |
|       $request->{command} = 'renergy';
 | |
| 
 | |
|       #no fields will default to 'all'
 | |
|       if(defined $q->param('field')){
 | |
|         foreach ($q->param('field')){
 | |
|           push @args, $_;
 | |
|         }
 | |
|       }
 | |
|     }
 | |
|     elsif($subResource =~ "osImage"){
 | |
|       
 | |
|     }
 | |
|     elsif($subResource =~ "status"){
 | |
|       $request->{command} = 'nodestat';
 | |
|     }
 | |
|     elsif($subResource =~ "inventory"){
 | |
|       $request->{command} = 'rinv';
 | |
|       if(defined $q->param('field')){
 | |
|         push @args, $q->param('field');
 | |
|       }
 | |
|       else{
 | |
|         push @args, 'all';
 | |
|       }
 | |
|     }
 | |
|     elsif($subResource =~ "location"){
 | |
|       $request->{command} = 'nodels';
 | |
|       push @args, 'nodepos';
 | |
|     }
 | |
|     else{
 | |
|       $request->{command} = 'nodels';
 | |
|       #if the table or field is specified in the URI
 | |
|       if(defined $subResource){
 | |
|         push @args, $subResource;
 | |
|       }
 | |
|       #maybe it's specified in the parameters
 | |
|       else{
 | |
|         push @args, $q->param('field');
 | |
|       }
 | |
|     }
 | |
|   }
 | |
|   elsif(isPut()){
 | |
|     my $subResource;
 | |
|     if(defined $path[2]){
 | |
|       $subResource = $path[2];
 | |
|     }
 | |
|     if($subResource =~ "bootState"){
 | |
|       $request->{command} = 'nodeset';
 | |
|       if(defined $q->param('boot')){
 | |
|         push @args, 'boot';
 | |
|       }
 | |
|       if(defined $q->param('install')){
 | |
|         if($q->param('install')){
 | |
|           push @args, "install=".$q->param('install');
 | |
|         }
 | |
|         else{
 | |
|           push @args, 'install';
 | |
|         }
 | |
|       }
 | |
|       if(defined $q->param('netboot')){
 | |
|         if($q->param('netboot')){
 | |
|           push @args, "netboot=".$q->param('netboot');
 | |
|         }
 | |
|         else{
 | |
|           push @args, 'netboot';
 | |
|         }
 | |
|       }
 | |
|       if(defined $q->param('statelite')){
 | |
|         if($q->param('statelite')){
 | |
|           push @args, "statelite=".$q->param('statelite');
 | |
|         }
 | |
|         else{
 | |
|           push @args, 'statelite';
 | |
|         }
 | |
|       }
 | |
|       if(defined $q->param('bmcSetup')){
 | |
|         push @args, "runcmd=bmcsetup";
 | |
|       }
 | |
|       #can't do this
 | |
|       #if(defined $q->param('shell')){
 | |
|         #push @args, 'shell';
 | |
|       #}
 | |
|     }
 | |
|     else{
 | |
|       sendErrorMessage($STATUS_BAD_REQUEST, "The subResource \'$request->{subResource}\' does not exist");
 | |
|     }
 | |
|   }
 | |
|   elsif(isPost()){
 | |
|     $request->{command} = 'nodeadd';
 | |
|     if(defined $q->param('groups')){
 | |
|       $request->{groups} = $q->param('groups');
 | |
|     }
 | |
| 
 | |
|     #since we can't predict which table fields will be passed
 | |
|     #we just pass everything else
 | |
|     for my $arg ($q->param){
 | |
|       if($arg !~ "nodeRange" && $arg !~ "groups"){
 | |
|         push @args, $arg;
 | |
|       }
 | |
|     }
 | |
|   }
 | |
|   elsif(isPatch()){
 | |
|     $request->{command} = 'nodech';
 | |
|   }
 | |
|   elsif(isDelete()){
 | |
|     #FYI:  the nodeRange for delete has to be specified in the URI
 | |
|     $request->{command} = 'noderm';
 | |
|   }
 | |
|   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')){
 | |
|       sendStatusMsg($STATUS_BAD_REQUEST, "fileName, table and operation must be specified for a POST on /notifications");
 | |
|     }
 | |
|     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{
 | |
|       sendStatusMsg($STATUS_BAD_REQUEST, "fileName must be specified for a DELETE on /notifications");
 | |
|     }
 | |
|   }
 | |
|   else{
 | |
|     unsupportedRequestType();
 | |
|     exit();
 | |
|   }
 | |
|   
 | |
|   push @{$request->{arg}}, @args;
 | |
|   print "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{
 | |
|       sendStatusMsg($STATUS_BAD_REQUEST, "The priority must be specified when creating a policy");
 | |
|       exit(0);
 | |
|     }
 | |
|   }
 | |
|   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{
 | |
|       sendStatusMsg($STATUS_BAD_REQUEST, "The priority must be specified when updating a policy");
 | |
|       exit(0);
 | |
|     }
 | |
|   }
 | |
|   else{
 | |
|     unsupportedRequestType();
 | |
|     exit();
 | |
|   }
 | |
| 
 | |
|   push @{$request->{arg}}, @args;
 | |
|   print "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} = 'tabdump';
 | |
|     push @{$request->{arg}}, 'site';
 | |
|     my $req = genRequest();
 | |
|     @responses = sendRequest($req);
 | |
|   }
 | |
|   elsif(isPut() || isPatch()){
 | |
|     $request->{command} = 'tabch';
 | |
|     if(defined $q->param('PUTDATA')){
 | |
|       my $entries = decode_json $q->param('PUTDATA');;
 | |
|       foreach (values %$entries){
 | |
|         my %fields = %$_;
 | |
|         foreach my $key (keys %fields){
 | |
|           if($key =~ /key/){
 | |
|             #the key needs to be first
 | |
|             unshift @args, "key=$fields{$key}";
 | |
|           }
 | |
|           else{
 | |
|             push @args, "site.$key=$fields{$key}";
 | |
|           }
 | |
|         }
 | |
|         push @{$request->{arg}}, @args;
 | |
|         my $req = genRequest();
 | |
|         my @subResponses = sendRequest($req);
 | |
|         #TODO:  look at the reponses and see if there are errors
 | |
|         push @responses, @subResponses;
 | |
|       }
 | |
|     }
 | |
|   }
 | |
|   else{
 | |
|     unsupportedRequestType();
 | |
|     exit();
 | |
|   }
 | |
| 
 | |
|   #change response formatting
 | |
|   foreach my $response (@responses){
 | |
|     foreach my $item (@{$response->{data}}){
 | |
|       if($item !~ /^#/)
 | |
|       {
 | |
|         my @values = split(/,/, $item);
 | |
|         my %item = (
 | |
|           entry => $values[0],
 | |
|           value => $values[1],
 | |
|           comments => $values[2],
 | |
|           disable => $values[3]);
 | |
|         push @data, \%item;
 | |
|       }
 | |
|     }
 | |
|   }
 | |
|   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()){
 | |
|     $request->{command} = 'tabdump';
 | |
|     if(defined $q->param('desc')){
 | |
|       push @args, '-d';
 | |
|     }
 | |
| 
 | |
|     #table was specified
 | |
|     if (defined $table){
 | |
|       push @args, $table;
 | |
|       if(!defined $q->param('desc')){
 | |
|         $formatType = 'splitCommas';
 | |
|       }
 | |
|     }
 | |
|   }
 | |
|   elsif(isPut() || isPatch()){
 | |
|     my $condition = $q->param('condition');
 | |
|     if(!defined $table || !defined $condition){
 | |
|       sendStatusMsg($STATUS_BAD_REQUEST, "The table and condition must be specified when adding, changing or deleting an entry");
 | |
|       exit(0);
 | |
|     }
 | |
|     $request->{command} = 'tabch';
 | |
|     if(defined $q->param('delete')){
 | |
|       push @args, '-d';
 | |
|       push @args, $condition;
 | |
|       push @args, $table;
 | |
|     }
 | |
|     else{
 | |
|       push @args, $condition;
 | |
|       for($q->param('value')){
 | |
|         push @args, "$table.$_";
 | |
|       }
 | |
|     }
 | |
|   }
 | |
|   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{
 | |
|         sendStatusMsg($STATUS_BAD_REQUEST, "The key must be specified when creating a non-cluster user");
 | |
|         exit(0);
 | |
|       }
 | |
|     }
 | |
|     #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{
 | |
|         sendStatusMsg($STATUS_BAD_REQUEST, "The key must be specified when creating a cluster user");
 | |
|         exit(0);
 | |
|       }
 | |
|     }
 | |
|   }
 | |
|   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{
 | |
|         sendStatusMsg($STATUS_BAD_REQUEST, "The key must be specified when deleting a non-cluster user");
 | |
|         exit(0);
 | |
|       }
 | |
|     }
 | |
|     else{
 | |
|       if(defined $q->param('userName')){
 | |
|         $request->{command} = 'xcatclientnnr';
 | |
|         push @args, 'clusteruserdel';
 | |
|         push @args, $q->param('userName');
 | |
|       } 
 | |
|       else{
 | |
|         sendStatusMsg($STATUS_BAD_REQUEST, "The userName must be specified when deleting a cluster user");
 | |
|         exit(0);
 | |
|       }
 | |
|     }
 | |
|   }
 | |
|   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{
 | |
|         sendStatusMsg($STATUS_BAD_REQUEST, "The key must be specified when updating a non-cluster user");
 | |
|         exit(0);
 | |
|       }
 | |
|     }
 | |
|     #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')){
 | |
|       sendStatusMsg($STATUS_BAD_REQUEST, "The object must be specified.");
 | |
|     }
 | |
|     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')){
 | |
|       sendStatusMsg($STATUS_BAD_REQUEST, "The object must be specified.");
 | |
|     }
 | |
|     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{
 | |
|       sendStatusMsg($STATUS_BAD_REQUEST, "Either the help info must be requested or the object must be specified or the flag that indicates everything should be removed.");
 | |
|       exit(0);
 | |
|     }
 | |
|     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;
 | |
|   if(defined $q->param('nodeRange')){
 | |
|     $request->{noderange} = $q->param('nodeRange');
 | |
|   }
 | |
|   if(defined $q->param('verbose')){
 | |
|     push @args, '-V';
 | |
|   }
 | |
| 
 | |
|   if(isGet()){
 | |
|     $request->{command} = 'lsvm';
 | |
|     if(defined $q->param('all')){
 | |
|       push @args, '-a';
 | |
|     }
 | |
|   }
 | |
|   elsif(isPost()){
 | |
|     if(defined $q->param('clone')){
 | |
|       $request->{command} = 'clonevm';
 | |
|       if(defined $q->param('target')){
 | |
|         push @args, '-t';
 | |
|         push @args, $q->param('target');
 | |
|       }
 | |
|       if(defined $q->param('source')){
 | |
|         push @args, '-b';
 | |
|         push @args, $q->param('source');
 | |
|       }
 | |
|       if(defined $q->param('detached')){
 | |
|         push @args, '-d';
 | |
|       }
 | |
|       if(defined $q->param('force')){
 | |
|         push @args, '-f';
 | |
|       }
 | |
|     }
 | |
|     else{
 | |
| #man page for mkvm needs updating for options
 | |
|       $request->{command} = 'mkvm';
 | |
|       if(defined $q->param('cec')){
 | |
|         push @args, '-c';
 | |
|         push @args, $q->param('cec');
 | |
|       }
 | |
|       if(defined $q->param('startId')){
 | |
|         push @args, '-i';
 | |
|         push @args, $q->param('startId');
 | |
|       }
 | |
|       if(defined $q->param('source')){
 | |
|         push @args, '-l';
 | |
|         push @args, $q->param('source');
 | |
|       }
 | |
|       if(defined $q->param('profile')){
 | |
|         push @args, '-p';
 | |
|         push @args, $q->param('profile');
 | |
|       }
 | |
|       if(defined $q->param('full')){
 | |
|         push @args, '--full';
 | |
|       }
 | |
|       #if(defined $q->param('master')){
 | |
|         #push @args, '-m';
 | |
|         #push @args, $q->param('master');
 | |
|       #}
 | |
|       #if(defined $q->param('size')){
 | |
|         #push @args, '-s';
 | |
|         #push @args, $q->param('size');
 | |
|       #}
 | |
|       #if(defined $q->param('force')){
 | |
|         #push @args, '-f';
 | |
|       #}
 | |
|     }
 | |
|   }
 | |
|   elsif(isPut() || isPatch()){
 | |
|     $request->{command} = 'chvm';
 | |
|     if(defined $q->param('field')){
 | |
|       foreach ($q->param('field')){
 | |
|         push @args, $_;
 | |
|       }
 | |
|     }
 | |
|     
 | |
|   }
 | |
|   elsif(isDelete()){
 | |
|     $request->{command} = 'rmvm';
 | |
|     if(defined $request->{nodeRange}){
 | |
|       if(defined $q->param('retain')){
 | |
|         push @args, '-r';
 | |
|       }
 | |
|       if(defined $q->param('service')){
 | |
|         push @args, '--service';
 | |
|       }
 | |
|     }
 | |
|     else{
 | |
|       sendStatusMsg($STATUS_BAD_REQUEST, "The node range must be specified when deleting vms");
 | |
|       exit(0);
 | |
|     }
 | |
|   }
 | |
|   else{
 | |
|     unsupportedRequestType();
 | |
|     exit();
 | |
|   }
 | |
| 
 | |
|   push @{$request->{arg}}, @args;
 | |
|   my $req = genRequest();
 | |
|   my @responses = sendRequest($req);
 | |
|   return @responses;
 | |
| }
 | |
| 
 | |
| #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;
 | |
|   #trim the serverdone message off
 | |
|   if(exists $data[0][$#{$data[0]}]->{serverdone}){
 | |
|     pop @{$data[0]};
 | |
|   }
 | |
|   if(exists $formatters{$format}){
 | |
|     $formatters{$format}->(@data);
 | |
|   }
 | |
| }
 | |
| 
 | |
| sub wrapJson
 | |
| {
 | |
|   my @data = shift;
 | |
|   print header('application/json');
 | |
|   my $json;
 | |
|   $json->{'data'} = \@data;
 | |
|   print to_json($json);
 | |
| }
 | |
| 
 | |
| sub wrapHtml
 | |
| {
 | |
|   my $item;
 | |
|   my @response = shift;
 | |
|   my $baseUri = $url.$pathInfo;
 | |
|   if($baseUri !~ /\/^/)
 | |
|   {
 | |
|     $baseUri .= "/";
 | |
|   }
 | |
|   #print $q->p("dumping in wrapHtml ".Dumper(@response));
 | |
|   foreach my $data (@response){
 | |
|     if(@$data[0]->{error}){
 | |
|       if(@$data[0]->{error}[0] =~ /Permission denied/ || @$data[0]->{error}[0] =~ /Authentication failure/){
 | |
|         sendStatusMsg($STATUS_UNAUTH, @$data[0]->{error}[0]);
 | |
|       }
 | |
|       else{
 | |
|         sendStatusMsg($STATUS_FORBIDDEN, @$data[0]->{error}[0]);
 | |
|       }
 | |
|       exit(0);
 | |
|     }
 | |
|     else{
 | |
|       if(isPost()){
 | |
|         sendStatusMsg($STATUS_CREATED);
 | |
|       }
 | |
|       else{
 | |
|         sendStatusMsg($STATUS_OK);
 | |
|       }
 | |
|     }
 | |
|     foreach my $element (@$data){
 | |
|       #if($element->{error}){
 | |
|       if($element->{node}){
 | |
|         print "<table border=1>";
 | |
|         foreach $item (@{$element->{node}}){
 | |
|           #my $url = $baseUri.$item->{name}[0];
 | |
|           #print "<tr><td><a href=$url>$item->{name}[0]</td></tr>";
 | |
|           print "<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]){
 | |
|                 print "<td>$item->{data}[0]->{desc}[0]</td>";
 | |
|               }
 | |
|               if(ref($item->{data}[0]) eq 'HASH' && exists $item->{data}[0]->{contents}[0]){
 | |
|                 print "<td>$item->{data}[0]->{contents}[0]</td>";
 | |
|               }
 | |
|             }
 | |
|             else{
 | |
|               print "<td>$item->{data}[0]</td>";
 | |
|             }
 | |
|           }
 | |
|           elsif(exists $item->{error}){
 | |
|             print "<td>$item->{error}[0]</td>";
 | |
|           }
 | |
|           print "</tr>";
 | |
|         }
 | |
|         print "</table>";
 | |
|       }
 | |
|       elsif($element->{data}){
 | |
|         print "<table border=1>";
 | |
|         foreach $item (@{$element->{data}}){
 | |
|           my @values = split(/:/, $item, 2);
 | |
|           #print "<tr><td><a href=$url$pathInfo$key>$key</a></td><td>$value</td></tr>";
 | |
|           print "<tr>";
 | |
|           foreach (@values){
 | |
|             if($formatType =~ /splitCommas/){
 | |
|               my @fields = split(/,/, $_,-1);
 | |
|               foreach (@fields){
 | |
|                 print "<td>$_</td>";
 | |
|               }
 | |
|             }
 | |
|             else{
 | |
|               print "<td>$_</td>";
 | |
|             }
 | |
|           }
 | |
|           print "</tr>\n";
 | |
|         }
 | |
|         print "</table>";
 | |
|       }
 | |
|       elsif($element->{info}){
 | |
|         print "<table border=1>";
 | |
|         foreach $item (@{$element->{info}}){
 | |
|           my @values = split(/:/, $item, 2);
 | |
|           #print "<tr><td><a href=$url$pathInfo$key>$key</a></td><td>$value</td></tr>";
 | |
|           print "<tr>";
 | |
|           foreach (@values){
 | |
|             if($formatType =~ /splitCommas/){
 | |
|               my @fields = split(/,/, $_,-1);
 | |
|               foreach (@fields){
 | |
|                 print "<td>$_</td>";
 | |
|               }
 | |
|             }
 | |
|             else{
 | |
|               print "<td>$_</td>";
 | |
|             }
 | |
|           }
 | |
|           print "</tr>\n";
 | |
|         }
 | |
|         print "</table>";
 | |
|         #foreach $item (@{$element->{info}}){
 | |
|           #print $item;
 | |
|         #}
 | |
|       }
 | |
|     }
 | |
|   }
 | |
| }
 | |
| 
 | |
| sub wrapXml
 | |
| {
 | |
|   my @data = shift;
 | |
|   print header('text/xml');
 | |
|   foreach(@data){
 | |
|     foreach(@$_){
 | |
|       print XMLout($_, RootName=>'',NoAttr=>1,KeyAttr=>[]);
 | |
|     }
 | |
|   }
 | |
| }
 | |
| 
 | |
| #general tests for valid requests and responses with HTTP codes here
 | |
| if(!doesResourceExist($resource)){
 | |
|   sendStatusMsg($STATUS_NOT_FOUND, "Resource '$resource' does not exist");
 | |
|   exit(0);
 | |
| }
 | |
| else{
 | |
|   if($DEBUGGING){
 | |
|     print $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;
 | |
|     print $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/) {
 | |
|       sendStatusMsg($STATUS_TIMEOUT, "Connection failure: SSL Timeout or incorrect certificates in ~/.xcat");
 | |
|       exit(0);
 | |
|     }
 | |
|     else{
 | |
|       sendStatusMsg($STATUS_SERVICE_UNAVAILABLE, "Connection failure: $@");
 | |
|       exit(0);
 | |
|     }
 | |
|   }
 | |
| 
 | |
|   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
 | |
|       $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) {
 | |
|     sendStatusMsg($STATUS_SERVICE_UNAVAILABLE, "ERROR/WARNING: communication with the xCAT server seems to have been ended prematurely");
 | |
|     exit(0);
 | |
|   }
 | |
|   
 | |
|   if($DEBUGGING){
 | |
|     print $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
 | |
|   sendStatusMsg($STATUS_UNAUTH, $responses[0]->{error}[0]);
 | |
|   return 0;
 | |
| }
 |