From 12f5f93b87de8334a7f505fb37cf20b6915ff529 Mon Sep 17 00:00:00 2001 From: ibmmqmet Date: Fri, 25 Feb 2022 12:48:31 +0000 Subject: [PATCH] Update for MQ 9.2.5 --- CHANGELOG.md | 7 +++ DEPRECATIONS.md | 2 + Dockerfile | 2 +- ibmmq/cmqc_aix.go | 8 ++- ibmmq/cmqc_darwin.go | 8 ++- ibmmq/cmqc_linux_amd64.go | 8 ++- ibmmq/cmqc_linux_ppc64le.go | 8 ++- ibmmq/cmqc_linux_s390x.go | 8 ++- ibmmq/cmqc_windows.go | 8 ++- ibmmq/mqiMQCNO.go | 40 ++++++------- ibmmq/mqiPCF.go | 98 ++++++++++++++++++++++++++++++++ ibmmq/mqistr.go | 4 ++ mqmetric/discover.go | 20 ++++--- mqmetric/globals.go | 1 + mqmetric/mqif.go | 28 +++++---- mqmetric/status.go | 16 ++++-- samples/amqspcf.go | 2 +- samples/runSample.deb.Dockerfile | 2 +- samples/runSample.ubi.Dockerfile | 2 +- 19 files changed, 207 insertions(+), 65 deletions(-) diff --git a/CHANGELOG.md b/CHANGELOG.md index 3bebf10..b7571dd 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -1,6 +1,13 @@ # Changelog Newest updates are at the top of this file. +## Feb 25 2022 - v5.2.5 +* Update for MQ 9.2.5 +* ibmmq - Add MQI character constants for Group/Segment status +* ibmmq - PCF parser now understands PCF Groups +* samples - Add a PCF command creator/parser +* mqmetric - Optional ReplyQ2 config parm as separate name (ibm-messaging/mq-metric-samples#100) + ## Nov 19 2021 - v5.2.4 * Update for MQ 9.2.4 * ibmmq - Support for MQBNO (application balancing) structure diff --git a/DEPRECATIONS.md b/DEPRECATIONS.md index 9479f7a..61c14f6 100644 --- a/DEPRECATIONS.md +++ b/DEPRECATIONS.md @@ -15,6 +15,8 @@ The following interfaces are planned to be removed: * The replacement APIs is already available in the v5 stream. * InqMap - was a temporary route to replace original Inq function * Replacement is the current Inq function +* The PCFParameter class will change so that instead of separate + int64/string etc values, there's a single {} interface object #### Package mqmetric * Remove direct access to xxxStatus variables. diff --git a/Dockerfile b/Dockerfile index be7ab98..f6a20dc 100644 --- a/Dockerfile +++ b/Dockerfile @@ -58,7 +58,7 @@ RUN mkdir -p $GOPATH/src $GOPATH/bin $GOPATH/pkg \ # Location of the downloadable MQ client package \ ENV RDURL="https://public.dhe.ibm.com/ibmdl/export/pub/software/websphere/messaging/mqdev/redist" \ RDTAR="IBM-MQC-Redist-LinuxX64.tar.gz" \ - VRMF=9.2.4.0 + VRMF=9.2.5.0 # Install the MQ client from the Redistributable package. This also contains the # header files we need to compile against. Setup the subset of the package diff --git a/ibmmq/cmqc_aix.go b/ibmmq/cmqc_aix.go index a4cdad6..e2ccbbf 100644 --- a/ibmmq/cmqc_aix.go +++ b/ibmmq/cmqc_aix.go @@ -32,8 +32,8 @@ package ibmmq **************************************************************** * * -* Generated on: 11/4/21 3:44 PM -* Build Level: p924-L211104 +* Generated on: 2/7/22 6:36 PM +* Build Level: p925-L220207 * Build Type: Production * */ @@ -1021,7 +1021,7 @@ const ( MQCMDI_SEC_SIGNOFF_ERROR int32 = 17 MQCMDI_SEC_TIMER_ZERO int32 = 14 MQCMDI_SEC_UPPERCASE int32 = 21 - MQCMDL_CURRENT_LEVEL int32 = 924 + MQCMDL_CURRENT_LEVEL int32 = 925 MQCMDL_LEVEL_1 int32 = 100 MQCMDL_LEVEL_101 int32 = 101 MQCMDL_LEVEL_110 int32 = 110 @@ -1067,6 +1067,7 @@ const ( MQCMDL_LEVEL_922 int32 = 922 MQCMDL_LEVEL_923 int32 = 923 MQCMDL_LEVEL_924 int32 = 924 + MQCMDL_LEVEL_925 int32 = 925 MQCMD_ACCOUNTING_MQI int32 = 167 MQCMD_ACCOUNTING_Q int32 = 168 MQCMD_ACTIVITY_MSG int32 = 69 @@ -2669,6 +2670,7 @@ const ( MQIMMREASON_NONE int32 = 0 MQIMMREASON_NOT_CLIENT int32 = 1 MQIMMREASON_NOT_RECONNECTABLE int32 = 2 + MQIMMREASON_NO_REDIRECT int32 = 7 MQIMPO_CONVERT_TYPE int32 = 2 MQIMPO_CONVERT_VALUE int32 = 32 MQIMPO_CURRENT_LENGTH int32 = 64 diff --git a/ibmmq/cmqc_darwin.go b/ibmmq/cmqc_darwin.go index 2aa1219..2c639e7 100644 --- a/ibmmq/cmqc_darwin.go +++ b/ibmmq/cmqc_darwin.go @@ -30,8 +30,8 @@ package ibmmq **************************************************************** * * -* Generated on: 11/4/21 3:44 PM -* Build Level: p924-L211104 +* Generated on: 2/7/22 6:36 PM +* Build Level: p925-L220207 * Build Type: Production * */ @@ -1019,7 +1019,7 @@ const ( MQCMDI_SEC_SIGNOFF_ERROR int32 = 17 MQCMDI_SEC_TIMER_ZERO int32 = 14 MQCMDI_SEC_UPPERCASE int32 = 21 - MQCMDL_CURRENT_LEVEL int32 = 924 + MQCMDL_CURRENT_LEVEL int32 = 925 MQCMDL_LEVEL_1 int32 = 100 MQCMDL_LEVEL_101 int32 = 101 MQCMDL_LEVEL_110 int32 = 110 @@ -1065,6 +1065,7 @@ const ( MQCMDL_LEVEL_922 int32 = 922 MQCMDL_LEVEL_923 int32 = 923 MQCMDL_LEVEL_924 int32 = 924 + MQCMDL_LEVEL_925 int32 = 925 MQCMD_ACCOUNTING_MQI int32 = 167 MQCMD_ACCOUNTING_Q int32 = 168 MQCMD_ACTIVITY_MSG int32 = 69 @@ -2667,6 +2668,7 @@ const ( MQIMMREASON_NONE int32 = 0 MQIMMREASON_NOT_CLIENT int32 = 1 MQIMMREASON_NOT_RECONNECTABLE int32 = 2 + MQIMMREASON_NO_REDIRECT int32 = 7 MQIMPO_CONVERT_TYPE int32 = 2 MQIMPO_CONVERT_VALUE int32 = 32 MQIMPO_CURRENT_LENGTH int32 = 64 diff --git a/ibmmq/cmqc_linux_amd64.go b/ibmmq/cmqc_linux_amd64.go index 7d6580d..f2433e5 100644 --- a/ibmmq/cmqc_linux_amd64.go +++ b/ibmmq/cmqc_linux_amd64.go @@ -30,8 +30,8 @@ package ibmmq **************************************************************** * * -* Generated on: 11/4/21 3:44 PM -* Build Level: p924-L211104 +* Generated on: 2/7/22 6:36 PM +* Build Level: p925-L220207 * Build Type: Production * */ @@ -1019,7 +1019,7 @@ const ( MQCMDI_SEC_SIGNOFF_ERROR int32 = 17 MQCMDI_SEC_TIMER_ZERO int32 = 14 MQCMDI_SEC_UPPERCASE int32 = 21 - MQCMDL_CURRENT_LEVEL int32 = 924 + MQCMDL_CURRENT_LEVEL int32 = 925 MQCMDL_LEVEL_1 int32 = 100 MQCMDL_LEVEL_101 int32 = 101 MQCMDL_LEVEL_110 int32 = 110 @@ -1065,6 +1065,7 @@ const ( MQCMDL_LEVEL_922 int32 = 922 MQCMDL_LEVEL_923 int32 = 923 MQCMDL_LEVEL_924 int32 = 924 + MQCMDL_LEVEL_925 int32 = 925 MQCMD_ACCOUNTING_MQI int32 = 167 MQCMD_ACCOUNTING_Q int32 = 168 MQCMD_ACTIVITY_MSG int32 = 69 @@ -2667,6 +2668,7 @@ const ( MQIMMREASON_NONE int32 = 0 MQIMMREASON_NOT_CLIENT int32 = 1 MQIMMREASON_NOT_RECONNECTABLE int32 = 2 + MQIMMREASON_NO_REDIRECT int32 = 7 MQIMPO_CONVERT_TYPE int32 = 2 MQIMPO_CONVERT_VALUE int32 = 32 MQIMPO_CURRENT_LENGTH int32 = 64 diff --git a/ibmmq/cmqc_linux_ppc64le.go b/ibmmq/cmqc_linux_ppc64le.go index fdcdcfc..f92cb18 100644 --- a/ibmmq/cmqc_linux_ppc64le.go +++ b/ibmmq/cmqc_linux_ppc64le.go @@ -30,8 +30,8 @@ package ibmmq **************************************************************** * * -* Generated on: 11/4/21 3:44 PM -* Build Level: p924-L211104 +* Generated on: 2/7/22 6:36 PM +* Build Level: p925-L220207 * Build Type: Production * */ @@ -1019,7 +1019,7 @@ const ( MQCMDI_SEC_SIGNOFF_ERROR int32 = 17 MQCMDI_SEC_TIMER_ZERO int32 = 14 MQCMDI_SEC_UPPERCASE int32 = 21 - MQCMDL_CURRENT_LEVEL int32 = 924 + MQCMDL_CURRENT_LEVEL int32 = 925 MQCMDL_LEVEL_1 int32 = 100 MQCMDL_LEVEL_101 int32 = 101 MQCMDL_LEVEL_110 int32 = 110 @@ -1065,6 +1065,7 @@ const ( MQCMDL_LEVEL_922 int32 = 922 MQCMDL_LEVEL_923 int32 = 923 MQCMDL_LEVEL_924 int32 = 924 + MQCMDL_LEVEL_925 int32 = 925 MQCMD_ACCOUNTING_MQI int32 = 167 MQCMD_ACCOUNTING_Q int32 = 168 MQCMD_ACTIVITY_MSG int32 = 69 @@ -2667,6 +2668,7 @@ const ( MQIMMREASON_NONE int32 = 0 MQIMMREASON_NOT_CLIENT int32 = 1 MQIMMREASON_NOT_RECONNECTABLE int32 = 2 + MQIMMREASON_NO_REDIRECT int32 = 7 MQIMPO_CONVERT_TYPE int32 = 2 MQIMPO_CONVERT_VALUE int32 = 32 MQIMPO_CURRENT_LENGTH int32 = 64 diff --git a/ibmmq/cmqc_linux_s390x.go b/ibmmq/cmqc_linux_s390x.go index 374c7c5..0af9477 100644 --- a/ibmmq/cmqc_linux_s390x.go +++ b/ibmmq/cmqc_linux_s390x.go @@ -30,8 +30,8 @@ package ibmmq **************************************************************** * * -* Generated on: 11/4/21 3:44 PM -* Build Level: p924-L211104 +* Generated on: 2/7/22 6:36 PM +* Build Level: p925-L220207 * Build Type: Production * */ @@ -1019,7 +1019,7 @@ const ( MQCMDI_SEC_SIGNOFF_ERROR int32 = 17 MQCMDI_SEC_TIMER_ZERO int32 = 14 MQCMDI_SEC_UPPERCASE int32 = 21 - MQCMDL_CURRENT_LEVEL int32 = 924 + MQCMDL_CURRENT_LEVEL int32 = 925 MQCMDL_LEVEL_1 int32 = 100 MQCMDL_LEVEL_101 int32 = 101 MQCMDL_LEVEL_110 int32 = 110 @@ -1065,6 +1065,7 @@ const ( MQCMDL_LEVEL_922 int32 = 922 MQCMDL_LEVEL_923 int32 = 923 MQCMDL_LEVEL_924 int32 = 924 + MQCMDL_LEVEL_925 int32 = 925 MQCMD_ACCOUNTING_MQI int32 = 167 MQCMD_ACCOUNTING_Q int32 = 168 MQCMD_ACTIVITY_MSG int32 = 69 @@ -2667,6 +2668,7 @@ const ( MQIMMREASON_NONE int32 = 0 MQIMMREASON_NOT_CLIENT int32 = 1 MQIMMREASON_NOT_RECONNECTABLE int32 = 2 + MQIMMREASON_NO_REDIRECT int32 = 7 MQIMPO_CONVERT_TYPE int32 = 2 MQIMPO_CONVERT_VALUE int32 = 32 MQIMPO_CURRENT_LENGTH int32 = 64 diff --git a/ibmmq/cmqc_windows.go b/ibmmq/cmqc_windows.go index 87c2a7e..9106f50 100644 --- a/ibmmq/cmqc_windows.go +++ b/ibmmq/cmqc_windows.go @@ -30,8 +30,8 @@ package ibmmq **************************************************************** * * -* Generated on: 11/4/21 3:44 PM -* Build Level: p924-L211104 +* Generated on: 2/7/22 6:36 PM +* Build Level: p925-L220207 * Build Type: Production * */ @@ -1019,7 +1019,7 @@ const ( MQCMDI_SEC_SIGNOFF_ERROR int32 = 17 MQCMDI_SEC_TIMER_ZERO int32 = 14 MQCMDI_SEC_UPPERCASE int32 = 21 - MQCMDL_CURRENT_LEVEL int32 = 924 + MQCMDL_CURRENT_LEVEL int32 = 925 MQCMDL_LEVEL_1 int32 = 100 MQCMDL_LEVEL_101 int32 = 101 MQCMDL_LEVEL_110 int32 = 110 @@ -1065,6 +1065,7 @@ const ( MQCMDL_LEVEL_922 int32 = 922 MQCMDL_LEVEL_923 int32 = 923 MQCMDL_LEVEL_924 int32 = 924 + MQCMDL_LEVEL_925 int32 = 925 MQCMD_ACCOUNTING_MQI int32 = 167 MQCMD_ACCOUNTING_Q int32 = 168 MQCMD_ACTIVITY_MSG int32 = 69 @@ -2667,6 +2668,7 @@ const ( MQIMMREASON_NONE int32 = 0 MQIMMREASON_NOT_CLIENT int32 = 1 MQIMMREASON_NOT_RECONNECTABLE int32 = 2 + MQIMMREASON_NO_REDIRECT int32 = 7 MQIMPO_CONVERT_TYPE int32 = 2 MQIMPO_CONVERT_VALUE int32 = 32 MQIMPO_CURRENT_LENGTH int32 = 64 diff --git a/ibmmq/mqiMQCNO.go b/ibmmq/mqiMQCNO.go index ec4386b..dbeeb63 100644 --- a/ibmmq/mqiMQCNO.go +++ b/ibmmq/mqiMQCNO.go @@ -1,7 +1,7 @@ package ibmmq /* - Copyright (c) IBM Corporation 2016,2021 + Copyright (c) IBM Corporation 2016,2022 Licensed under the Apache License, Version 2.0 (the "License"); you may not use this file except in compliance with the License. @@ -34,9 +34,9 @@ to select what can be done. void freeCnoCCDTUrl(MQCNO *mqcno) { #if defined(MQCNO_VERSION_6) && MQCNO_CURRENT_VERSION >= MQCNO_VERSION_6 - if (mqcno->CCDTUrlPtr != NULL) { - free(mqcno->CCDTUrlPtr); - } + if (mqcno->CCDTUrlPtr != NULL) { + free(mqcno->CCDTUrlPtr); + } #endif } @@ -44,17 +44,17 @@ void setCnoCCDTUrl(MQCNO *mqcno, PMQCHAR url, MQLONG length) { #if defined(MQCNO_VERSION_6) && MQCNO_CURRENT_VERSION >= MQCNO_VERSION_6 if (mqcno->Version < MQCNO_VERSION_6) { mqcno->Version = MQCNO_VERSION_6; - } - mqcno->CCDTUrlOffset = 0; - mqcno->CCDTUrlPtr = NULL; - mqcno->CCDTUrlLength = length; - if (url != NULL && length > 0) { - mqcno->CCDTUrlPtr = url; - } + } + mqcno->CCDTUrlOffset = 0; + mqcno->CCDTUrlPtr = NULL; + mqcno->CCDTUrlLength = length; + if (url != NULL && length > 0) { + mqcno->CCDTUrlPtr = url; + } #else - if (url != NULL) { - free(url); - } + if (url != NULL) { + free(url); + } #endif } @@ -75,21 +75,21 @@ void setCnoApplName(MQCNO *mqcno, PMQCHAR applName, MQLONG length) { return; } -// A totally new structure in MQ 9.2.4. In order to handle builds against older versions of MQ +// A new structure in MQ 9.2.4. In order to handle builds against older versions of MQ // we have to extract the individual fields from the Go version of the structure first. And // we then use those as separate parameters to this function. void setCnoBalanceParms(MQCNO *mqcno, MQLONG ApplType, MQLONG Timeout, MQLONG Options) { #if defined(MQCNO_VERSION_8) && MQCNO_CURRENT_VERSION >= MQCNO_VERSION_8 PMQBNO pmqbno = malloc(MQBNO_CURRENT_LENGTH); // This is freed on return from the C function pmqbno->Version = MQBNO_VERSION_1; - memcpy(pmqbno->StrucId,MQBNO_STRUC_ID,4); + memcpy(pmqbno->StrucId,MQBNO_STRUC_ID,4); pmqbno->ApplType = ApplType; pmqbno->Timeout = Timeout; pmqbno->Options = Options; mqcno->BalanceParmsPtr = pmqbno; - mqcno->BalanceParmsOffset = 0; + mqcno->BalanceParmsOffset = 0; if (mqcno->Version < MQCNO_VERSION_8) { - mqcno->Version = MQCNO_VERSION_8; + mqcno->Version = MQCNO_VERSION_8; } #endif return; @@ -98,8 +98,8 @@ void setCnoBalanceParms(MQCNO *mqcno, MQLONG ApplType, MQLONG Timeout, MQLONG Op void freeCnoBalanceParms(MQCNO *mqcno) { #if defined(MQCNO_VERSION_8) && MQCNO_CURRENT_VERSION >= MQCNO_VERSION_8 if (mqcno->Version >= MQCNO_VERSION_8 && mqcno->BalanceParmsPtr != NULL) { - free(mqcno->BalanceParmsPtr); - } + free(mqcno->BalanceParmsPtr); + } #endif return; } diff --git a/ibmmq/mqiPCF.go b/ibmmq/mqiPCF.go index 6a0b8e1..afff2d1 100644 --- a/ibmmq/mqiPCF.go +++ b/ibmmq/mqiPCF.go @@ -50,6 +50,20 @@ type MQCFH struct { ParameterCount int32 } +/* +MQEPH is a structure containing the MQ PCF Embedded Header fields +It is always followed by a CFH which we do not include here +*/ +type MQEPH struct { + Version int32 + StrucLength int32 + Encoding int32 + CodedCharSetId int32 + Format string + Control int32 + Flags int32 +} + /* PCFParameter is a structure containing the data associated with various types of PCF element. Use the Type field to decide which @@ -85,6 +99,21 @@ func NewMQCFH() *MQCFH { return cfh } +/* +NewMQEPH returns a PCF Embedded Header structure with correct initialisation +*/ +func NewMQEPH() *MQEPH { + eph := new(MQEPH) + eph.StrucLength = C.MQEPH_STRUC_LENGTH_FIXED + eph.Version = C.MQCFH_VERSION_1 + eph.Encoding = 0 + eph.CodedCharSetId = C.MQCCSI_UNDEFINED + eph.Format = C.MQFMT_NONE + eph.Flags = C.MQEPH_NONE + + return eph +} + /* Bytes serialises an MQCFH structure as if it were the corresponding C structure */ @@ -128,6 +157,23 @@ func (p *PCFParameter) Bytes() []byte { var buf []byte switch p.Type { + case C.MQCFT_GROUP: + buf = make([]byte, C.MQCFGR_STRUC_LENGTH) + offset := 0 + l := len(p.GroupList) + + endian.PutUint32(buf[offset:], uint32(p.Type)) + offset += 4 + endian.PutUint32(buf[offset:], uint32(len(buf))) + offset += 4 + endian.PutUint32(buf[offset:], uint32(p.Parameter)) + offset += 4 + endian.PutUint32(buf[offset:], uint32(l)) + offset += 4 + for i := 0; i < l; i++ { + buf = append(buf, p.GroupList[i].Bytes()...) + } + case C.MQCFT_INTEGER: buf = make([]byte, C.MQCFIN_STRUC_LENGTH) offset := 0 @@ -207,6 +253,46 @@ func ReadPCFHeader(buf []byte) (*MQCFH, int) { return cfh, bytesRead } +/* +ReadPCFEmbeddedHeader extracts the MQCFH from an MQ message +*/ +func ReadPCFEmbeddedHeader(buf []byte) (*MQEPH, int) { + var dummy int32 + + fullLen := len(buf) + if fullLen < C.MQEPH_STRUC_LENGTH_FIXED { + return nil, 0 + } + + eph := new(MQEPH) + p := bytes.NewBuffer(buf) + + offset := 0 + binary.Read(p, endian, &dummy) + offset += 4 + binary.Read(p, endian, &eph.Version) + offset += 4 + + binary.Read(p, endian, &eph.StrucLength) + offset += 4 + + binary.Read(p, endian, &eph.Encoding) + offset += 4 + + binary.Read(p, endian, &eph.CodedCharSetId) + offset += 4 + + s := string(buf[offset : offset+8]) + s = trimToNull(s) + offset += 8 + p.Next(8) + + binary.Read(p, endian, &eph.Flags) + bytesRead := fullLen - p.Len() + + return eph, bytesRead +} + /* ReadPCFParameter extracts the next PCF parameter element from an MQ message. @@ -278,8 +364,18 @@ func ReadPCFParameter(buf []byte) (*PCFParameter, int) { p.Next(int(pcfParm.strucLength - C.MQCFSL_STRUC_LENGTH_FIXED)) case C.MQCFT_GROUP: + // This reads the entire group, including the group elements. + // Which might in turn be nested groups binary.Read(p, endian, &pcfParm.Parameter) binary.Read(p, endian, &pcfParm.ParameterCount) + offset := 16 // Include the Type/StrucLength words in the already-read count + bytesRead := 0 + pcfParm.GroupList = make([]*PCFParameter, pcfParm.ParameterCount) + for i := 0; i < int(pcfParm.ParameterCount); i++ { + pcfParm.GroupList[i], bytesRead = ReadPCFParameter(buf[offset:]) + offset += bytesRead + } + return pcfParm, offset case C.MQCFT_BYTE_STRING: // The byte string is converted to a hex string as that's how @@ -297,7 +393,9 @@ func ReadPCFParameter(buf []byte) (*PCFParameter, int) { // TODO: Put this in something like an environment variable control option localerr := fmt.Errorf("mqiPCF.go: Unknown PCF type %d", pcfParm.Type) fmt.Println("Error: ", localerr) + fmt.Println("Buffer Len: ", len(buf)) fmt.Println("Buffer: ", buf) + debug.PrintStack() // After dumping the stack, we will try to carry on regardless. // Skip the remains of this structure, assuming it really is diff --git a/ibmmq/mqistr.go b/ibmmq/mqistr.go index 731e6e7..0f035da 100644 --- a/ibmmq/mqistr.go +++ b/ibmmq/mqistr.go @@ -1421,6 +1421,8 @@ func MQItoString(class string, value int) string { s = "MQCMDL_LEVEL_923" case 924: s = "MQCMDL_LEVEL_924" + case 925: + s = "MQCMDL_LEVEL_925" default: s = "" } @@ -2495,6 +2497,8 @@ func MQItoString(class string, value int) string { s = "MQIMMREASON_IN_TRANSACTION" case 6: s = "MQIMMREASON_AWAITS_REPLY" + case 7: + s = "MQIMMREASON_NO_REDIRECT" default: s = "" } diff --git a/mqmetric/discover.go b/mqmetric/discover.go index dec3116..0449073 100644 --- a/mqmetric/discover.go +++ b/mqmetric/discover.go @@ -185,11 +185,14 @@ func VerifyConfig() (int32, error) { // Make sure this reply queue that has been opened is not a predefined queue, so it // has come from a model definition. The base replyQ is opened twice for different reasons. - // A LOCAL queue would end up with mixed sets of replies/publications - defType := v[ibmmq.MQIA_DEFINITION_TYPE].(int32) - if defType == ibmmq.MQQDT_PREDEFINED { - err = fmt.Errorf("Error: ReplyQ parameter %s must refer to a MODEL queue,", ci.si.replyQBaseName) - compCode = ibmmq.MQCC_FAILED + // A LOCAL queue would end up with mixed sets of replies/publications. + // This test is bypassed if 2 different reply queue names are configured. + if ci.si.replyQ2BaseName == "" || ci.si.replyQ2BaseName == ci.si.replyQBaseName { + defType := v[ibmmq.MQIA_DEFINITION_TYPE].(int32) + if defType == ibmmq.MQQDT_PREDEFINED { + err = fmt.Errorf("Error: ReplyQ parameter %s must refer to a MODEL queue,", ci.si.replyQBaseName) + compCode = ibmmq.MQCC_FAILED + } } } } @@ -1198,13 +1201,14 @@ func parsePCFResponse(buf []byte) ([]*ibmmq.PCFParameter, bool) { elem, bytesRead = ibmmq.ReadPCFParameter(buf[offset:]) offset += bytesRead // Have we now reached the end of the message + // We now understand PCF Groups so don't need to extract them explicitly elemList = append(elemList, elem) if elem.Type == ibmmq.MQCFT_GROUP { groupElem := elem for j := 0; j < int(groupElem.ParameterCount); j++ { - elem, bytesRead = ibmmq.ReadPCFParameter(buf[offset:]) - offset += bytesRead - groupElem.GroupList = append(groupElem.GroupList, elem) + //elem, bytesRead = ibmmq.ReadPCFParameter(buf[offset:]) + //offset += bytesRead + //groupElem.GroupList = append(groupElem.GroupList, elem) } } diff --git a/mqmetric/globals.go b/mqmetric/globals.go index cfafa87..8e78156 100644 --- a/mqmetric/globals.go +++ b/mqmetric/globals.go @@ -29,6 +29,7 @@ type sessionInfo struct { replyQObj ibmmq.MQObject qMgrObject ibmmq.MQObject replyQBaseName string + replyQ2BaseName string statusReplyQObj ibmmq.MQObject statusReplyBuf []byte diff --git a/mqmetric/mqif.go b/mqmetric/mqif.go index a856d11..dd98b41 100644 --- a/mqmetric/mqif.go +++ b/mqmetric/mqif.go @@ -81,13 +81,13 @@ InitConnection connects to the queue manager, and then opens both the command queue and a dynamic reply queue to be used for all responses including the publications */ -func InitConnection(qMgrName string, replyQ string, cc *ConnectionConfig) error { - return initConnectionKey("", qMgrName, replyQ, cc) +func InitConnection(qMgrName string, replyQ string, replyQ2 string, cc *ConnectionConfig) error { + return initConnectionKey("", qMgrName, replyQ, replyQ2, cc) } -func InitConnectionKey(key string, qMgrName string, replyQ string, cc *ConnectionConfig) error { - return initConnectionKey(key, qMgrName, replyQ, cc) +func InitConnectionKey(key string, qMgrName string, replyQ string, replyQ2 string, cc *ConnectionConfig) error { + return initConnectionKey(key, qMgrName, replyQ, replyQ2, cc) } -func initConnectionKey(key string, qMgrName string, replyQ string, cc *ConnectionConfig) error { +func initConnectionKey(key string, qMgrName string, replyQ string, replyQ2 string, cc *ConnectionConfig) error { var err error var gocd *ibmmq.MQCD var mqreturn *ibmmq.MQReturn @@ -238,7 +238,7 @@ func initConnectionKey(key string, qMgrName string, replyQ string, cc *Connectio // MQOPEN of a reply queue also used for subscription delivery if err == nil { mqod := ibmmq.NewMQOD() - openOptions := ibmmq.MQOO_INPUT_AS_Q_DEF | ibmmq.MQOO_FAIL_IF_QUIESCING + openOptions := ibmmq.MQOO_INPUT_EXCLUSIVE | ibmmq.MQOO_FAIL_IF_QUIESCING openOptions |= ibmmq.MQOO_INQUIRE mqod.ObjectType = ibmmq.MQOT_Q mqod.ObjectName = replyQ @@ -246,8 +246,9 @@ func initConnectionKey(key string, qMgrName string, replyQ string, cc *Connectio ci.si.replyQBaseName = replyQ if err == nil { ci.si.queuesOpened = true + clearQ(ci.si.replyQObj) } else { - errorString = "Cannot open queue " + replyQ + errorString = "Cannot open queue " + mqod.ObjectName mqreturn = err.(*ibmmq.MQReturn) } } @@ -255,13 +256,20 @@ func initConnectionKey(key string, qMgrName string, replyQ string, cc *Connectio // MQOPEN of a second reply queue used for status polling if err == nil { mqod := ibmmq.NewMQOD() - openOptions := ibmmq.MQOO_INPUT_AS_Q_DEF | ibmmq.MQOO_FAIL_IF_QUIESCING + openOptions := ibmmq.MQOO_INPUT_EXCLUSIVE | ibmmq.MQOO_FAIL_IF_QUIESCING mqod.ObjectType = ibmmq.MQOT_Q - mqod.ObjectName = replyQ + ci.si.replyQ2BaseName = replyQ2 + if replyQ2 != "" { + mqod.ObjectName = replyQ2 + } else { + mqod.ObjectName = replyQ + } ci.si.statusReplyQObj, err = ci.si.qMgr.Open(mqod, openOptions) if err != nil { - errorString = "Cannot open queue " + replyQ + errorString = "Cannot open queue " + mqod.ObjectName mqreturn = err.(*ibmmq.MQReturn) + } else { + clearQ(ci.si.statusReplyQObj) } } diff --git a/mqmetric/status.go b/mqmetric/status.go index 89de1ea..8cebb13 100644 --- a/mqmetric/status.go +++ b/mqmetric/status.go @@ -144,10 +144,7 @@ func statusTimeDiff(now time.Time, d string, t string) int64 { return rc } -func statusClearReplyQ() { - traceEntry("statusClearReplyQ") - ci := getConnection(GetConnectionKey()) - +func clearQ(hObj ibmmq.MQObject) { buf := make([]byte, 0) // Empty replyQ in case any left over from previous errors for ok := true; ok; { @@ -158,12 +155,21 @@ func statusClearReplyQ() { gmo.Options |= ibmmq.MQGMO_NO_WAIT gmo.Options |= ibmmq.MQGMO_CONVERT gmo.Options |= ibmmq.MQGMO_ACCEPT_TRUNCATED_MSG - _, err := ci.si.statusReplyQObj.Get(getmqmd, gmo, buf) + _, err := hObj.Get(getmqmd, gmo, buf) if err != nil && err.(*ibmmq.MQReturn).MQCC == ibmmq.MQCC_FAILED { ok = false } } + return +} + +func statusClearReplyQ() { + traceEntry("statusClearReplyQ") + ci := getConnection(GetConnectionKey()) + + clearQ(ci.si.statusReplyQObj) + traceExit("statusClearReplyQ", 0) return } diff --git a/samples/amqspcf.go b/samples/amqspcf.go index de73904..a5c1980 100644 --- a/samples/amqspcf.go +++ b/samples/amqspcf.go @@ -319,7 +319,7 @@ func printPcfParm(p *ibmmq.PCFParameter) { func close(object ibmmq.MQObject) error { err := object.Close(0) if err == nil { - fmt.Println("Closed queue") + fmt.Println("Closed queue " + object.Name) } else { fmt.Println(err) } diff --git a/samples/runSample.deb.Dockerfile b/samples/runSample.deb.Dockerfile index eae2a37..b6813e0 100644 --- a/samples/runSample.deb.Dockerfile +++ b/samples/runSample.deb.Dockerfile @@ -74,7 +74,7 @@ RUN mkdir -p $GOPATH/src $GOPATH/bin $GOPATH/pkg \ # Location of the downloadable MQ client package \ ENV RDURL="https://public.dhe.ibm.com/ibmdl/export/pub/software/websphere/messaging/mqdev/redist" \ RDTAR="IBM-MQC-Redist-LinuxX64.tar.gz" \ - VRMF=9.2.4.0 + VRMF=9.2.5.0 # Install the MQ client from the Redistributable package. This also contains the # header files we need to compile against. Setup the subset of the package diff --git a/samples/runSample.ubi.Dockerfile b/samples/runSample.ubi.Dockerfile index 3700319..1e700f2 100644 --- a/samples/runSample.ubi.Dockerfile +++ b/samples/runSample.ubi.Dockerfile @@ -52,7 +52,7 @@ RUN mkdir -p $GOPATH/src $GOPATH/bin $GOPATH/pkg \ # Location of the downloadable MQ client package \ ENV RDURL="https://public.dhe.ibm.com/ibmdl/export/pub/software/websphere/messaging/mqdev/redist" \ RDTAR="IBM-MQC-Redist-LinuxX64.tar.gz" \ - VRMF=9.2.4.0 + VRMF=9.2.5.0 # Install the MQ client from the Redistributable package. This also contains the # header files we need to compile against. Setup the subset of the package