This document describes the principles and practices to implement the REST API interface for xCAT. The rest api framework has been determined, the implementated resources are the good examples for new developers to implement new resources.
The resource name must be noun. If the resource name can be a collection of multiple resource, use plurals.
e.g. Since the URI for xcat node can be requested on multiple nodes, the URI should be /nodes instead of /node.
Present all URI parameters inside the URI itself. Try not to use the URI parameter section (i.e. after "?") except the filter/search. Mostly, we don't need URI parameters for GET method. For example, this URI can be used to get the 'arch','groups' and 'mgt' attributes for the node 'mynode'"
/nodes/mynode/attr/arch,groups,mgt
The usage of PUT and POST
PUT - is used to create or update a resource for which you know what the resource name is (or will be), so you can include it in the URI in the http request. PUT should be used for most xCAT create operations since the URI for resource is predictable before creating it.
POST - is used to create a resource for which the resource name (and therefore the URI) is not known yet, because it will be generated by xCAT.
The definition for all the resource is stored in the restapi.pl::%URIdef which is a perl hash that includes the resource descriptions, URI format, supported methods and the usage information for each resource.
The format and principles to define a resource in the %URIdef:
|--node - Resource Group | `--allnode - Resource Name | `--desc - Description for the Resource | `--desc[1..10] - Additional description for the Resource | `--matcher - The matcher which is used to match the URI to the Resource | `--GET - The info is used to handle the GET request | `--desc - Description for the GET operation | `--desc[1..10] - Additional description for the GET operation | `--usage - Usage message. The format must be '|Parameters for the GET request|Returns for the GET request|'. The message in the '|' can be black, but the delimiter '|' must be kept. | `--example - Example message. The format must be '|Description|GET|URI PUT/POST_data|Return Msg|'. The messages in the four sections must be completed. | `--cmd - The xCAT command line coammnd which will be used to complete the request. It's not a must have attribute. | `--fhandler - The call back subroutine which is used to handle the GET request. Generally, it parses the parameters from request and then call xCAT command. This subroutine can be exclusive or shared. | `--outhdler - The call back subroutine which is used to handle the GET request. Generally, it parses the xml output from the 'fhandler' and then format the output to JSON. This subroutine can be exclusive or shared. | `--PUT - The info is used to handle the PUT request | `--POST - The info is used to handle the POST request | `--DELETE - The info is used to handle the DELETE request
The prerequisite to implement the correct output format is that the 'error/errorcode' returned by the xcatd xml response should be valid and correct. If it's not, the xCAT team should fix it.
For all the GET/PUT/POST/DELETE methods, the output will only includes 'error' and 'errorcode' properties:
{ error:[ msg1, msg2, ... ], errorcode:error_number }
If the output can be grouped by the object (resource) name, and the information being returned is attributes of the object, then use the object name as the hash key and make the value be a hash of its attributes/values:
{ object1: { a1 : v1, a2 : v2, ... }, object2: { a1 : v1, a2 : v2, ... }, }
If the output can be grouped by the object (resource) name, but the information being returned is not attributes of the object, then use the object name as the hash key and make the value be an array of strings:
{ object1: [ msg1, msg2, ... ], object2: [ msg1, msg2 ... ], }
An example of this case is the output of reventlog:
{ "node1" : [ "09/07/2013 10:05:02 Event Logging Disabled, Log Area Reset/Cleared (SEL Fullness)", ... ], }
If the output is not object related, put all the output in a list (array):
[ msg1, msg2, ... ]
There will be no output for operations that succeed. (We made this decision because the output for them is always not formatted, and no program will read it if xcat indicates the operation has succeeded.)
Since POST methods can either be creates or general actions, there is not as much consistency. In the case of a create, the rule is the same as PUT/DELETE (no output if successful). For actions that have output that matters (e.g. xdsh, xdcp, updatenode), the rules are like the GET method.
Use parameter 'pretty=1' - Display the readable json format in the curl command
curl -X GET -k 'https://127.0.0.1/xcatws/node/node1?userName=root&password=cluster&pretty=1'
Use parameter 'debug=1' - Display debug messages like the URI which is passed to the restapi.pl, the xml request and response which communicate with xcatd. 'debug=2' will display additional information.
curl -X GET -k 'https://127.0.0.1/xcatws/node/node1?userName=root&password=cluster&pretty=1&debug=1'
Use perl debug mode to track the step by step execution
cd /opt/xcat/ws
perl -d ./restapi.pl GET /node/node1 root:cluster
Use formatmsg.pl to format the GET output to be a flat text for the fourth part the example description
curl -X GET -k 'https://127.0.0.1/xcatws/nodes/node1/vitals/fanspeed?userName=root&password=cluster&pretty=1' 2>/dev/null | ./formatmsg.pl
{\n \"node1\":{\n \"Fan 1A Tach\":\"3219 RPM\",\n \"Fan 4B Tach\":\"2720 RPM\",\n \"Fan 3B Tach\":\"2560 RPM\",\n \"Fan 4A Tach\":\"3330 RPM\",\n \"Fan 2A Tach\":\"3256 RPM\",\n \"Fan 1B Tach\":\"2592 RPM\",\n \"Fan 3A Tach\":\"3145 RPM\",\n \"Fan 2B Tach\":\"2592 RPM\"\n }\n}
The file formatmsg.pl
# cat formatmsg.pl #! /usr/bin/perl my $out; while (<STDIN>) { $msg = $_; $msg =~ s/\n/\\n/g; $msg =~ s/"/\\"/g; $out .= $msg; } $out =~ s/(\\n)*$//g; print "$out\n";
Get all the nodes in the xCAT cluster
curl -X GET -k 'https://127.0.0.1/xcatws/node?userName=root&password=cluster&pretty=1'
"all",
"mmnodex3650m4n01",
"mmnodex3650m4n02",
"node1",
"node2",
"node3",
"nodexxx",
"x346n01",
"x3550m4n01",
"x3550m4n02",
"x3550m4n02k01",
"x3550m4n02k02",
"x3550m4n02k03",
"x3550m4n03",
"x3650m4n03",
"x3650m4n04",
"x3650m4n05",
"x3650m4n06",
"x3650m4n07",
"zxnode2"
Get all the attributes for node1
curl -X GET -k 'https://127.0.0.1/xcatws/node/node1?userName=root&password=cluster&pretty=1'
{
"node1":{
"profile":"compute",
"netboot":"xnba",
"ip":"192.168.1.10",
"arch":"x86_64",
"currchain":"boot",
"os":"rhels6.4",
"mac=mac":"6c:ae:8b:41:3f:53",
"kernel":"xcat/osimage/rhels6.4-x86_64-install-compute/vmlinuz",
"mgt":"ipmi",
"bmc":"192.168.1.110",
"groups":"111",
"currstate":"install rhels6.4-x86_64-compute",
"postscripts":"syslog,remoteshell,syncfiles",
"provmethod":"rhels6.4-x86_64-install-compute",
"updatestatustime":"03-20-2014 15:36:56",
"updatestatus":"failed",
"installnic":"mac",
"kcmdline":"quiet repo=http://!myipfn!:80/install/rhels6.4/x86_64 ks=http://!myipfn!:80/install/autoinst/node1 ksdevice=mac=6c:ae:8b:41:3f:53",
"initrd":"xcat/osimage/rhels6.4-x86_64-install-compute/initrd.img",
"statustime":"03-19-2014 10:51:53",
"postbootscripts":"otherpkgs"
}
}
Change the 'mgt' attribute for node1
curl -k -X PUT -H Content-Type:application/json 'https://127.0.0.1/xcatws/node/node1?userName=root&password=cluster&pretty=1' --data '{"mgt":"ipmi"}'