DISPLAY DQM for Distributed

If you’re familiar with the IBM MQ for z/OS product, you may have issued the DISPLAY DQM command which gives you the following output:

CSQX830I M901 CSQXRDQM Channel initiator active
CSQX831I M901 CSQXRDQM 8 adapter subtasks started, 8 requested 
CSQX832I M901 CSQXRDQM 5 dispatchers started, 5 requested
CSQX833I M901 CSQXRDQM 0 SSL server subtasks started, 0 requested
CSQX840I M901 CSQXRDQM 5 channels current, maximum 200 
CSQX841I M901 CSQXRDQM 4 channels active, maximum 200, including 0 paused 
CSQX842I M901 CSQXRDQM 0 channels starting, 1 stopped, 0 retrying
CSQX836I M901 CSQXRDQM Maximum channels - TCP/IP 200, LU 6.2 200 
CSQX845I M901 CSQXRDQM TCP/IP system name is TCPIP 
CSQX846I M901 CSQXRDQM TCP/IP listener INDISP=QMGR started, for port 1591 address *
CSQX849I M901 CSQXRDQM LU 6.2 listener INDISP=QMGR not started 

There is no equivalent command for a distributed queue manager, however, you can get most of the same information from various other commands. So we have created an MQSCX script to create an equivalent set of output for a distributed queue manager.

Clearly some of the information simply doesn’t apply to distributed queue managers; for example the number of adapter, dispatcher and SSL Server subtasks. Also the TCP/IP system name doesn’t really have an equivalent on a distributed platform – or at least certainly not one that can be retrieved from the command server. The equivalents of DISPLAY QMGR MAXCHL ACTCHL TCPCHL LU62CHL is to look in the queue manager’s qm.ini file for MaxChannels and MaxActiveChannels on distributed, which is something that cannot work unless you are running the script local to the queue manager.

So the script issues the various commands required to get the information and then prints out a set of equivalent looking lines to give you a similar output:

MQG1 Channel initiator active
MQG1 14 channels current, maximum 400
MQG1 12 channels active, maximum 400, including 0 paused
MQG1 0 channels starting, 1 stopped, 1 retrying
MQG1 TCP/IP listener TCP.LSTR started, for port 1701 address *
MQG1 LU6.2 listener not started

It starts by checking whether the Channel initiator is active, which for most people will be since it gets started automatically by the queue manager these days.

DISPLAY QMSTATUS CHINIT
if (CHINIT = "RUNNING")
  print _qmgr,'Channel initiator active'
endif

Then it looks in the qm.ini file (but only if you’re not connected by a client or via connection). MQSCX can read environment variables just as if they were user variables, so it can make use of the MQ environment variable MQ_DATA_PATH which is setup by setmqenv. The _client system variable is new in MQSCX V9.0.0.

if (!(_client | (_connqmgr != _qmgr)))
  @filename = @MQ_DATA_PATH+"/qmgrs/"+_qmgr+"/qm.ini"
  @hf = fopen(@filename,"r")
  if (@hf)
    while (fgets(@hf,@line) >= 0)

For each line in the qm.ini file it will check for MaxChannels and MaxActiveChannels.

if (findstri(@line, "MaxChannels") > 0)
  @offset = findstr(@line, "=")
  if (@offset > 0)
    @MaxChannelsStr = substr(@line,@offset+1,strlen(@line)-@offset)
    @MaxChannels = eval(@MaxChannelsStr)
  endif
endif

A simple foreach loop allows the script to total up the number of different channel states currently on show. This then allows the various channel status lines in the output to be printed.

Finally the script has another simple foreach loop for listeners which also makes use of the new _numEach system variable to detect if the loop has never been called.

foreach(DISPLAY LSSTATUS(*) ALL WHERE(TRPTYPE EQ TCP))
  print _qmgr, 'TCP/IP listener', LISTENER ,'started, for port', PORT, 'address', IPADDR
endfor
if (_numEach = 0)
  print _qmgr, 'TCP/IP listener not started'
endif

The complete function is available to download in our Example Scripts bundle.


If you’re not a current licence holder, and you’d like to try out MQSCX, please email support@mqgem.com to request a trial licence.

Advertisements

MQSCX functions

MQGem recently delivered a new version of MQSCX that supports the new IBM MQ V9 release. As well as support for the new command level, there were a number of other features in this new version of MQSCX. One of those new features was a popular customer request for the addition of functions to the MQSCX control language.

MQSCX FunctionsThere are some new examples available in our Example Scripts bundle, which demonstrate how to use functions. In this blog post we’re going to take a look at one of those samples, conns.mqx as a way to introduce you to functions. This function evolved from an earlier blog post, MaxChannels vs DIS QMSTATUS CONNS where it was used to demonstrate all the different ways application connections show up in a queue manager.

The first thing to notice comparing the script in the earlier blog post, to the one in the sample download, is that the code is topped and tailed by the following statements:-

func conns()
:
endfunc

This is how you define a function in the MQSCX control language. All the statements in between the func and endfunc statements make up the body of your function.

If you load up the sample into MQSCX by importing the file, and then show the contents of the function with the =show func(conns) list command, you’ll also see that the comments that immediately precede the function in the imported file are included in this display. A handy place to describe what your function does to remind you in the future.

MQSCX Extended MQSC Program – Version 9.0.0

Licenced to Paul Clarke

[16:58:24] =import file(C:\MQGem\MQSCX\conns.mqx)

[16:58:32] =show func(conns) list

***********************************************************************

* Function : conns *

* Purpose : Print out the current state of connections to the QM *

***********************************************************************

func conns()

 

=echo resp(no)

You can run the function simply by typing its name on the command line.

[16:58:32] conns

Total connections: 23

Local : 21

QMgr Chls : 0

Client Chls: 2

 

Total Running Channel instances: 1

QMgr Channels: 0

Client Channels: 1

MQG1>

The next comparison to make between this function and it’s original form in the earlier blog post, is use of the =echo statements. The intention of this script (in both cases) is that you don’t see all the commands and responses going to and from the command server, you just see the final totals printed on the screen. For the original script this meant at the start it switched off commands and responses, and then at the end, switched them back on again.

=echo cmds(NO)
=echo resp(NO)
:
=echo cmds(YES)
=echo resp(YES)

This would have the slightly undesirable effect that if you had either of those turned off before you ran the script, the script would inadvertently turn them back on again when it was done!

In the new version where the script is wrapped into function, there is only one =echo statement at the top.

=echo resp(NO)

There is no need to switch responses back on again because the =echo statement only applies inside the function. The function is a black box to any callers. It doesn’t impact any settings, such as these =echo settings, on the caller. Also notice that the default inside a function is that the commands are not shown anyway.

Functions aren’t just handy for wrapping your scripts into handy re-usable chunks, but also functions are very useful when they are parameterised. In this blog post we’re going to make some changes to the supplied conns() function to add a parameter. At the moment it totals all your connections. Now we’ll give it a parameter of an application name (or part of one) and it can total just those connections.

To indicate that a function has a parameter, the parameter name goes between the parentheses on the func conns() statement. When you later refer to that parameter in your script statements within the function you prefix it’s name with the ‘@’ symbol to show that it is a user variable.

func conns(ApplTag)
  :
  @ApplTag ...

In the MQSCX control language, parameters are not mandatory. We are still allowed to call the conns() function without giving it a parameter – if we code it that way. This would be a handy thing to have; without a parameter it totals everything, with a parameter it filters the totals by that application.

The way to achieve this – to have a parameter that can be optional – is to ensure that everywhere the parameter is used is preceded by a test to see if it exists. Now, I want to use the parameter more than once; first to check it against the APPLTAG that comes back from a DISPLAY CONN command, and then to check it against the RAPPLTAG that comes back from a DISPLAY CHSTATUS command. So rather than checking it exists multiple times, right up front I’ll test it and set it to a useful value if it doesn’t exist.

if (!exists(@ApplTag))
  @ApplTag = ""
endif

Now I can use the @ApplTag variable throughout the rest of the function with impunity.

In the old version of the script it just counted the totals that came back from a command issued to the command server – now it needs to look at the output to see whether the APPLTAG attribute contains the string supplied in the parameter. So let’s replace the initial two display commands with the following:-

@localconns = 0
@chlconns   = 0
foreach(DISPLAY CONN(*) CHANNEL APPLTAG)
  if (findstri(APPLTAG, @ApplTag))
    if (CHANNEL)
      @chlconns = @chlconns + 1
    else
      @localconns = @localconns + 1
    endif
  endif
endfor

Clearly if you ask to filter by an application name, none of the queue manager channel connections are going to match, but this code will still work when we don’t want to filter by anything because the findstri function returns TRUE when asked if the string contains the empty string.

N.B. findstri is the case insensitive version of findstr.

We also make a little tweak to the print out of the first line to reflect the use of the parameter by the user running the function.

And finally, the pre-existing foreach loop needs a little tweak. The DISPLAY CHSTATUS command is extended to also return the RAPPLTAG attribute, and then an if statement is added just as with the earlier for loop.

foreach(DISPLAY CHSTATUS(*) CURSHCNV CHLTYPE RAPPLTAG WHERE(STATUS EQ RUNNING)
  if (findstri(RAPPLTAG, @ApplTag))
    if (CHLTYPE = "SVRCONN")

Clearly you could take these changes even further, perhaps adding a parameter to configure a detail level for the output, with high detail showing all the channel names. The possibilities are endless. We hope you find functions a very useful addition to your MQSCX scripts.

Here’s the final view of the updated function with all the changes described in this post.

***********************************************************************
* Function : conns                                                    *
* Purpose  : Print out the current state of connections to the QM     *
***********************************************************************
func conns(ApplTag)

  if (_connqmgr = '')
    print 'Please connect to your queue manager before issuing "conns"'
    return
  endif

  if (!exists(@ApplTag))
    @ApplTag = ""
  endif

  @localconns = 0
  @chlconns   = 0
  foreach(DISPLAY CONN(*) CHANNEL APPLTAG)
    if (findstri(APPLTAG, @ApplTag))
      if (CHANNEL)
        @chlconns = @chlconns + 1
      else
        @localconns = @localconns + 1
      endif
    endif
  endfor

  if (@ApplTag)
    print 'Total connections containing "',:n:@ApplTag,:n:'":',@localconns + @chlconns
  else
    print 'Total connections:',@localconns + @chlconns
  endif
  print '   Local      :',@localconns

  @total = 0
  @svrcn = 0
  foreach(DISPLAY CHSTATUS(*) CURSHCNV CHLTYPE RAPPLTAG WHERE(STATUS EQ RUNNING)
    if (findstri(RAPPLTAG, @ApplTag))
      if (CHLTYPE = "SVRCONN")
        @svrcn = @svrcn + 1
        @total = @total + CURSHCNV
      endif
    endif
  endfor
  print '   QMgr Chls  :',@chlconns-@total
  print '   Client Chls:',@total
  print
  print 'Total Running Channel instances:',_matches
  print '   QMgr   Channels:',_matches - @svrcn
  print '   Client Channels:',@svrcn

endfunc

If you are a current MQSCX licence holder, you can simply download the new version of MQSCX and start using it. If you’re not a current licence holder, and you’d like to try out MQSCX, please email support@mqgem.com to request a trial licence.

Using the CCDT URL

MQGem recently delivered new versions of MO71 and MQSCX that support the new IBM MQ V9 release. As well as support for the new command level, they support other new IBM MQ V9 features. One such feature is the ability to have your Client Channel Definition Table (CCDT) hosted somewhere centralised, such as on an FTP server or web server. Prior to IBM MQ V9, this was only available to Java clients due to the fact that the language gave you the capability whenever you needed to specify a file name URI. Now in IBM MQ V9, ‘C’ clients (and unmanaged .NET clients) also have this feature.

Jon Rumsey has a great write-up of this feature on the MQDev Blog, MQ V9 Client Channel Table Enhancements – URL retrieval.

MO71

You can either set the MQCCDTURL environment variable and the whole MO71 application will take note of it, or you can set it individually for specific locations by providing the CCDT URL in the location dialog. Open the Location, ensure the Client checkbox is ticked which enables two things, the Configure button – which is for defining your channel definition manually through the MQCNO, and the CCDT URL entry field, which is where you can put the URL of your hosted CCDT file. You don’t need both of course, and MQ defines a precedence order of which is used if you do specify both.

MO71 Location Dialog showing CCDT URL field in use

Specify your CCDT URL in the MO71 Location Dialog.
Please note, the URL shown is for demonstration purposes only. There is no CCDT at the shown URL!

MQSCX

As with MO71, you can either set the MQCCDTURL environment variable and the whole MQSCX application will take note of it, or you can set it individually for specific locations by providing the ccdturl() on the =conn command.

MQSCX Extended MQSC Program – Version 9.0.0

Licenced to Paul Clarke

Licence Location: Head Quarters

> =conn qm(MQ900) client ccdturl(http://www.mqgem.com/MQGEM.TAB)

MQSCX Extended MQSC Program – Version 9.0.0

Licenced to Paul Clarke

Licence Location: Head Quarters

[14:05:31] =conn qm(MQ900) client ccdturl(http://www.mqgem.com/MQ

Connected to ‘MQ900’

MQ900>


If this feature interests you and you’d like to try it out for yourself on either of these products, and you are not currently a licence holder, you may email support@mqgem.com to request a trial licence.

MQSCX version 9.0.0 is released

MQGem Software is pleased to announce that a new version of MQSCX, our command line extended MQSC tool for IBM MQ, is now available.

The main features of the release are as follows:-

Support for MQ Command Level 900

As normal with a new release of IBM MQ, there is a new command level. MQSCX now supports this new command level and its contents.

foreach

foreach(…) loop now operates in CCDT mode

Previous releases of MQSCX allowed the use of the foreach(…) statement to process each response from the command server. This release extends that processing to work with the responses to commands issued against the CCDT. For more information see Scripts using foreach on the CCDT

New iteration system variables loops

New system variables _idxEach, _idxItem, _idxWhile, _numEach, _numItem and _numWhile which can make processing loops easier.

Support of CCDT URL

IBM MQ V9 allows a connecting application to specify the URL location of the CCDT file to use. This field can now be specified on the =conn command. For more information see Using the CCDT URL.
MQSCX Functions

Support for functions

You can now define lists of commands which can be invoked from the command line, other functions or expressions. For more information see MQSCX functions, which has a worked example.

Support for GOTO

You can now jump to labelled parts of your code.
MQSCX Bootstrap

Automatically loads bootstrap.mqx file

This can be useful to load useful functions so they are always available. Although it could equally be used to always run a specific command or several commands every time the MQSCX tool is started. For more information see MQSCX Bootstrap file.

Various improvements to the usability of the debugger

Including commands to support the new functions capability, such as sf to set your current stack frame.

New eval() function

This function allows the user to create more dynamic expressions by having the contents of strings evaluated as an expression. For example, print eval(“curdepth > 0”).


The new version can be downloaded from the MQSCX Download Page. Any current licensed users of MQSCX can run the new version on their existing licence. If you don’t have a licence and would like to try out MQSCX then send a note to support@mqgem.com and a 1-month trial licence will be sent to you.

MaxChannels vs DIS QMSTATUS CONNS

I got asked this question on twitter the other day, so I thought it would make an interesting blog post.

Let’s look at each piece of the question.

DISPLAY QMSTATUS CONNS

You can use the DISPLAY QMSTATUS command to see how many connections there are currently made into the queue manager. This is a count of the number of applications (or some queue manager processes too) that have made an MQCONN(X) to the queue manager. It is also the same number of responses you should see returned by DISPLAY CONN(*) – if you don’t want to count them, find an MQ admin tool that counts them for you. These connections might be local or client connections – both contribute to the total.

To see the local ones use command:-

DISPLAY CONN(*) ALL WHERE(CHANNEL EQ ' ')

To see the remote ones use command:-

DISPLAY CONN(*) ALL WHERE(CHANNEL NE ' ')

Client Connections and MaxChannels

So having ruled out the local connections what should you think if the number of connections coming in over a channel is more than MaxChannels? As the question asks, “Shouldn’t that be failing?”

The other thing to remember here is that, since MQ V7, one SVRCONN channel can relay several client MQCONNs over to the queue manager.

To see this take a look at the DISPLAY CHSTATUS command. There is a status attribute CURSHCNV that shows the number currently being shared over that one SVRCONN instance.

To see the number of running channels, use the command:-

DISPLAY CHSTATUS(*) CURSHCNV

The number of responses will show you how many running channel instances there are – which is the number to compare against MaxChannels. If you add up the total of all the numbers shown in CURSHCNV, this total will be less than (or equal to) the above number of channel based connections shown when you used the DISPLAY CONN command. Both queue manager channels and client channels contribute to that total.

HINT: If you want an easy way to total up all the numbers shown in CURSHCNV, try out MQSCX with this single line:-

@total=0;foreach(DISPLAY CHSTATUS(*) CURSHCNV);@total=@total+CURSHCNV;endfor;print @total

Or you could make a little import file to print out all the various numbers:-

=echo cmds(NO)
=echo resp(NO)
print 'Show all the connections into queue manager',_connqmgr
print _sep

DISPLAY QMSTATUS CONNS
print 'Total connections ',CONNS

DISPLAY CONN(*) ALL WHERE(CHANNEL EQ ' ')
print 'Local connections ',_matches

DISPLAY CONN(*) ALL WHERE(CHANNEL NE ' ')
print 'Remote connections',_matches

@total = 0
@svrcn = 0
foreach(DISPLAY CHSTATUS(*) CURSHCNV CHLTYPE)
  if (CHLTYPE = "SVRCONN")
    @svrcn = @svrcn + 1
  endif
  @total = @total + CURSHCNV
endfor
print 'Total Channel instances ',_matches
print 'QMgr Channel instances  ',_matches - @svrcn
print 'Client Channel instances',@svrcn
print 'Client connections',@total
=echo cmds(YES)
=echo resp(YES)

UPDATE: This script evolved further with the release of MQSCX V9.0.0 and the use of functions – see more in MQSCX Functions.


IBM Certified SpecialistIBM Champion 2016 Middleware

Morag Hughson
IBM Champion 2016 – Middleware
IBM Certified System Administrator – MQ V8.0
Find her on: LinkedIn: http://uk.linkedin.com/in/moraghughson Twitter: https://twitter.com/MoragHughson SlideShare: http://www.slideshare.net/moraghughson developerWorks: https://www.ibm.com/developerworks/community/profiles/html/profileView.do?userid=110000EQPN

Manipulating Namelists with MQSCX

NamelistWriting a script to make changes to an MQ Namelist is actually very difficult to do. You have to display the contents of the list of names, and then build an ALTER NAMELIST command passing in the original list along with your changes to that list. What a palaver.

MQSCX makes that operation marvelously simple. Adding, or removing names from the list in a namelist is very simple. Here’s an example to show you just how simple it is.

ALTER NAMELIST(OVERLAPPING.CLUSTER) =add(SALES)

Before the command was issued the OVERLAPPING.CLUSTER had, let’s say, three names in the list:-

AMQ8550: Display namelist details.
   NAMELIST(OVERLAPPING.CLUSTER)           NAMCOUNT(3)
   NAMES(NEWS                           
        ,INVENTORY                      
        ,PAYMENT)                          DESCR(Cluster Repos NL)
   ALTDATE(2016-02-11)                     ALTTIME(21.03.44)

After the command was issued it now looks like:-

AMQ8550: Display namelist details.
   NAMELIST(OVERLAPPING.CLUSTER)           NAMCOUNT(4)
   NAMES(NEWS                           
        ,INVENTORY                      
        ,PAYMENT                        
        ,SALES)                            DESCR(Cluster Repos NL)
   ALTDATE(2016-02-11)                     ALTTIME(21.04.50)

The beauty of this command is that, you didn’t need to know what the names in the namelist were in order to add a new name to the list.

If the list already had the name you tried to add in the list, then the command won’t add it in a second time.

There is also the capability to remove names from the list – also with a very simple command.

ALTER NAMELIST(OVERLAPPING.CLUSTER) =rmv(NEWS)

Not only can you remove a single name, you can also use wildcards in the =rmv field to match against multiple names in the list and remove them all.

Of course, the best way to understand scripts is of course to have a go with them yourself. If this looks like something you’d like to try, and you are not currently an MQSCX licence holder, you may email support@mqgem.com to request a trial licence and have a go with it yourself.

MQSCX feature – String Replace

MQSCX String ReplaceWhen building a report, or outputting information to the screen about your IBM MQ Queue Manager, you may wish to manipulate strings, as is shown in a new example script, mqauthlist.mqsx, available in our Example Scripts bundle. This script builds an array of temporary dynamic queues to exclude from the report later. Some string manipulation is done on the names to make the search easier using the strreplace() function of MQSCX to replace underscores with dots. Here’s how:-

** Query the queue manager for the current temporary dynamic queues
delvar(@tempqlist)
@x = 0
foreach(DISPLAY QLOCAL(*) WHERE(DEFTYPE EQ TEMPDYN))

   if( !_cmdok )
      print "Error querying TempDyn queues for queue manager", _qmgr
      continue
   endif

   @x = @x + 1
   ** In order for the search to work properly,
   ** we need to uppercase the queue names
   ** and substitute underscores with periods.
   @tempqlist[@x] = strreplace(upper(QUEUE), "_", ".")
endfor

Of course there are many uses you might find for using the strreplace() function, especially if you want to work with MQ object names that follow a Naming Convention, then you might find yourself wanting to replace the characters TEST with the characters PROD when working with different environments for Test and Production.


The best way to understand scripts is of course to have a go with them yourself. There are various examples in the download, so why not try them out yourself. If you are not currently an MQSCX licence holder, you may email support@mqgem.com to request a trial licence.