(Quick Reference)

3 API Documentation

3 API Documentation

Introduction

The Moab® Web Services (MWS) provide a set of RESTful resources that can be used to create, read, update, and delete various objects in the Moab® Workload Manager.

3.1 RESTful Web Services

In order to understand how to use Moab Web Services, it is first necessary to give a brief introduction to REST. REST (Representational State Transfer) is a set of guidelines which utilizes the full HTTP (Hypertext Transfer Protocol) specification along with endpoint URLs that describe resources. The HTTP methods used in REST are composed of the following:

MethodDescription
GETQuery for a list or a single resource.
POSTCreating a resource.
PUTModifying a resource.
DELETEDeleting a resource.

In comparison to other architectures of web services which use a single HTTP method and service endpoint to perform multiple types of operations (such as a POST operation to a URL), REST utilizes all of the available HTTP methods and URLs that directly correlate to resources. For example, RESTful web services for books in a library may expose many URL endpoints and the HTTP methods available for each such as GET, POST, PUT, and DELETE. The list below gives the methods, URLs, and descriptions for a sample set of services. The number 1 represents a unique identifier for books in each case.

MethodURLDescription
GET/booksRetrieves a list of all books in the library.
POST/booksCreates a new book.
GET/books/1Retrieves a single book.
PUT/books/1Modifies a single book.
DELETE/books/1Deletes a single book.

Note that in the cases of the POST and PUT operations, additional information may be needed to describe the resource to be created or the fields that should be modified.

Moab Web Services provides RESTful web services for many resources. The methods and URLs available are documented in the Resources section.

3.2 Data Format

JSON (JavaScript Object Notation) is the data format used for all communication with MWS. This format makes use of two main structures: collections of key/value pairs called objects and ordered lists of values called arrays . Objects are defined by using curly braces ({}), and arrays are defined by using square brackets ([]). A JSON object or array may contain several different types of values including numbers, booleans (true/false), strings, objects, arrays, or the keyword 'null' representing no value. For example, a simple JSON object might be defined as:

{
  "number": 1,
  "decimalNumber": 1.2,
  "boolean": true,
  "string": "Any string",
  "dateString": "2013-05-23 17:32:02 UTC",
  "object": {
    "key": "value"
  },
  "array": [
    "value1",
    "value2"
  ],
  "nullValue": null
}

Dates in MWS, for both input and output, use the pattern "yyyy-MM-dd HH:mm:ss ZZZ". For more details on that pattern, see Joda-Time DateTimeFormat. For a list of valid time zone IDs, see Joda-Time Available Time Zones.

For more information on JSON, see json.org.

The data format of MWS is defined as follows:

  • Input for a POST or PUT must be in JSON format. Set the Content-Type header to application/json.
  • Output is in JSON format and always consists of an object with zero or more key/value pairs.
  • The output may also be "pretty-printed" or formatted for human viewing by sending a URL parameter. See Global URL Parameters for more information.

3.3 Global URL Parameters

All URL parameters are optional.

ParameterValid ValuesDescription
api-versionIntegerRequests a specific API version
pretty true Controls pretty printing of output
fieldsComma-Separated StringIncludes only specified fields in output
exclude-fieldsComma-Separated StringExcludes specified fields from output
maxIntegerThe maximum number of items to return
offsetIntegerThe index of the first item to return

API Version (api-version)

See Requesting Specific API Versions for information on this parameter and how it should be used.

Pretty (pretty)

By default, the output is easy for a machine to read but difficult for humans to read. The pretty parameter formats the output so that it is easier to read.

Field Selection (fields)

The fields parameter will include only the specified fields in the output. For list queries, the field selection acts on the objects in results and not on the totalCount or results properties themselves.

The format of the fields parameter is a comma-separated list of properties that should be included, as in id,state. Using periods, sub-objects may also be specified, and fields of these objects may be included as well. This is done with the same syntax for both single sub-objects and lists of sub-objects, as in id,requirements.requiredNodeCountMinimum,blockReason.message.

Example for a job query

Request
GET /rest/jobs?api-version=2&fields=name,flags,requirements.taskCount,dates.createdDate

Response
{
  "totalCount": 1,
  "resultCount": 1,
  "results": [  {
    "dates": {"createdDate": "2012-10-17 01:11:54 UTC"},
    "flags": ["GLOBALQUEUE"],
    "name": "Moab.24",
    "requirements": [{"taskCount": 1}]
  }]
}

Field Exclusion (exclude-fields)

The exclude-fields parameter is the opposite of the fields parameter. All fields will be included in the output except those that are specified. For list queries, the field exclusion acts on the objects in results and not on the totalCount or results properties themselves.

The format of the exclude-fields parameter is a comma-separated list of properties that should be excluded from the output, as in id,state. Using periods, sub-objects may also be specified, and fields of these objects may be excluded as well. This is done with the same syntax for both single sub-objects and lists of sub-objects, as in id,requirements.requiredNodeCountMinimum,blockReason.message.

Example

Suppose a query returns the following JSON:

Request with No Field Exclusion
GET /objects

Response
{
  "id": "1",
  "listOfStrings":   [
    "string1",
    "string2"
  ],
  "listOfObjects": [  {
    "item1": "value1",
    "item2": "value2"
  }],
  "singleObject":   {
    "id": "obj1",
    "field1": "value1"
  }
}

The same query with exclude-fields would return the following output:

Request with Field Exclusion
GET /objects?exclude-fields=id,listOfObjects.item2,singleObject.field1,listOfStrings

Response
{
  "listOfObjects": [{"item1": "value1"}],
  "singleObject": {"id": "obj1"}
}

Sorting (sort)

Services, Service Templates, Images, and Events support sorting based on MongoDB syntax by using the sort parameter. To sort in ascending order, specify a 1 for the sorting field. To sort in descending order, specify a -1. Objects can also be sorted on nested fields by using dot notation to separate the sub-fields, such as field.subfield1.subfield2.

Examples

To sort services in ascending order by account:

http://localhost/mws/rest/services?sort={"account":1}

To sort services in descending order by account:

http://localhost/mws/rest/services?sort={"account":-1}

To sort services in descending order by processors:

http://localhost/mws/rest/services?sort={"attributes.moab.job.resources.procs":-1}

To sort service templates in ascending order by name:

http://localhost/mws/rest/service-templates?sort={"name":1}

To sort service templates in descending order by name:

http://localhost/mws/rest/service-templates?sort={"name":-1}

To sort service templates in ascending order by the nested field template:

http://localhost/mws/rest/service-templates?sort={"attributes.moab.job.template":1}

3.4 Requesting Specific API Versions

Because of significant changes in the API introduced in 7.2, MWS possesses a versioned API. The api-version URL parameter may be used to change the requested API version for any call to MWS. The current valid API versions with their corresponding MWS versions are shown in the table below:

API VersionMWS VersionDocumentation
17.0 and 7.1MWS 7.1.1 Documentation
27.2Contained within this document
latestLatestContained within this document

Additionally, several points should be noted:

  • If no API version is requested, it will default to version 1.
  • The Resources documentation contains information for the latest API version. For documentation of previous API versions, please see the table above.
  • When the latest API version is requested, it resolves to the latest API version of MWS, such as 2 for MWS 7.2.

Examples

GET http://localhost:8080/mws/rest/nodes
// Data returned uses API version 1

GET http://localhost:8080/mws/rest/nodes?api-version=1 // Data returned uses API version 1

GET http://localhost:8080/mws/rest/nodes?api-version=2 // Data returned uses API version 2

GET http://localhost:8080/mws/rest/nodes?api-version=latest // Data returned uses API version 2

3.5 Responses and Return Codes

Various HTTP responses and return codes are generated from MWS operations. These are documented below according to the operation that they are associated with.

Listing and Showing Resources

For any successful list or show operation (GET), a 200 OK response code is always returned. No additional headers beyond those typical of a HTTP response are given in the response.

The body of this response consists of the results of the list or show operation. For a list operation, the results are wrapped in metadata giving total and result counts. The result count represents the number of resource records returned in the current request, and the total count represents the number of all records available. These differ when querying or the max and offset parameters are used. The following is an example of a list operation response:

JSON List Response Body
{
	"resultCount":1,
	"totalCount":5,
	"results":[
		{
			"id":"Moab.1",
			…
		}
	]
}

For a show operation, the result is given as a single object:

JSON Show Response Body
{
	"id":"Moab.1",
	…
}

Creating Resources

A successful creation (POST) of a resource has two potential response codes:

  • If the resource was created immediately, a 201 Created response code is returned.
  • If the resource is still being created, a 202 Accepted response code is returned.

In either case, a Location header is added to the response with the full URL which can be used to get more information about the newly created resource or the task associated with creating the resource (if a 202 is returned).

Additionally, the body of the response will contain the unique identifier of the newly created resource or the unique identifier for the task associated with creating the resource (if a 202 is returned).

For example, during creation or submission of a job, a 201 response code is returned with the following response headers and body:

Job Creation Response Headers
HTTP/1.1 201 Created
Server: Apache-Coyote/1.1
Location: /mws/rest/jobs/Moab.21
X-Moab-Status: Success
X-Moab-Code: 000
Content-Type: application/json;charset=utf-8
Content-Length: 16
Date: Wed, 21 Dec 2011 23:04:47 GMT

Job Creation Response Body
{"id":"Moab.21"}

For another resource that is not immediately created, such as virtual machines, the response headers and body are shown below. In this case, a job is submitted to track the progress of the VM creation. This job contains information pertaining to the VM that is being created.

VM Creation Response Headers
HTTP/1.1 202 Accepted
Server: Apache-Coyote/1.1
Location: /mws/rest/jobs/vmcreate-1
X-Moab-Status: Success
X-Moab-Code: 000
Content-Type: application/json;charset=utf-8
Content-Length: 23
Date: Wed, 21 Dec 2011 23:12:50 GMT

VM Creation Response Body
{"jobId":"vmcreate-1"}

As can be seen, the body of the response contains only a job ID and not the ID of the virtual machine.

Modifying Resources

For any successful resource modification operation (PUT), a 200 OK or 202 Accepted response code is returned. A 200 response code signifies that the modification was immediately completed. No additional headers are returned in this case. A 202 response code is used again to signify that the modification is not yet complete and additional actions are taking place. In this case, a Location header is also returned with the full URL of the resource describing the additional actions.

In the case of a 200 response code, the body of this response typically consists of an object with a single messages property containing a list of statuses or results of the modification(s). However, a few exceptions to this rule exist as documented in the Resources section. In the case of a 202 response code, the format is the same as for a 202 during a creation operation, in that the body consists of an object with the unique identifier for the task associated with the additional action(s).

For example, when modifying a job, several messages may be returned as follows with the associated 200 response code.

Job Modification Response Headers
HTTP/1.1 200 OK
Server: Apache-Coyote/1.1
X-Moab-Status: Success
X-Moab-Code: 000
X-Moab-Message:
Content-Type: application/json;charset=utf-8
Content-Length: …
Date: Thu, 22 Dec 2011 16:49:43 GMT

JSON Modify Response Body
{
	"messages":[
		"gevent processed",
		"variables successfully modified"
	]
}

When modifying a virtual machine, however, the action sometimes does not occur immediately, such as when migrating the VM to another hypervisor as described in the VM documentation. In this case, the headers and response body are as follows:

VM Modification Response Headers
HTTP/1.1 202 Accepted
Server: Apache-Coyote/1.1
Location: /mws/rest/jobs/vmmigrate-1
X-Moab-Status: Success
X-Moab-Code: 000
Content-Type: application/json;charset=utf-8
Content-Length: 22
Date: Wed, 21 Dec 2011 23:12:50 GMT

VM Modification Response Body
{"jobId":"vmmigrate-1"}

Deleting Resources

For any successful resource deletion operation (DELETE), a 200 OK or 202 Accepted response code is returned. A 200 response code signifies that the deletion was immediately completed. No additional headers are returned in this case. A 202 response code is used again to signify that the deletion is not yet complete and additional actions are taking place. In this case, a Location header is also returned with the full URL of the resource describing the additional actions.

In the case of a 200 response code, the body of this response is empty. In the case of a 202 response code, the format is the same as for a 202 during a creation operation, in that the body consists of an object with the unique identifier for the task associated with the additional action(s).

For example, when deleting a job, a 200 response code is returned with an empty body as shown below.

Job Deletion Response
HTTP/1.1 200 OK
Server: Apache-Coyote/1.1
X-Moab-Status: Success
X-Moab-Code: 000
X-Moab-Message:
Content-Type: application/json;charset=utf-8
Content-Length: 0
Date: Thu, 22 Dec 2011 16:49:43 GMT

When deleting a virtual machine, however, the action does not occur immediately. In this case, the headers and response body are as follows:

VM Deletion Response Headers
HTTP/1.1 202 Accepted
Server: Apache-Coyote/1.1
Location: /mws/rest/jobs/vmdestroy-1
X-Moab-Status: Success
X-Moab-Code: 000
Content-Type: application/json;charset=utf-8
Content-Length: 22
Date: Wed, 21 Dec 2011 23:12:50 GMT

VM Deletion Response Body
{"jobId":"vmdestroy-1"}

Moab Response Headers

In addition to the typical HTTP headers and the Location header described above, several headers are returned if the operations directly interact with Moab. These headers are described in the following table:

NameDescription
X-Moab-StatusOne of Success, Warning, or Failure. Describes the overall status of the Moab request.
X-Moab-CodeA three digit code specifying the exact error encountered, used only in debugging.
X-Moab-MessageAn optional message returned by Moab during the request.

3.6 Error Messages

Below is an explanation of what error message format to expect when an HTTP status code other than 20x is returned. All error codes have a response code of 400 or greater.

400 Bad Request

This response code is returned when the request itself is at fault, such as when trying to modify a resource with an empty PUT request body or when trying to create a new resource with invalid parameters. The response body is as follows:

{
	"messages":[
		"Message describing error",
		"Possible prompt to take action"
	]
}

401 Unauthorized

This response code is returned when authentication credentials are not supplied or are invalid. The response body is as follows:

{
	"messages":[
		"You must be authenticated to access this area"
	]
}

403 Forbidden

This response code is returned when the credentials supplied are valid, but the permissions granted are insufficient for the operation. This occurs when using Application Accounts with limited access.

{
	"messages":[
		"You are not authorized to access this area"
	]
}

404 Not Found

This response code is returned when the request specifies a resource that does not exist. The response body is as follows:

{
	"messages":[
		"The resource with id 'uniqueId' was not found"
	]
}

405 Method Not Allowed

This response code is returned when a resource does not support the specified HTTP method as an operation. The response body is as follows:

{
	"messages":[
		"The specified HTTP method is not allowed for the requested resource"
	]
}

500 Internal Server Error

This indicates that there was an internal server error while performing the request, or that an operation failed in an unexpected manner. These are the most serious errors returned by MWS. If additional information is needed, the MWS log may contain further error data. The response body is as follows:

{
	"messages":[
		"A problem occurred while processing the request",
		"A message describing the error"
	]
}

3.7 Pre and Post-Processing Hooks

MWS provides functionality to intercept and modify data sent to and returned from web services for all available resources. This is done by creating hooks in Groovy files located in a sub-directory of the MWS_HOME directory (/opt/mws/hooks by default).

The full reference for available hooks and methods available to them can be found on the Hooks page in the reference guide.

Configuring Hooks

The directory of the hooks folder may be changed by providing a value for mws.hooks.location in the configuration file. If the directory starts with a path separator (ie /path/to/hooks), it will be treated as an absolute path. Otherwise, it will be used relative to the location of the MWS home directory.

For example, if the MWS home directory is set to /opt/mws, the hooks directory by default would be in /opt/mws/hooks. Changing the mws.hooks.location property to myhooks would result in the hooks directory being located at /opt/mws/myhooks. Due to the default location of the MWS home directory, the default directory of the hooks directory is /opt/mws/hooks.

On startup, if the hooks directory does not exist, it will be created with a simple README.txt file with instructions on how to create hooks, the objects available, and the hooks available. If the folder or file is unable to be created, a message will be printed on the log with the full location of a README file, copied into a temporary directory.

Defining Hooks for a Resource

Hooks are defined for resources by creating groovy class files in the hooks directory (MWS_HOME/hooks by default). Each groovy file must be named by the resource URL it is associated with and end in ".groovy". The following table shows some possible hook files that may be created. Notice that the virtual machines hook file is abbreviated as vms, just as the URL for virtual machines is /rest/vms. In all cases, the hook file names will match the URLs.

ResourceHook Filename
Jobsjobs.groovy
Nodesnodes.groovy
Virtual Machinesvms.groovy
Pending Actionspending-actions.groovy
url url.groovy

A complete example of a hook file is as follows:

Complete Hook File
// Example before hook
def beforeList = {
	// Perform actions here
	// Return true to allow the API call to execute normally
	return true
}

def beforeShow = { // Perform actions here // Render messages to the user with a 405 Method Not Allowed // HTTP response code renderMessages("Custom message here", 405) // Return false to stop normal execution of the API call return false }

// Example after hook def afterList = { o -> if (!isSuccess()) { // Handle error here return false } // Perform actions here return o }

As the specific format for the hooks for before and after are different, each will be explained separately.

Before Hooks

As shown above, before hooks require no arguments. They can directly act on several properties, objects, and methods as described in the Hooks reference guide. The return value is one of the most important aspects of a before hook. If it is false, a renderMessages, renderObject, renderList, render, or redirect method must first be called. This signifies that the API call should be interrupted and the render or redirect action specified within the hook is to be completed immediately.

A return value of true signifies that the API call should continue normally. Parameters, session variables, request and response variables may all be modified within a before hook.

If no return value is explicitly given, the result of the last statement in the before hook to be executed will be returned. This may cause unexpected behavior if the last statement resolves to false.

For all methods available to before hooks as well as specific examples, see the Hooks page in the reference guide.

After Hooks

After hooks are always passed one argument: the object or list that is to be rendered as JSON. This may be modified as desired, but note that the object or list value is either a JSONArray or JSONObject. Therefore, it may not be accessed and modified as a typical groovy Map.

Unlike before hooks, after hooks should not call the render* methods directly. This method will automatically be called on the resulting object or list returned. The redirect and render methods should also not be called at this point. Instead, if a custom object or list is desired to be used, the serializeObject and serializeList methods are available to create suitable results to return.

The return value of an after hook may be one of two possibilities:

  1. The potentially modified object or list passed as the first argument to the hook. In this case, this value will override the output object or list unless it is null.
  2. Null or false. In this case, the original, unmodified object or list will be used in the output.

The return value of the after hook, if not null or false, must be the modified object passed into the hook or an object or list created with the serialize* methods.

For all methods available to after hooks as well as specific examples, see the Hooks page in the reference guide.

Error Handling

After hooks, unlike the before hooks, have the possibility of handling errors encountered during the course of the request. Handling errors is as simple as adding a one-line check to the hook as shown above or in the following code:

if (!isSuccess()) {
	// Handle error
	return false
}

It is recommended that each after hook contain at least these lines of code to prevent confusion on what the input object or list represents or should look like.

The isSuccess() function is false if and only if the HTTP response code is 400 or higher, such as a 404 Not Found, 400 Bad Request, or 500 Internal Server Error and the cause of the error state was not in the associated before hook. In other words, objects and lists rendered in the before hook with any HTTP response code will never run the associated after hook.

When handling errors, the passed in object will always contain a messages property containing a list of Strings describing the error(s) encountered.

Defining Common Hooks

Sometimes it is beneficial to create hooks which are executed for all calls of a certain type, such as a beforeList hook that is executed during the course of listing any resource. These are possible using an all.groovy file. The format of this file is exactly the same as other hook files. The order of execution is as follows:

  1. Before common hook executed
  2. Before resource-specific hook executed
  3. Normal API call executed
  4. After resource-specific hook executed
  5. After common hook executed

3.8 Authentication

MWS uses Basic Authentication for all REST API requests. This means that a username and password must be provided for each call to resources. There are two types of accounts that can be granted access: Users and Applications.
  • For insructions on how to set the credentials for the default User account, see the "Client Connections to MWS" section in Security.
  • For insructions on how to manage Application accounts, see Application Accounts.

To use Basic Authentication, each client request must contain a header that looks like this:

Authorization: Basic YWRhcHRpdmU6YzNVU3R1bkU=

The string after the word Basic is the base64 encoding of username : password . In the example above, YWRhcHRpdmU6YzNVU3R1bkU= is the base64 encoding of adaptive:c3UStunE. See section 2 of RFC 2617 for more details.

The username and password in the Basic Authentication header are encoded but not encrypted. Therefore, it is strongly recommended that MWS be run behind a proxy (like Apache) with SSL enabled. See the section "Encrypting Client Connections using Apache and SSL" under Security.