IBM published the reference documentation for HMC V8 REST api. Having a real API to interact with HMC is great. I played with it and in this post i will show how to use it with curl. Maybe not the most useful thing to do but it’s a good way to see how the API work :)

documentation

The main documentation is the HMC V8 programmer guide

API access

The guide is great but doesn’t provide much real examples. The first step was to find what is the port used by REST api. It’s port 12443 and it’s using TLS.

So all the requests should be sent to :

https://myhmc:12443

login

We need to have credentials to perform requests. So the first step is to log on. Credentials will be kept in a cookies jar and we will reuse it for all subsequent requests.

We create a login.xml text file containing the login informations. Here it’s hscroot/abc123 :)

<?xml version="1.0" encoding="UTF-8" standalone="yes"?>
<LogonRequest xmlns="http://www.ibm.com/xmlns/systems/power/firmware/web/mc/2012_10/" schemaVersion="V1_0">
  <UserID>hscroot</UserID>
  <Password>abc123</Password>
</LogonRequest>

The curl command to perform the authentication :

curl -k -c cookies.txt -i -X PUT -H "Content-Type: application/vnd.ibm.powervm.web+xml; type=LogonRequest" -H "Accept: application/vnd.ibm.powervm.web+xml; type=LogonResponse" -H "X-Audit-Memento: hmc_test" -d @login.xml https://myhmc:12443/rest/api/web/Logon

Explanations on the different parameters :

  • -k : “insecure” mode. It permits the use of the self signed certificate used by the HMC.
  • -c cookies.txt : setup the cookies jar where authentication session informations will be kept.

  • -X PUT : use PUT request method. Requested by the HMC API.

  • -d @login.xml : will use content of login.xml.

  • -H : http headers added to the request.

  • -i : show the http headers of the answer. Useful for debugging.

The correct request headers was somewhat difficult to find. But the ones below are working :

  • Content-Type: application/vnd.ibm.powervm.web+xml; type=LogonRequest : specify the request content format
  • Accept: application/vnd.ibm.powervm.web+xml; type=LogonResponse : specify the expected response content format
  • “X-Audit-Memento: hmc_test” : a simple comment

Here a correct response :

HTTP/1.1 200 OK
X-Powered-By: Servlet/3.0
X-Transaction-ID: XT10132256
Content-Type: application/vnd.ibm.powervm.web+xml; type=LogonResponse
Content-Length: 576
Set-Cookie: JSESSIONID=0000BESHFwhxLNhfvbtz6eUxqzF:5ee591ee-0191-4c4b-8b2d-bf8c4b6a4053; Path=/; Secure; HttpOnly
Set-Cookie: CCFWSESSION=D5215916101E34ED06EAB24FE6B58060; Path=/; Secure; HttpOnly
Date: Wed, 05 Aug 2014 20:33:07 GMT
Expires: Thu, 01 Dec 1994 16:00:00 GMT
Cache-Control: no-cache="set-cookie, set-cookie2"

<?xml version="1.0" encoding="UTF-8" standalone="yes"?>
<LogonResponse xmlns="http://www.ibm.com/xmlns/systems/power/firmware/web/mc/2012_10/" xmlns:ns2="http://www.w3.org/XML/1998/namespace/k2" schemaVersion="V1_1_0">
    <Metadata>
        <Atom/>
    </Metadata>
    <X-API-Session kb="ROR" kxe="false">BBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBB-AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAACCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCC/X-API-Session>
</LogonResponse>

If authentication go well, you should have a 200 return code and cookies.txt should contains the cookie needed for authentication.

$ cat cookies.txt
# Netscape HTTP Cookie File
# http://curl.haxx.se/docs/http-cookies.html
# This file was generated by libcurl! Edit at your own risk.

#HttpOnly_myhmc FALSE / TRUE  0 JSESSIONID  0000BESHBBBBBBBBBBBAAAAAA:55555555555-1111-4444-8888-7777777777
#HttpOnly_myhmc FALSE / TRUE  0 CCFWSESSION D555555555555555555555555555555

requesting informations

Now, it’s pretty easy to perform requests to get informations about the different elements. It’s where the API reference book become very valuable. It’s describing all it’s possible to do.

For example, to get informations about all lpars, the request would be :

https://myhmc:12443/rest/api/uom/LogicalPartition

The following curl command will get the datas :

curl -k -c cookies.txt -b cookies.txt -H "Accept: application/atom+xml; charset=UTF-8" https://myhmc:12443/rest/api/uom/LogicalPartition

Explanations on the different parameters :

  • -c cookies.txt : set up the cookies jar file.
  • -b cookies.txt: use the appropriate cookies during the session.
  • -k : “insecure” mode for self signed certificates.
  • -H “Accept: application/atom+xml; charset=UTF-8” : the expected response should be a atom feed.

This command will get all partitions on all managed system so the output could be very big depending on your environment.

It’s also possible to perform a search on a specific partition. Here rhel01 :

 curl -k -c cookies.txt -b cookies.txt -i -H "Accept: application/atom+xml; charset=UTF-8" https://myhmc:12443/rest/api/uom/LogicalPartition/search/\(PartitionName\=\=rhel01\)

Here a small extract of the atom feed :

 <feed xmlns="http://www.w3.org/2005/Atom" xmlns:ns2="http://a9.com/-/spec/opensearch/1.1/" xmlns:ns3="http://www.w3.org/1999/xhtml">
    <id>9c9d480f-26d2-3bfe-b5c8-e8e7b7d74ed1</id>
    <updated>2014-08-05T20:08:51.926+02:00</updated>
    <link rel="SELF" href="https://myhmc:12443/rest/api/uom/LogicalPartition/search/(PartitionName==rhel01)"/>
    <link rel="MANAGEMENT_CONSOLE" href="https://myhmc:12443/rest/api/uom/ManagementConsole/ec1c8c00-dde4-39f5-afcf-6a3724eb1363"/>
    <generator>IBM Power Systems Management Console</generator>
    <entry>
        <id>235A6C07-65CF-4673-B25B-41DA41C3D75D</id>
        <title>LogicalPartition</title>
        <published>2014-08-05T20:08:53.307+02:00</published>
        <link rel="SELF" href="https:/myhmc:12443/rest/api/uom/LogicalPartition/235A6C07-65CF-4673-B25B-41DA41C3D75D"/>
        <author>
            <name>IBM Power Systems Management Console</name>
        </author>
        <etag:etag xmlns:etag="http://www.ibm.com/xmlns/systems/power/firmware/uom/mc/2012_10/" xmlns="http://www.ibm.com/xmlns/systems/power/firmware/uom/mc/2012_10/">-2080971054</etag:etag>
        <content type="application/vnd.ibm.powervm.uom+xml; type=LogicalPartition">
            <LogicalPartition:LogicalPartition xmlns:LogicalPartition="http://www.ibm.com/xmlns/systems/power/firmware/uom/mc/2012_10/" xmlns="http://www.ibm.com/xmlns/systems/power/firmware/uom/mc/2012_10/" xmlns:ns2="http://www.w3.org/XML/1998/namespace/k2" schemaVersion="V1_1_0">
    <Metadata>
        <Atom>
            <AtomID>235A6C07-65CF-4673-B25B-41DA41C3D75D</AtomID>
            <AtomCreated>1406824984214</AtomCreated>
        </Atom>
    </Metadata>
    <AllowPerformanceDataCollection kb="CUD" kxe="false">true</AllowPerformanceDataCollection>

The atom xml global structure is like that :

<feed>
  <entry>
    <HMC element>
      ...
    </HMC element>
  </entry>
</feed>

creating a job

The HMC API offers a lot of jobs to perform different tasks. They are described in the programmer’s guide.

Here i will describe how to launch a job to add an LU in a shared storage pool.

The programmer’s guide give the format to follow for JobRequest but it’s also possible to request the format to the HMC with a GET request :

curl -k -c cookies.txt -b cookies.txt -H "Accept: application/atom+xml; charset=UTF-8" https://myhmc:12443/rest/api/uom/Cluster/95d38275-ab43-333e-a472-bb4aab38645b/do/CreateLogicalUnit

The response include the jobrequest format :

<entry xmlns="http://www.w3.org/2005/Atom" xmlns:ns2="http://a9.com/-/spec/opensearch/1.1/" xmlns:ns3="http://www.w3.org/1999/xhtml">
    <id>3a090510-10c7-3d14-afe0-f9fd0cc53b6c</id>
    <title>JobRequest</title>
    <published>2014-08-05T20:21:03.532+02:00</published>
    <link rel="SELF" href="https://myhmc:12443/rest/api/uom/Cluster/95d38275-ab43-333e-a472-bb4aab38645b/do/CreateLogicalUnit/b995b76c-2e74-47d9-be8a-9751eb15bdd9"/>
    <link rel="MANAGEMENT_CONSOLE" href="https://myhmc:12443/rest/api/uom/ManagementConsole/ec1c8c00-dde4-39f5-afcf-6a3724eb1363"/>
    <author>
        <name>IBM Power Systems Management Console</name>
    </author>
    <content type="application/vnd.ibm.powervm.web+xml; type=JobRequest">
        <JobRequest:JobRequest xmlns:JobRequest="http://www.ibm.com/xmlns/systems/power/firmware/web/mc/2012_10/" xmlns="http://www.ibm.com/xmlns/systems/power/firmware/web/mc/2012_10/" xmlns:ns2="http://www.w3.org/XML/1998/namespace/k2" schemaVersion="V1_1_0">
    <Metadata>
        <Atom/>
    </Metadata>
    <RequestedOperation kb="CUR" kxe="false" schemaVersion="V1_1_0">
        <Metadata>
            <Atom/>
        </Metadata>
        <OperationName kb="ROR" kxe="false">CreateLogicalUnit</OperationName>
        <GroupName kxe="false" kb="ROR">Cluster</GroupName>
    </RequestedOperation>
    <JobParameters kb="CUR" kxe="false" schemaVersion="V1_1_0">
        <Metadata>
            <Atom/>
        </Metadata>
    </JobParameters>
</JobRequest:JobRequest>
    </content>
</entry>

It’s only missing the parameters to create the LU in the JobParameters section :

<JobParameters kb="CUR" kxe="false" schemaVersion="V1_1_0">
  <Metadata>
    <Atom/>
  </Metadata>
  <JobParameter schemaVersion="V1_0">
    <Metadata>
      <Atom/>
    </Metadata>
    <ParameterName kb="ROR" kxe="false">LUName</ParameterName>
    <ParameterValue kxe="false" kb="CUR">newLU</ParameterValue>
  </JobParameter>
  <JobParameter schemaVersion="V1_0">
    <Metadata>
      <Atom/>
    </Metadata>
    <ParameterName kb="ROR" kxe="false">LUSize</ParameterName>
    <ParameterValue kxe="false" kb="CUR">18</ParameterValue>
  </JobParameter>
  <JobParameter schemaVersion="V1_0">
    <Metadata>
      <Atom/>
    </Metadata>
    <ParameterName kb="ROR" kxe="false">LUType</ParameterName>
    <ParameterValue kxe="false" kb="CUR">THIN</ParameterValue>
  </JobParameter>
  <JobParameter schemaVersion="V1_0">
    <Metadata>
      <Atom/>
    </Metadata>
    <ParameterName kb="ROR" kxe="false">DeviceType</ParameterName>
    <ParameterValue kxe="false" kb="CUR">VirtualIO_Disk</ParameterValue>
  </JobParameter>
</JobParameters>

running a job

The first step is to find the cluster UUID :

curl -k -c cookies.txt -b cookies.txt -H "Accept: application/atom+xml; charset=UTF-8" https://myhmc:12443/rest/api/uom/Cluster

The UUID is in the id field of entry section :

    <entry>
        <id>95d38275-ab43-333e-a472-bb4aab38645b</id>
        <title>Cluster</title>
        <published>2014-08-06T15:10:45.965+02:00</published>
        <link rel="SELF" href="https://myhmc:12443/rest/api/uom/Cluster/95d38275-ab43-333e-a472-bb4aab38645b"/>
        <author>
            <name>IBM Power Systems Management Console</name>
        </author>
Here the cluster’s UUID is 95d38275-ab43-333e-a472-bb4aab38645b.

I put in add_lu.xml the complete jobrequest.

The curl command :

curl -k -c cookies.txt -b cookies.txt -i -H "Content-Type: application/vnd.ibm.powervm.web+xml; type=JobRequest" -H "Accept: application/atom+xml; charset=UTF-8" -H "X-Audit-Memento: addlu" -X PUT -H "Expect:" -d @add_lu.xml https://myhmc:12443/rest/api/uom/Cluster/95d38275-ab43-333e-a472-bb4aab38645b/do/CreateLogicalUnit

It’s very important to add this header -H “Expect:”. It avoid the use of HTTP 100- Continue request by curl. It would botch the command because the HMC doesn’t handle it properly.

A complete explanation is available here : curl-http1-1-100-continue-and-multipartform-data-post.html

Jobs are handled asynchronously.

The response will contains the job id and the received request :

<entry xmlns="http://www.w3.org/2005/Atom" xmlns:ns2="http://a9.com/-/spec/opensearch/1.1/" xmlns:ns3="http://www.w3.org/1999/xhtml">
    <id>ca4e36da-9cb2-4d99-8375-a518e39edb97</id>
    <title>JobResponse</title>
    <published>2014-08-05T21:32:51.868+02:00</published>
    <link rel="SELF" href="https://myhmc:12443/rest/api/uom/jobs/1406824782891"/>
    <author>
        <name>IBM Power Systems Management Console</name>
    </author>
    <content type="application/vnd.ibm.powervm.web+xml; type=JobResponse">
        <JobResponse:JobResponse xmlns:JobResponse="http://www.ibm.com/xmlns/systems/power/firmware/web/mc/2012_10/" xmlns="http://www.ibm.com/xmlns/systems/power/firmware/web/mc/2012_10/" xmlns:ns2="http://www.w3.org/XML/1998/namespace/k2" schemaVersion="V1_1_0">
    <Metadata>
        <Atom/>
    </Metadata>
    <RequestURL kb="ROR" kxe="false" href="Cluster/95d38275-ab43-333e-a472-bb4aab38645b/do/CreateLogicalUnit" rel="via" title="The URL to which the JobRequest was submitted."/>
    <TargetUuid kb="ROR" kxe="false">95d38275-ab43-333e-a472-bb4aab38645b</TargetUuid>
    <JobID kxe="false" kb="ROR">1406824782891</JobID>
    <TimeStarted kb="ROR" kxe="false">0</TimeStarted>
    <TimeCompleted kb="ROR" kxe="false">0</TimeCompleted>
    <Status kb="ROR" kxe="false">NOT_STARTED</Status>
    <JobRequestInstance kb="ROR" kxe="false" schemaVersion="V1_1_0">
        <Metadata>
            <Atom/>
        </Metadata>
        <RequestedOperation kb="CUR" kxe="false" schemaVersion="V1_1_0">
            <Metadata>
                <Atom/>
            </Metadata>
            <OperationName kb="ROR" kxe="false">CreateLogicalUnit</OperationName>
            <GroupName kxe="false" kb="ROR">Cluster</GroupName>
        </RequestedOperation>
        <JobParameters kb="CUR" kxe="false" schemaVersion="V1_1_0">
            <Metadata>
                <Atom/>
            </Metadata>
            <JobParameter schemaVersion="V1_0">
                <Metadata>
                    <Atom/>
                </Metadata>
                <ParameterName kb="ROR" kxe="false">LUName</ParameterName>
                <ParameterValue kb="CUR" kxe="false">newLU1</ParameterValue>
            </JobParameter>
            <JobParameter schemaVersion="V1_0">
                <Metadata>
                    <Atom/>
                </Metadata>
                <ParameterName kb="ROR" kxe="false">LUSize</ParameterName>
                <ParameterValue kb="CUR" kxe="false">18</ParameterValue>
            </JobParameter>
            <JobParameter schemaVersion="V1_0">
                <Metadata>
                    <Atom/>
                </Metadata>
                <ParameterName kb="ROR" kxe="false">LUType</ParameterName>
                <ParameterValue kb="CUR" kxe="false">THIN</ParameterValue>
            </JobParameter>
            <JobParameter schemaVersion="V1_0">
                <Metadata>
                    <Atom/>
                </Metadata>
                <ParameterName kb="ROR" kxe="false">DeviceType</ParameterName>
                <ParameterValue kb="CUR" kxe="false">VirtualIO_Disk</ParameterValue>
            </JobParameter>
        </JobParameters>
    </JobRequestInstance>
    <Progress kb="ROO" kxe="false" schemaVersion="V1_1_0">
        <Metadata>
            <Atom/>
        </Metadata>
    </Progress>
    <Results kb="ROR" kxe="false" schemaVersion="V1_1_0">
        <Metadata>
            <Atom/>
        </Metadata>
    </Results>
</JobResponse:JobResponse>
    </content>
</entry>

Job id is 1406824782891

job status

It’s possible to get status with this command :

curl -k -c cookies.txt -b cookies.txt -i -H "Accept: application/atom+xml; charset=UTF-8" https://myhmc:12443/rest/api/uom/jobs/1406824782891

The atom feed contains the request and the status :

<entry xmlns="http://www.w3.org/2005/Atom" xmlns:ns2="http://a9.com/-/spec/opensearch/1.1/" xmlns:ns3="http://www.w3.org/1999/xhtml">
    <id>49a81946-a030-3600-a0ec-b93953d3e5dd</id>
    <title>JobResponse</title>
    <published>2014-08-05T20:51:22.029+02:00</published>
    <link rel="SELF" href="nulljobs/1406824782891"/>
    <link rel="SELF" href="https://myhmc:12443/rest/api/uom/jobs/1406824782891/c3cd9db5-3765-4350-9f1c-c996509ffacf"/>
    <link rel="MANAGEMENT_CONSOLE" href="https://myhmc:12443/rest/api/uom/ManagementConsole/ec1c8c00-dde4-39f5-afcf-6a3724eb1363"/>
    <author>
        <name>IBM Power Systems Management Console</name>
    </author>
    <content type="application/vnd.ibm.powervm.web+xml; type=JobResponse">
        <JobResponse:JobResponse xmlns:JobResponse="http://www.ibm.com/xmlns/systems/power/firmware/web/mc/2012_10/" xmlns="http://www.ibm.com/xmlns/systems/power/firmware/web/mc/2012_10/" xmlns:ns2="http://www.w3.org/XML/1998/namespace/k2" schemaVersion="V1_1_0">
    <Metadata>
        <Atom/>
    </Metadata>
    <RequestURL kb="ROR" kxe="false" href="Cluster/95d38275-ab43-333e-a472-bb4aab38645b/do/CreateLogicalUnit" rel="via" title="The URL to which the JobRequest was submitted."/>
    <TargetUuid kb="ROR" kxe="false">95d38275-ab43-333e-a472-bb4aab38645b</TargetUuid>
    <JobID kxe="false" kb="ROR">1406824782891</JobID>
    <TimeStarted kb="ROR" kxe="false">1407331971868</TimeStarted>
    <TimeCompleted kb="ROR" kxe="false">1407331972538</TimeCompleted>
    <Status kb="ROR" kxe="false">COMPLETED_OK</Status>
    <JobRequestInstance kb="ROR" kxe="false" schemaVersion="V1_1_0">
        <Metadata>
            <Atom/>
        </Metadata>
        <RequestedOperation kb="CUR" kxe="false" schemaVersion="V1_1_0">
            <Metadata>
                <Atom/>
            </Metadata>
            <OperationName kb="ROR" kxe="false">CreateLogicalUnit</OperationName>
            <GroupName kxe="false" kb="ROR">Cluster</GroupName>
        </RequestedOperation>
        <JobParameters kb="CUR" kxe="false" schemaVersion="V1_1_0">
            <Metadata>
                <Atom/>
            </Metadata>
            <JobParameter schemaVersion="V1_0">
                <Metadata>
                    <Atom/>
                </Metadata>
                <ParameterName kb="ROR" kxe="false">LUName</ParameterName>
                <ParameterValue kb="CUR" kxe="false">newLU1</ParameterValue>
            </JobParameter>
            <JobParameter schemaVersion="V1_0">
                <Metadata>
                    <Atom/>
                </Metadata>
                <ParameterName kb="ROR" kxe="false">LUSize</ParameterName>
                <ParameterValue kb="CUR" kxe="false">18</ParameterValue>
            </JobParameter>
            <JobParameter schemaVersion="V1_0">
                <Metadata>
                    <Atom/>
                </Metadata>
                <ParameterName kb="ROR" kxe="false">LUType</ParameterName>
                <ParameterValue kb="CUR" kxe="false">THIN</ParameterValue>
            </JobParameter>
            <JobParameter schemaVersion="V1_0">
                <Metadata>
                    <Atom/>
                </Metadata>
                <ParameterName kb="ROR" kxe="false">DeviceType</ParameterName>
                <ParameterValue kb="CUR" kxe="false">VirtualIO_Disk</ParameterValue>
            </JobParameter>
        </JobParameters>
    </JobRequestInstance>
    <Progress kb="ROO" kxe="false" schemaVersion="V1_1_0">
        <Metadata>
            <Atom/>
        </Metadata>
        <DiscreteProgress kb="ROR" kxe="false" schemaVersion="V1_1_0">
            <Metadata>
                <Atom/>
            </Metadata>
            <CompletedStates kb="ROR" kxe="false" schemaVersion="V1_1_0">
                <Metadata>
                    <Atom/>
                </Metadata>
                <NLSStaticMessage schemaVersion="V1_1_0">
                    <Metadata>
                        <Atom/>
                    </Metadata>
                    <UntranslatedMessage kb="ROR" kxe="false">Create Logical Unit not yet started</UntranslatedMessage>
                    <MessageKey kb="ROR" kxe="false">NOT STARTED</MessageKey>
                </NLSStaticMessage>
                <NLSStaticMessage schemaVersion="V1_1_0">
                    <Metadata>
                        <Atom/>
                    </Metadata>
                    <UntranslatedMessage kb="ROR" kxe="false">Create logical unit started</UntranslatedMessage>
                    <MessageKey kb="ROR" kxe="false">CREATE LU STARTED</MessageKey>
                </NLSStaticMessage>
                <NLSStaticMessage schemaVersion="V1_1_0">
                    <Metadata>
                        <Atom/>
                    </Metadata>
                    <UntranslatedMessage kb="ROR" kxe="false">Create logical unit completed</UntranslatedMessage>
                    <MessageKey kb="ROR" kxe="false">CREATE LU COMPLETED</MessageKey>
                </NLSStaticMessage>
            </CompletedStates>
        </DiscreteProgress>
    </Progress>
    <Results kb="ROR" kxe="false" schemaVersion="V1_1_0">
        <Metadata>
            <Atom/>
        </Metadata>
        <JobParameter schemaVersion="V1_1_0">
            <Metadata>
                <Atom/>
            </Metadata>
            <ParameterName kb="ROR" kxe="false">LUCreated</ParameterName>
            <ParameterValue kb="CUR" kxe="false">27dfe45390bc0611e396cc00215e89aea6970a1de8ce2bdf1d4b7a67f0a72cca91</ParameterValue>
        </JobParameter>
    </Results>
</JobResponse:JobResponse>
    </content>
</entry>

conclusion

This API will not replace the standard CLI commands. It’s not the goal. It’s not very useful if you don’t have a way to process xml. With shell scripts and curl, it’s somewhat hard and using standard hmc CLI commands seems better.

But curl is perfect for testing a REST API and understanding how it’s working. Debugging REST requests with curl can too be simpler.

I published a git repository with all the xml files and curl commands :

hmc_api_test

I will show in a next post how to use the API with golang.