Category Archives: IBM MQ

My IBM MQ Cluster Ping Nagios script

Monitoring cluster health can be quite tricky. I have created a small Nagios script to help in the task. It uses the sample programs amqsput and amqsget, delivered with the IBM MQ installation

Preparations:
In this example I’m only going to use two queue managers QMBASE (full repository) and QMEXTERNAL (partial repository). Commands below are for runmqsc
QMEXTERNAL

DEFINE QA(QA.CLUSTER.PING) TARGET(TOP.CLUSTER.PING) TARGTYPE(TOPIC)
DEFINE QL(QL.CLUSTER.PING) CLUSTER(EXTERNAL)

QMBASE

DEFINE TOP(TOP.CLUSTER.PING) TOPICSTR('ping') CLUSTER(EXTERNAL) 
DEFINE SUB(SUB.CLUSTER.PING) TOPIC(TOP.CLUSTER.PING) TOPICSTR('#') DEST(QL.CLUSTER.PING)

How it works:
It puts a message on a queue alias, using amqsput, that is connected to a cluster topic on the base queue manager
A subscription to the topic picks up the message and put it on the cluster queue on the external queue manager
The message is then picked up by and checked. I also check the length of the message to check for more than one message

And here is the script:

#!/bin/bash

if [ $# -lt 1 ]; then
  echo "********************"
  echo "Cluster Ping"
  echo "********************"
  echo "NOTE!"
  echo "This script needs that all the MQ objects are in place (see below)"
  echo ""
  echo "QMEXTENAL                        QMBASE (REPOSITORY)"
  echo "QA.CLUSTER.PING            ->    TOP.CLUSTER.PING (CLUSTER)"
  echo "QL.CLUSTER.PING (CLUSTER)  <-    SUB.CLUSTER.PING(TOP.CLUSTER.PING)"
  echo ""
  echo "Usage: $0 <external queue manager>"
  echo ""
  echo "External Queue Manager: ex. QMEXTERNAL"
  echo ""
  echo "Ex. $0 QMEXTERNAL"
  exit 1
fi

# Define variables
qmanager=$1
inqueue=QA.CLUSTER.PING
outqueue=QL.CLUSTER.PING
timestamp=$(date +%s)
match=false
normal=true

#Send message to QMBASE
printf "%s\n\n" ${timestamp} | amqsput ${inqueue} ${qmanager} > /dev/null

msg=$(amqsget ${outqueue} ${qmanager})

if [[ ${msg} == *"${timestamp}"* ]]; then
  match=true
fi

if [ ${#msg} -gt 80 ]; then
  normal=false
fi

if [[ ${match} == "true" && ${normal} == "true" ]]; then
  echo "OK - Message received from cluster"
  exit 0
fi

if [[ ${match} == "true" && ${normal} == "false" ]]; then
  echo "WARNING - More then one message was received"
  exit 1
fi

if [[ ${match} == "false" ]]; then
  echo "ERROR - No message received!"
  exit 2
fi

echo "UNKNOWN - Script has not run correctly"
exit 3

Now, this will tell us that the cluster can transport messages to and from the base queue manager, but we need more to be able to feel safe (at least I do) so here are a few other things to look at:
* Keep track of the transmission queues so that they process messages. I have, so far, only worked with small clusters so monitoring queue depth of the SYSTEM.CLUSTER.TRANSMIT.QUEUE has been enough, but if you have more transmission queues you need to monitor them all.
* Keep track of the command queue SYSTEM.CLUSTER.COMMAND.QUEUE. This queue should also process messages and not only grow
* Look for error messages in the queue manager error log (AMQERR01.LOG). Here I look for the following codes (short description in parentheses):

- AMQ9465 (Failed republishing of cluster information)
- AMQ5534E (User ID 'anyuser' authentication failed)
- AMQ5542I (The failed authentication check was caused by the queue manager)
- AMQ9202E (Remote host 'anyhost (anyip) (anyport)' not available, retry)
- AMQ9259E (Connection timed out from host 'anyhost')
- AMQ9469W: (Update not received for CLUSRCVR channel any channel)
- AMQ9492E (The TCP/IP responder program encountered an error)
- AMQ9558E (The remote channel 'any channel' encountered a problem)
- AMQ9633E (Bad SSL certificate for channel 'any channel')
- AMQ9637E (Channel is lacking a certificate)
- AMQ9716E (Remote SSL certificate revocation status check failed for channel)

After all of the tests above I usually feel pretty confident that we have a working environment.

Tested on IBM MQ 9 and Red Hat 7

IBM MQ: Setup a simple REST API environment with MQWEB and cURL

I’m here going to show you how I setup a small environment for the MQWEB REST API, mainly to try it out. It is actually not much to be done to get this up and running

First choose the security settings. For this IBM provide us with four sample configurations (/<installation path>/mqserver/web/mq/samp/configuration/):

basic_registry.xml  
ldap_registry.xml  
local_os_registry.xml
no_security.xml  

Out of these I’m going to choose local_os_registry.xml because it uses the groups and users already setup on the OS. This saves me from setting up new groups and users somewhere else

Copy desired configuration to MQWEB server settings

cp local_os_registry.xml /var/mqm/web/installations/<installation name>/servers/mqweb/mqwebuser.xml 

Start MQWEB server

strmqweb

That is pretty much it. Time to test

Put message on queue

curl -k -X POST -d 'helloworld' -u user:password -H "ibm-mq-rest-csrf-token: nothing" -H "Content-Type: text/plain"  https://localhost:9443/ibmmq/rest/v1/messaging/qmgr/MYQM01/queue/MYQUEUE/message

Here I feel we need some explaining:
-k: The default SSL certificate on the MQWEB server is self-signed. This option ignores that
-X POST: Use POST for putting messages onto MQ
-d: This is the data (string) that eventually will land on the queue
-u: The OS user and password (part of the mqm group in this example)
-H: The “ibm-mq-rest-csrf-token” needs to exist as a header but can contain anything, can even be completely blank
-H: We need to set a content type for the payload (from the -d option above). Valid content types include:

text/plain;charset=utf-8
text/html;charset=utf-8
text/xml;charset=utf-8
application/json;charset=utf-8
application/xml;charset=utf-8

NOTE: if omitting the charset, utf-8 is assumed
URL: Default URL and port: host:9443/ibmmq/rest/v1/. On top of this we add the default URL for handling messages on queues: /messaging/qmgr/<queue manager name>/queue/<queue name>/message

Get messages from queue

curl -k -X DELETE -u user:password -H "ibm-mq-rest-csrf-token: nothing" https://localhost:9443/ibmmq/rest/v1/messaging/qmgr/MYQM01/queue/MYQUEUE/message

Here I believe that I only need to explain one option:
-X DELETE: When fetching messages from MQ we use the REST DELETE operation

Done!

A couple of useful commands:

 
# Stop IBM MQ REST SERVER
endmqweb

# Show status of MQWEB (will also show the base URL for MQWEB REST API)
dspmqweb

Tested on IBM MQ 9.0.5.0 and Red Hat Linux 7.5 with curl 7.29.0

IBM MQ: My first try at topic trees

There is a lot of texts and pictures out there talking about topic trees but I have had a hard time finding any complete examples, so to better get a grip on what topic trees are and how I can use them I created this small example.

Goal: To be able to subscribe to multiple topics of similar entity types using only one subscription

Let’s get right into the tree building. I’m here going to use the runmqsc program but you can use MQExplorer if you like a GUI

DEFINE TOPIC(PRICES) TOPICSTR('/prices')
DEFINE TOPIC(FRUITS) TOPICSTR('/prices/fruits')
DEFINE TOPIC(APPLE)  TOPICSTR('/prices/fruit/apple')
DEFINE TOPIC(ORANGE) TOPICSTR('/prices/fruit/orange')
DEFINE TOPIC(TOYS)   TOPICSTR('/prices/toys')
DEFINE TOPIC(PUZZLE) TOPICSTR('/prices/toys/puzzle')
DEFINE TOPIC(CUBE)   TOPICSTR('/prices/toys/cube')

These commands will give you a tree looking like this

                     prices
                    /      \
               fruits       toys
              /     \      /    \
          orange  apple  cube  puzzle

And now I’m going to try to show the “magic” this brings

Tests
A. Subscribe to TOPICSTR(‘/prices/#’) will get you ALL messages published on ANY topic string in this tree
B. Subscribe to TOPICSTR(‘/prices/toys/#’) will get you messages published on ‘/prices/toys’, ‘/prices/toys/cube’ and ‘/prices/toys/puzzle’. No other
C. Subscribe to TOPICSTR(‘/prices/fruit/orange/#’) will get you messages published on ‘/prices/fruit/orange’ only. No other

Pure magic!

Tested on IBM MQ v9.0.5.0 on Red Hat Linux 7.5