Why have we introduced a REST API for MQSC commands?

The MQ REST API is a growing API that provides access to administrative functionality. Much of its behaviour is based around traditional CRUD (Create, Read, Update, Delete) operations on MQ objects (such as Queues, Subscriptions or Channels) which we make available via the appropriate HTTP verbs (POST, GET, PATCH, DELETE) on suitable URLS. As some MQ objects have not yet had a set of fully RESTful interfaces created, we felt it would be helpful to provide an interface which allows basic administrative access, albeit without a fully RESTful approach.

So, what have we done?

We now expose a URL to which single MQSC commands can be POSTed, using the term POST with its meaning in the context of HTTP. The command will be passed to the command server in the queue manager for execution. (For those with an interest in such things, on z/OS the command is directly submitted to the queue manager command server, while on other platforms the command is submitted to the queue manager using an ESCAPE PCF message – more details in the resources mentioned in the “References” section below). The HTTP response, if the command is successfully submitted for execution, will contain the output from the command, much as it would be displayed by the runmqsc utility, simply wrapped into a JSON object.

What commands are available?

Subject to the usual authentication and authorisation checks (see this page in the Knowledge Centre) any command that can be submitted via runmqsc can be executed via this interface.

How do we access this functionality?

The URL for this interface is of the form
https://host:port/ibmmq/rest/v1/admin/action/qmgr/qmgrName/mqsc
Where the host and port are those on which your MQ webserver is started and the qmgrName corresponds to a queue manager accessible from that webserver.

Note that only POST operations are available – even if the mqsc command submitted is logically an enquiry. Other HTTP verbs, such as GET, will be rejected with HTTP response code 405 – METHOD NOT ALLOWED.

What is the structure of the request body?

The request body is in JSON format:

{
  "type": "runCommand",
   "parameters": {
     "command": string
    }
}

The JSON object has a “type” attribute, which is always “runCommand”, and a “parameters” attribute which is a nested JSON object containing a single attribute “command”. The only variable part here is the “command” attribute – a string which contains the full text of the mqsc command to be executed.

What is the structure of the response body?

Leaving aside the various error responses, which follow the normal formats for the MQ REST API, the response body for a successfully submitted command (HTTP 200) has the following JSON format:

{
  "overallCompletionCode": number,
  "overallReasonCode": number,
  "commandResponse": [
    {
      "completionCode": number,
      "reasonCode": number,
      "text": [
        string
      ]
    }
  ]
}

There is a completion code and reason code for the command overall, plus an array of command responses, as a single command may produce multiple responses – for example “DISPLAY QLOCAL(*)” will produce a response for each local queue found.

Each command response object has its own completion and response codes, as in certain cases (for example performing operations in a queue-sharing group) operations may work in part.

Each command response also contains the text of the queue manager’s response as an array of strings, with little change to formatting (the API removes new-lines from the text, but otherwise doesn’t change it).

A Simple Example

I have a queue manager called “QM_T1” (I’m very creative with my naming) on my Windows laptop.

If I start the web server and POST to https://localhost:9443/ibmmq/rest/v1/admin/action/qmgr/QM_T1/mqsc with the following request body:

{
  "type": "runCommand",
  "parameters": {
    "command": "DISPLAY CHANNEL(*) TYPE(CLNTCONN)"
  }
}

I get a response code of 200 (OK) and a response body containing the following text:

{
  "commandResponse": [
    {
      "completionCode": 0,
      "reasonCode": 0,
      "text": [
        "AMQ8414: Display Channel details. CHANNEL(ClientConn1) CHLTYPE(CLNTCONN)"
      ]
    },
    {
      "completionCode": 0,
      "reasonCode": 0,
      "text": [
        "AMQ8414: Display Channel details. CHANNEL(ClientConn2) CHLTYPE(CLNTCONN)"
      ]
    },
    {
      "completionCode": 0,
      "reasonCode": 0,
      "text": [
        "AMQ8414: Display Channel details. CHANNEL(ClientConn3) CHLTYPE(CLNTCONN)"
      ]
    },
    {
      "completionCode": 0,
      "reasonCode": 0,
      "text": [
        "AMQ8414: Display Channel details. CHANNEL(SYSTEM.DEF.CLNTCONN) CHLTYPE(CLNTCONN)"
      ]
    }
  ],
  "overallCompletionCode": 0,
  "overallReasonCode": 0
}

As can be seen, the “commandResponse” JSONArray contains one entry for each Client Connection Channel discovered.

The first thing to be aware of – what counts as “success”?

While this API will do some simple validation of the input command string – checking that it starts with a valid mqsc “verb”, such as DISPLAY or DEFINE – it does not examine the response from the queue manager in any detail (indeed it does not even check that the word following the “verb” is valid – it would submit the command “DISPLAY FIREWORKS” to the queue manager, should anyone be foolish enough to request it to do so).

As far as the MQ REST API is concerned, if the command was successfully submitted to the Queue Manager, then it will produce an HTTP 200 (OK) response even if the Queue Manager subsequently rejects the command.

For this reason, the overallCompletionCode and overallReasonCode in the response object should also be checked.

For example, the request body:

{
  "type": "runCommand",
  "parameters": {
    "command": "DISPLAY CHANNEL(*) TYPE(BANANA)"
  }
}

Will yield the response code 200, but the response body will contain overall completion and reason codes indicating failure, and the command response entries will contain the error text returned by the queue manager:

{
  "commandResponse": [
    {
      "completionCode": 0,
      "reasonCode": 0,
      "text": [
        "AMQ8405: Syntax error detected at or near end of command segment below:-"
      ]
    },
    {
      "completionCode": 0,
      "reasonCode": 0,
      "text": [
        "DISPLAY CHANNEL(*) TYPE(B"
      ]
    },
    {
      "completionCode": 0,
      "reasonCode": 0,
      "text": [
        "AMQ8427: Valid syntax for the MQSC command: DISPLAY CHANNEL( generic_channel_name ) [ WHERE( filter_keyword operator filter_value ) ] [ TYPE( ALL | SDR | SVR | RCVR | RQSTR | CLNTCONN | SVRCONN | CLUSSDR | CLUSRCVR | AMQP | MQTT* ) ] [ ALL ] [ AFFINITY ] [ ALTDATE ] [ ALTTIME ] [ AMQPKA ] [ BACKLOG ] [ BATCHHB ] [ BATCHINT ] [ BATCHLIM ] [ BATCHSZ ] [ CERTLABL ] [ CHLTYPE ] [ CLNTWGHT ] [ CLUSNL ] [ CLUSTER ] [ CLWLPRTY ] [ CLWLRANK ] [ CLWLWGHT ] [ COMPHDR ] [ COMPMSG ] [ CONNAME ] [ CONVERT ] [ DEFRECON ] [ DESCR ] [ DISCINT ] [ HBINT ] [ KAINT ] [ LOCLADDR ] [ LONGRTY ] [ LONGTMR ] [ MAXINST ] [ MAXINSTC ] [ MAXMSGL ] [ MCANAME ] [ MCATYPE ] [ MCAUSER ] [ MODENAME ] [ MONCHL ] [ MRDATA ] [ MREXIT ] [ MRRTY ] [ MRTMR ] [ MSGDATA ] [ MSGEXIT ] [ NETPRTY ] [ NPMSPEED ] [ PASSWORD ] [ PORT ] [ PROPCTL ] [ PUTAUT ] [ QMNAME ] [ RCVDATA ] [ RCVEXIT ] [ RESETSEQ ] [ SCYDATA ] [ SCYEXIT ] [ SENDDATA ] [ SENDEXIT ] [ SEQWRAP ] [ SHARECNV ] [ SHORTRTY ] [ SHORTTMR ] [ SSLCAUTH ] [ SSLCIPH ] [ SSLKEYP ] [ SSLKEYR ] [ SSLPEER ] [ STATCHL ] [ STATUS ] [ TPNAME ] [ TPROOT ] [ TRPTYPE ] [ TYPE ] [ USECLTID ] [ USEDLQ ] [ USERID ] [ XMITQ ]"
      ]
    }
  ],
  "overallCompletionCode": 2,
  "overallReasonCode": 3008
}

The second thing to be aware of – platform differences

The MQ REST API works by submitting the command requested to the queue manager and performing some very simple wrapping of the responses it receives back. There are significant differences between the mechanisms for submitting the responses between z/OS and other queue managers, and the resultant responses differ in format. There are more detailed discussions of these differences in the Knowledge Center (see the References below). We chose to implement the MQ REST API very simply, and hence we do not attempt to mask these differences. Most notably, there will be several separate text elements for each command response from a z/OS queue manager, while there will be only one from a non-z/OS queue manager.

For example, if we submitted the following request body to the MQ REST API running against a z/OS queue manager:

{
  "type": "runCommand",
  "parameters": {
    "command": "DISPLAY CHANNEL(NEWSVRCONN) ALL"
  }
}

Then the response body might be:

{
  "commandResponse": [
    {
      "completionCode": 0,
      "reasonCode": 0,
      "text": [
        "CSQN205I COUNT= 3, RETURN=00000000, REASON=00000000",
        "CSQM415I ]MQ21 CHANNEL(NEWSVRCONN ) CHLTYPE(SVRCONN ) QSGDISP(QMGR ) DEFCDISP(PRIVATE ) TRPTYPE(LU62 )",
        "CSQ9022I ]MQ21 CSQMDRTS ' DISPLAY CHANNEL' NORMAL COMPLETION "
      ]
    }
  ],
  "overallCompletionCode": 0,
  "overallReasonCode": 0
}

As you can see, the “text” attribute of the command response object is noticeably different from the Windows queue manager example. However, it is very much as a z/OS queue manager administrator would expect.

In summary

We have provided a “bare-bones” mechanism to allow any valid MQSC command to be executed via the MQ REST API. We hope it will be a useful option – let us know if it is…

Knowledge Center References

  • This page and its siblings document the overall REST API.
  • This page and its siblings constitute the formal documentation of this feature.
  • This page and this page discuss the Escape PCF mechanism used by this REST API on platforms other than zSeries.
  • This page and its siblings discuss the use of the command server on zSeries queue managers, which is how this REST API operates in that context.

Leave a Reply