Connecting to an MQ with Jmeter - java

I've been assigned the task of using Apache Jmeter to connect to an MQ. Unfortunately, I'm not the admin of the MQ, and all my attempts to get more information about it have gotten me nowhere. What I have now is a queue name (call it q), a queue manager (its name, anyway; call it v), a host (w), a port (x), a channel (y), a user (z), and a test message I'm supposed to send across. The object of the game is straightforward: send the test message from Apache Jmeter to the MQ (after which I'll ask the admins whether the message went through or not). In other words, I need help figuring out what to do with Jmeter.
The MQ is version 8.0.0.4. I already have Jmeter installed, so I don't need advice on that (unless there's some special way it should have been installed for this task).
The links provided in this question's answer didn't get me very far. They seemed largely unrelated to what I was trying to do (and also imprecise in their instructions).

Download 8.0.0.4-WS-MQ-Install-Java-All file
Run it like java -jar 8.0.0.4-WS-MQ-Install-Java-All.jar and accept the license agreement
Add all .jars from wmq/JavaSE/ folder to JMeter Classpath
Restart JMeter to pick the .jars up
Add JSR223 Sampler to your Test Plan and put the following code into "Script" area:
import com.ibm.msg.client.jms.JmsFactoryFactory
import com.ibm.msg.client.wmq.WMQConstants
import javax.jms.Session
// 1
def hostName = "127.0.0.1"
def hostPort = 1414
def channelName = "DEV.APP.SVRCONN"
def queueManagerName = "QM1"
def queueName = "DEV.QUEUE.1"
// 2
def ff = JmsFactoryFactory.getInstance(WMQConstants.WMQ_PROVIDER)
def cf = ff.createConnectionFactory()
// 3
cf.setStringProperty(WMQConstants.WMQ_HOST_NAME, hostName)
cf.setIntProperty(WMQConstants.WMQ_PORT, hostPort)
cf.setStringProperty(WMQConstants.WMQ_CHANNEL, channelName)
cf.setIntProperty(WMQConstants.WMQ_CONNECTION_MODE, WMQConstants.WMQ_CM_CLIENT)
cf.setStringProperty(WMQConstants.WMQ_QUEUE_MANAGER, queueManagerName)
// 4
def conn = cf.createConnection("app", "")
def sess = conn.createSession(false, Session.AUTO_ACKNOWLEDGE)
// 5
def destination = sess.createQueue(queueName)
conn.start()
See IBM MQ testing with JMeter - Learn How article for more information if needed.

Related

Jmeter not finishing because of daemon threads

I am trying to run a JMX file from non GUI mode on linux server. Using SFTP protocol trying to upload file to object store. Below is the script and configuration used to run the script.
Test.jmx
import com.jcraft.jsch.*;
import java.io.*;
def jsch = new JSch()
def session = jsch.getSession("user1", "xyz", 4000)
session.setConfig("StrictHostKeyChecking", "no")
session.setPassword("password")
def sftpSession = session.connect()
def channel = session.openChannel("sftp")
channel.connect();
def channelSftp = (ChannelSftp)channel;
log.info("SFTP Connection with host is acquired" + channelSftp)
channelSftp.cd("/0002/test/upload/r9a1");
def f1 = new File("/home/dc-user/Files/test_exact5mb.txt");
channelSftp.put(new java.io.FileInputStream(f1), f1.getName()+ Math.random());
session.disconnect()
Configuration used is
No of Threads - 150
Ramp up period - 1
Loop Count -1
After running the script, out of 150 files sometimes 126 or 129 or 141 files gets uploaded but not 150.
Below is the error i see on terminal
The JVM should have exited but did not.
The following non-daemon threads are still running (DestroyJavaVM is OK):
Thread[Connect thread 10.157.147.242 session,5,main], stackTrace:java.net.SocketInputStream#socketRead0
java.net.SocketInputStream#socketRead at line:116
java.net.SocketInputStream#read at line:171
java.net.SocketInputStream#read at line:141
com.jcraft.jsch.IO#getByte at line:82
com.jcraft.jsch.Session#read at line:908
com.jcraft.jsch.Session#run at line:1378
java.lang.Thread#run at line:74
Please let me know if i am missing any configuration
I fail to see how this code can work as your i is not defined anywhere so it will not even compile
It seems that some thread(s) cannot be finished because they are still reading something, I believe you have some form of SLAs or NFRs which define the maximum acceptable time for the file upload operation and your test seems to be exceeding this time.
So before calling def sftpSession = session.connect() I would recommend placing the Session.setTimeout() function call like:
session.setTimeout(5000)
this way if the operation is not finished in 5 seconds your sampler will fail
If you're not too comfortable with Groovy scripting using SSH SFTP sampler might be much easier, check out Load Testing FTP and SFTP Servers Using JMeter article for more details.

Setting Trusted Packages (ActiveMQ)

I am trying to send receive ActiveMQ messages. But I see the messages come back with this message in them.
JMSException in onMessage(): javax.jms.JMSException: Failed to build body from content. Serializable class not available to broker. Reason: java.lang.ClassNotFoundException: Forbidden class com.logicalprovisioning.common.gtc.shared.GTCMessage! This class is not trusted to be serialized as ObjectMessage payload. Please take a look at http://activemq.apache.org/objectmessage.html for more information on how to configure trusted classes.
So I read the link in the message. And I tried to follow the instructions. Although I must say its not very well written on where to put the configuration.
So what I did was:
1. I edited the ACTIVEMQ_OPTS line in activemq.bat file in the bin folder to
if "%ACTIVEMQ_OPTS%" == "" set ACTIVEMQ_OPTS=-Xms1G -Xmx1G -Djava.util.logging.config.file=logging.properties -Djava.security.auth.login.config="%ACTIVEMQ_CONF%\login.config" -Dorg.apache.activemq.SERIALIZABLE_PACKAGES=com.logicalprovisioning.common.gtc.shared.GTCMessage
It didn't work.
I added the above line in the activemq.bat of the win64 folder as well. It didn't work.
I modified my subscriber object creation to add the Trusted Packages. Like:
String providerEndpoints = "tcp://" + host + ":" + port + "?wireFormat.maxInactivityDuration=7200000";
// Set the trusted packages/classes to move back and forth on the ActiveMQ JMS service.
ArrayList<String> trustedClasses = new ArrayList<String>();
trustedClasses.add("com.logicalprovisioning.common.gtc.shared.GTCMessage");
// Obtain the factory
ActiveMQConnectionFactory activeMQConnectionFactory = new ActiveMQConnectionFactory();
activeMQConnectionFactory.setBrokerURL(providerEndpoints);
// Add the trusted packages/classes to the ActiveMQ consumer.
activeMQConnectionFactory.setTrustedPackages(trustedClasses);
//Create the connection
setConnection(activeMQConnectionFactory.createQueueConnection());
getConnection().setClientID(this.getName());
// Make a session
setSession(getConnection().createQueueSession(false, Session.AUTO_ACKNOWLEDGE));
getSession().createQueue(jmsDestination);
// Create the destination
Destination destination = getSession().createQueue(jmsDestination);
String selector = "JMSCorrelationID = '" + getActionRequest().getOriginId() + "_" + getActionRequest().getRequestId() + "'" ;
setConsumer(getSession().createConsumer(destination, selector));
getConsumer().setMessageListener(new DefaultMessageListener(this));
// Start ...
gtcMessages = new GTCMessageQueue<GTCMessage>(); // We'll need a message store now
getConnection().start();
And I added something similar in my producer as well for good measure:
Context initialContext = new InitialContext();
Context environmentContext = (Context) initialContext.lookup("java:comp/env");
String queueConnectionFactoryNameLookup = PalInit.getProperty("jms.queue.connection.factory");
// Set the trusted packages/classes to move back and forth on the ActiveMQ JMS service.
ArrayList<String> trustedClasses = new ArrayList<String>();
trustedClasses.add("com.logicalprovisioning.common.gtc.shared.GTCMessage");
ActiveMQConnectionFactory activeMQConnectionFactory = (ActiveMQConnectionFactory) environmentContext.lookup(queueConnectionFactoryNameLookup);
activeMQConnectionFactory.setTrustedPackages(trustedClasses);
// Create connection
QueueConnection queueConnection = activeMQConnectionFactory.createQueueConnection();
queueConnection.start();
// Create session and producer
setSession(queueConnection.createSession(false, Session.AUTO_ACKNOWLEDGE));
String queueName = PalInit.getProperty("jms.destination");
Queue jmsQueue = getSession().createQueue(queueName);
setProducer(getSession().createProducer(jmsQueue));
setQueueConnection(queueConnection);
// Set Message "Time to Live" to the request timeout plus 10 minutes
getProducer().setTimeToLive(getTimeout() + (10 * 60 * 1000L));
But nothing seems to work. I have the ActiveMQ-All jar in the Tomcat's lib folder and so too the jar where the GTCMessage class resides. Can anyone please tell me what am I doing wrong? Is it a problem of a missing class or my bad configuration? Any help would be appreciated. Thanks!
The application is running on Tomcat 9, JAVA 1.8 and Active MQ 5.15.11.
I think your problem is that you're setting the name of the specific class rather than the package of the class. The code looks at the package name, not the class name. Try this:
// Set the trusted packages to move back and forth on the ActiveMQ JMS service.
ArrayList<String> trustedPackages = new ArrayList<String>();
trustedPackages.add("com.logicalprovisioning.common.gtc.shared");
ActiveMQConnectionFactory activeMQConnectionFactory = (ActiveMQConnectionFactory) environmentContext.lookup(queueConnectionFactoryNameLookup);
activeMQConnectionFactory.setTrustedPackages(trustedPackages);
I don't think you'll need to set this on the broker itself.
Aside from that I would strongly discourage you from using JMS ObjectMessage. They depend on Java serialization to marshal and unmarshal their object payload. This process is generally considered unsafe, because a malicious payload can exploit the host system. Lots of CVEs have been created for this which is why most JMS providers force users to explicitly whitelist packages that can be exchanged using ObjectMessage messages.
There are also a number of other issues with using JMS ObjectMessage not related to security that you should read about. This article has a good suggestion for how to replace ObjectMessage - define a data representation for the payload (JSON, protobuf, XML) and use TextMessage or BytesMessage to carry it.

work with IBM MQ from Java

I have a problem with connection in IBM MQ from java
this code
val cf: MQQueueConnectionFactory?
var mqConnection: QueueConnection? = null
var session: QueueSession? = null
var sender: QueueSender? = null
var value = ""
try {
cf = MQQueueConnectionFactory()
cf.hostName = host
cf.port = port
cf.queueManager = queueManager
cf.transportType = transport
cf.channel = channelName
cf.clientReconnectOptions = WMQConstants.WMQ_CLIENT_RECONNECT_Q_MGR
cf.clientReconnectTimeout = 3600
mqConnection = cf.createQueueConnection()
drops exception "JMSCMQ0001: WebSphere MQ call failed with compcode
'2' ('MQCC_FAILED') reason '2035' ('MQRC_NOT_AUTHORIZED')"
when I try create connection cf.createQueueConnection()
I don't understand what is a problem.
I use ibmmq lib 9.0.2.0 version, but this code doesn't work with 7.5.0.1 version too
MQRC 2035 means the user doesn't have the appropriate authorities to connect to the queue manager. The reason can be found in the AMQERR*.log in the queue manager errors directory. CHLAUTH is enabled by default. You need to add CHLAUTH rules. Following link provides details on create/modify CHLAUTH
IBM MQ 7.5.0 > WebSphere MQ > Reference > Administration reference > MQSC reference > The MQSC commands > SET CHLAUTH
If you want more details on CHLAUTH then go through the following link:
CHLAUTH Made Simple: Common Scenarios and Examples and How to Verify them with RUNCHECK
mqConnection = cf.createQueueConnection()
You should/need to pass the UserId and Password for the connection.
i.e.
mqConnection = cf.createQueueConnection("myUserId", "mypwd");

IBM MQ fail with reason '2278' ('MQRC_CLIENT_CONN_ERROR')

I have been trying with no luck to get a java app to connect to IBM MQ v8 via CCDT file. I can connect fine when connecting using properties (hostname, port, etc) but with CCDT I consistently get WebSphere MQ call failed with compcode '2' ('MQCC_FAILED') reason '2278' ('MQRC_CLIENT_CONN_ERROR').
I am using a vanilla install of MQ Developer 8.0 (version required, can't change) and the Jars from the installation. All I did was install MQ, then setup a QueueManager 'QM1', then create a queue 'Q1'.
My code:
package mqtest;
import com.ibm.mq.jms.*;
import java.io.File;
import java.net.URL;
public class Main {
public static void main(String[] args) {
try {
MQQueueConnectionFactory cf = new MQQueueConnectionFactory();
File file = new File("C:/ProgramData/IBM/MQ/qmgrs/QM1/#ipcc/AMQCLCHL.TAB");
URL clientChannelTableUrl = file.toURI().toURL();
cf.setQueueManager("QM1");
cf.setCCDTURL(clientChannelTableUrl);
MQQueueConnection mqQueueConnection = (MQQueueConnection) cf.createConnection();
} catch (Exception e) {
e.printStackTrace();
}
}
}
dis qmgr
AMQ8408: Display Queue Manager details.
QMNAME(QM1) ACCTCONO(DISABLED)
ACCTINT(1800) ACCTMQI(OFF)
ACCTQ(OFF) ACTIVREC(MSG)
ACTVCONO(DISABLED) ACTVTRC(OFF)
ALTDATE(2018-05-23) ALTTIME(10.21.26)
AUTHOREV(DISABLED) CCSID(437)
CERTLABL(ibmwebspheremqqm1) CERTVPOL(ANY)
CHAD(DISABLED) CHADEV(DISABLED)
CHADEXIT( ) CHLEV(DISABLED)
CHLAUTH(ENABLED) CLWLDATA( )
CLWLEXIT( ) CLWLLEN(100)
CLWLMRUC(999999999) CLWLUSEQ(LOCAL)
CMDEV(DISABLED) CMDLEVEL(800)
COMMANDQ(SYSTEM.ADMIN.COMMAND.QUEUE) CONFIGEV(DISABLED)
CONNAUTH(SYSTEM.DEFAULT.AUTHINFO.IDPWOS)
CRDATE(2018-05-23) CRTIME(10.21.26)
CUSTOM( ) DEADQ( )
DEFCLXQ(SCTQ) DEFXMITQ( )
DESCR( ) DISTL(YES)
INHIBTEV(DISABLED) IPADDRV(IPV4)
LOCALEV(DISABLED) LOGGEREV(DISABLED)
MARKINT(5000) MAXHANDS(256)
MAXMSGL(4194304) MAXPROPL(NOLIMIT)
MAXPRTY(9) MAXUMSGS(10000)
MONACLS(QMGR) MONCHL(OFF)
MONQ(OFF) PARENT( )
PERFMEV(DISABLED) PLATFORM(WINDOWSNT)
PSMODE(ENABLED) PSCLUS(ENABLED)
PSNPMSG(DISCARD) PSNPRES(NORMAL)
PSRTYCNT(5) PSSYNCPT(IFPER)
QMID(QM1_2018-05-23_10.21.26) REMOTEEV(DISABLED)
REPOS( ) REPOSNL( )
REVDNS(ENABLED) ROUTEREC(MSG)
SCHINIT(QMGR) SCMDSERV(QMGR)
SPLCAP(ENABLED) SSLCRLNL( )
SSLCRYP( ) SSLEV(DISABLED)
SSLFIPS(NO)
SSLKEYR(C:\ProgramData\IBM\MQ\qmgrs\QM1\ssl\key)
SSLRKEYC(0) STATACLS(QMGR)
STATCHL(OFF) STATINT(1800)
The error log in C:\ProgramData\IBM\MQ\qmgrs\QM1\errors has no relevant (that I can see at least) data in it.
As far as I can tell from various SO, IBM, Google searches this should work. As far as I can tell it has something to do with Channel definition or settings, but I just don't know what.
And, honestly, I think I have spent enough brain cells on this that I am most likely overlooking something important but can't see the small simple detail I am overlooking. Any help as appreciated.
MQ Version: 9.0.0.4
Step 1: only one jar required: com.ibm.mq.allclient-9.0.4.0.jar
Step 2:
Do not set any variable in MQEnvironment
Step 3:
java.net.URL chanTab1 = new URL("file:///C:/MGR.TAB");
MQQueueManager _queueManager = new MQQueueManager("*", chanTab1);
int openOptions = MQC.MQOO_OUTPUT + MQC.MQOO_FAIL_IF_QUIESCING;
MQQueue queue = _queueManager.accessQueue( "QNAME", openOptions,null,null, null );
MQMessage sendmsg = new MQMessage();
* will allow you to connect all the QManager available in the .TAB file.
Step 4:
Install certificate in your jre C:\Program Files\Java\jdk1.7\jre\bin by command
keytool -import -alias example -keystore ..\lib\security\cacerts -file C:\test.cer
default password is changeit. Mostly nobody change this. :-)
or
if you deployed your code on websphere application server then no need to install certificate in server JRE. Insted install certificate on Websphere server
SSL certificate and key management > Key stores and certificates > NodeDefaultKeyStore > Signer certificates > Retrieve from port

Issues with connecting to ibm mq 7.5 using java

I'm very new to ibm mq, I find out the documents or books related to mb are so few, the only one I found is 'WebSphere MQ Using Java' written in 2004. But the real world has changed a lot.
I installed and verified mq server 7.5 on redhat linux 64 bit successfully according to this
I also created queue manager myqm1, queue LQ.TEST, channel JAVA.CHANNEL and did some test through command lines on server to ensure they work well. However when I installed a mq client on windows xp and wrote below java code, it always throw a exception:com.ibm.mq.MQException: MQJE001: Completion Code '2', Reason '2035'
my code:
import com.ibm.mq.*; import com.ibm.mq.constants.MQConstants;
/** * Simple example program */ public class MQSample {
// code identifier
static final String sccsid = "#(#) MQMBID sn=p000-L120604 su=_H-IvIK4nEeGko6IWl3MDhA pn=MQJavaSamples/wmqjava/MQSample.java";
// define the name of the QueueManager
private static final String qManager = "myqm1";
// and define the name of the Queue
private static final String qName = "LQ.TEST";
/**
* Main entry point
*
* #param args - command line arguments (ignored)
*/
public static void main(String args[]) {
try {
MQEnvironment.hostname = "58.2.221.196";
MQEnvironment.channel = "JAVA.CHANNEL";
MQEnvironment.port = 1414;
MQEnvironment.properties.put(MQC.TRANSPORT_PROPERTY, MQC.TRANSPORT_MQSERIES);
MQEnvironment.userID = "mqm";
MQEnvironment.password = "mqm";
MQEnvironment.CCSID = 1208;
// Create a connection to the QueueManager
System.out.println("Connecting to queue manager: " + qManager);
MQQueueManager qMgr = new MQQueueManager(qManager);
// Set up the options on the queue we wish to open
int openOptions = MQConstants.MQOO_INPUT_AS_Q_DEF | MQConstants.MQOO_OUTPUT;
// Now specify the queue that we wish to open and the open options
System.out.println("Accessing queue: " + qName);
MQQueue queue = qMgr.accessQueue(qName, openOptions);
// Define a simple WebSphere MQ Message ...
MQMessage msg = new MQMessage();
// ... and write some text in UTF8 format
msg.writeUTF("Hello, World!");
// Specify the default put message options
MQPutMessageOptions pmo = new MQPutMessageOptions();
// Put the message to the queue
System.out.println("Sending a message...");
queue.put(msg, pmo);
// Now get the message back again. First define a WebSphere MQ
// message
// to receive the data
MQMessage rcvMessage = new MQMessage();
// Specify default get message options
MQGetMessageOptions gmo = new MQGetMessageOptions();
// Get the message off the queue.
System.out.println("...and getting the message back again");
queue.get(rcvMessage, gmo);
// And display the message text...
String msgText = rcvMessage.readUTF();
System.out.println("The message is: " + msgText);
// Close the queue
System.out.println("Closing the queue");
queue.close();
// Disconnect from the QueueManager
System.out.println("Disconnecting from the Queue Manager");
qMgr.disconnect();
System.out.println("Done!");
} catch (MQException ex) {
ex.printStackTrace();
System.out.println("A WebSphere MQ Error occured : Completion Code " + ex.completionCode
+ " Reason Code " + ex.reasonCode);
} catch (java.io.IOException ex) {
System.out.println("An IOException occured whilst writing to the message buffer: " + ex);
}
return;
} }
Can anybody throw a light to me on that? I'm totally down.
To expand on Shashi's answer, since WMQ V7.1 the default CHLAUTH rules block all access on all SVRCONN channels and they block administrative access on all SVRCONN channels. If you really want to connect to JAVA.CHANNEL as mqm then you will need to override both of these behaviors.
If you are actually willing to allow remote, unauthenticated connections to the QMgr with an administrative user ID, then you have the option of disabling CHLAUTH rules altogether. You can do this by issuing the ALTER QMGR CHLAUTH(DISABLED) command in runmqsc however this is HIGHLY discouraged because it leaves the QMgr open to anonymous remote code execution using the WMQ administrative user ID. This is, however, what you appear to be trying to do.
The recommended approach would be to use an ID that is not administrative. For example, if you made an ID called mquser with a private group also called mquser then you could grant it rights to connect and inquire on the QMgr and to open the designated queue for put, get, browse and inquire. Since the ID is not administrative, it would be relatively safe to use on unauthenticated channels. You could change your code to specify the ID as mquser instead of mqm and then use a CHLAUTH rule to allow the connection. For example:
SET CHLAUTH('JAVA.CHANNEL') TYPE(USERMAP) +
CLNTUSER('mquser') USERSRC(MAP) +
MCAUSER('mquser') ACTION(ADD)
The above rule tells the QMgr "when you see a connection from the mquser ID on JAVA.CHANNEL, then set MCAUSER to mquser and allow the connection."
When you grant permissions, remember to grant them on the group and not the user. For example, if using setmqaut use the -g option and not the -p option. If there are any issues with authorization errors, you can sort these out easily using event messages. First, enable events using the ALTER QMGR AUTHOREV(ENABLED). This will cause the QMgr to emit an event message into the SYSTEM.ADMIN.QMGR.EVENT queue. You can use SupportPac MH05 or SupportPac MS0P to parse the event messages. For any given authorization event the message tells you the ID that requested access, the API call (connect, open, close etc.), the object the call was made against and the exact options that were used.
Prior to WMQ V7.1, WebSphere MQ allowed all remote connections, even anonymous, administrative ones. Although this allowed you to connect easily, in today's more hostile network environment the ability to remotely and anonymously execute code on the QMgr's host server is seen as an unacceptable security risk. So now a new QMgr is set to not allow any remote administrative access by default. As the administrator this requires you to explicitly disable security to get the old behavior or to explicitly provision secure access.
In MQ v7.5, by default access to queue manager is blocked. You need to create channel authentication records for the channel you created, JAVA.CHANNEL to allow user to access queue manager. Please follow this link for more details on Channel Authentication Records

Categories