Skip to content

Commit

Permalink
Merge pull request #12 from Appdynamics/7.0.3
Browse files Browse the repository at this point in the history
7.0.3
  • Loading branch information
kunalgupApDx authored Jan 6, 2020
2 parents 73c2719 + 40226a4 commit 62072ba
Show file tree
Hide file tree
Showing 15 changed files with 192 additions and 54 deletions.
56 changes: 36 additions & 20 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -71,7 +71,9 @@ Configure the monitor by editing the config.yml file in <code><machine-agent-dir
3. Configure the queueManages with appropriate fields and filters. Below sample consists of 2 queueManagers.
```
queueManagers:
- host: "192.168.57.104"
- displayName: ""
# displayName (optional). This will be your QM name that will show up in AppD metric path. If empty, name (below) will show up.
host: "192.168.57.104"
port: 1414
#Actual name of the queue manager
name: "TEST_QM_1"
Expand All @@ -81,7 +83,7 @@ Configure the monitor by editing the config.yml file in <code><machine-agent-dir
#For bindings type connection WMQ extension (i.e machine agent) need to be on the same machine on which WebbsphereMQ server is running
#for client type connection change it to "Client".
transportType: "Client"
#user with admin level access, no need to provide credentials in case of bindings transport type, it is only applicable for client type
##for user access level, please check "Access Permissions" section on the extensions page, no need to provide credentials in case of bindings transport type, it is only applicable for client type
username: "hello"
password: "hello"
Expand Down Expand Up @@ -137,7 +139,7 @@ Configure the monitor by editing the config.yml file in <code><machine-agent-dir
#For bindings type connection WMQ extension (i.e machine agent) need to be on the same machine on which WebbsphereMQ server is running
#for client type connection change it to "Client".
transportType: "Client"
#user with admin level access, no need to provide credentials in case of bindings transport type, it is only applicable for client type
##for user access level, please check "Access Permissions" section on the extensions page, no need to provide credentials in case of bindings transport type, it is only applicable for client type
username: "hello"
password: "hello"
#This is the timeout on queue metrics threads.Default value is 20 seconds. No need to change the default
Expand Down Expand Up @@ -284,6 +286,7 @@ Configure the monitor by editing the config.yml file in <code><machine-agent-dir
ibmConstant: "com.ibm.mq.constants.CMQC.MQIA_SUB_COUNT"
ibmCommand: "MQCMD_INQUIRE_TOPIC_STATUS"
```
5. To run the extension at a frequency > 1 minute, please configure the taskSchedule section. Refer to the [Task Schedule](https://community.appdynamics.com/t5/Knowledge-Base/Task-Schedule-for-Extensions/ta-p/35414) doc for details.

### Extension Working - Internals
This extension extracts metrics through [PCF framework](https://www.ibm.com/support/knowledgecenter/SSFKSJ_8.0.0/com.ibm.mq.adm.doc/q019990_.htm). A complete list of PCF commands are listed [here](https://www.ibm.com/support/knowledgecenter/SSFKSJ_7.5.0/com.ibm.mq.ref.adm.doc/q086870_.htm)
Expand All @@ -299,22 +302,35 @@ If you are in **Bindings** mode, please make sure to start the MA process under
The user connecting to the queueManager should have the inquire, get, put (since PCF responses cause dynamic queues to be created) permissions. For metrics that execute MQCMD_RESET_Q_STATS command, chg permission is needed.

### SSL Support
Configure the IBM SSL Cipher Suite in the config.yaml.
1. Configure the IBM SSL Cipher Suite in the config.yml.
Note that, to use some CipherSuites the unrestricted policy needs to be configured in JRE. Please visit [this link](http://www.ibm.com/support/knowledgecenter/SSYKE2_8.0.0/com.ibm.java.security.component.80.doc/security-component/sdkpolicyfiles.html
) for more details. For Oracle JRE, please update with [JCE Unlimited Strength Jurisdiction Policy](http://www.oracle.com/technetwork/java/javase/downloads/jce8-download-2133166.html). The download includes a readme file with instructions on how to apply these files to JRE

Note that, to use some CipherSuites the unrestricted policy needs to be configured in JRE. Please visit [this link](http://www.ibm.com/support/knowledgecenter/SSYKE2_8.0.0/com.ibm.java.security.component.80.doc/security-component/sdkpolicyfiles.html
) for more details. For Oracle JRE, please update with [JCE Unlimited Strength Jurisdiction Policy](http://www.oracle.com/technetwork/java/javase/downloads/jce8-download-2133166.html)
2. Please add the following JVM arguments to the MA start up command or script.

To configure SSL, the MA's trust store and keystore needs to be setup with the JKS filepath.

Please add the following JVM arguments to the MA start up command or script.

```-Dcom.ibm.mq.cfg.useIBMCipherMappings=false``` (If you are using IBM Cipher Suites, set the flag to true. Please visit [this link](http://www.ibm.com/support/knowledgecenter/SSFKSJ_8.0.0/com.ibm.mq.dev.doc/q113210_.htm) for more details.
)
```-Dcom.ibm.mq.cfg.useIBMCipherMappings=false``` (If you are using IBM Cipher Suites, set the flag to true. Please visit [this link](http://www.ibm.com/support/knowledgecenter/SSFKSJ_8.0.0/com.ibm.mq.dev.doc/q113210_.htm) for more details.
)
3. To configure SSL, the MA's trust store and keystore needs to be setup with the JKS filepath. They can be passed either as Machine Agent JVM arguments or configured in config.yml (sslConnection) <br />

a. Machine Agent JVM arguments as follows:

```-Djavax.net.ssl.trustStore=<PATH_TO_JKS_FILE>```
```-Djavax.net.ssl.trustStorePassword=<PASS>```
```-Djavax.net.ssl.keyStore=<PATH_TO_JKS_FILE>```
```-Djavax.net.ssl.keyStorePassword=<PASS>```
```-Djavax.net.ssl.trustStore=<PATH_TO_JKS_FILE>```<br />
```-Djavax.net.ssl.trustStorePassword=<PASS>```<br />
```-Djavax.net.ssl.keyStore=<PATH_TO_JKS_FILE>```<br />
```-Djavax.net.ssl.keyStorePassword=<PASS>```<br />

b. sslConnection in config.yml, configure the trustStorePassword or trustStoreEncryptedPassword based on Credentials Encryption. Same holds for keyStore configuration as well.

```
sslConnection:
trustStorePath: ""
trustStorePassword: ""
trustStoreEncryptedPassword: ""
keyStorePath: ""
keyStorePassword: ""
keyStoreEncryptedPassword: ""
```
## Metrics
The metrics will be reported under the tree ```Application Infrastructure Performance|$TIER|Custom Metrics|WebsphereMQ```
Expand Down Expand Up @@ -494,7 +510,7 @@ Workbench is an inbuilt feature provided with each extension in order to assist
This might occour due to various reasons ranging from incorrect installation to applying [ibm fix packs](http://www-01.ibm.com/support/docview.wss?uid=swg21410038) but most of the time it happens when you are trying to connect in `Bindings` mode and machine agent is not on the same machine on which WMQ server is running. If you want to connect to WMQ server from a remote machine then connect using `Client` mode.
Another way to get around this issue is to avoid using the Bindings mode. Connect using CLIENT transport type from a remote box. Make sure to provide Windows admin username and password in the config.yaml.
Another way to get around this issue is to avoid using the Bindings mode. Connect using CLIENT transport type from a remote box.
3. Error `Completion Code '2', Reason '2035'`
This could happen for various reasons but for most of the cases, for **Client** mode the user specified in config.yml is not authorized to access the queue manager. Also sometimes even if userid and password are correct, channel auth (CHLAUTH) for that queue manager blocks traffics from other ips, you need to contact admin to provide you access to the queue manager.
Expand All @@ -518,7 +534,7 @@ Please provide the following in order for us to assist you better.


* \<logger name="com.appdynamics"\>
4. Start the machine agent and please let it run for 10 mins. Then zip and upload all the logs in the directory \<MachineAgent\>/logs/*.
5. Attach the zipped \<MachineAgent\>/conf/* directory here.
6. Attach the zipped \<MachineAgent\>/monitors/ExtensionFolderYouAreHavingIssuesWith directory here.
6. Attach the zipped \<MachineAgent\>/monitors/WMQMonitor directory here.
For any support related questions, you can also contact [email protected].
Expand All @@ -528,10 +544,10 @@ Always feel free to fork and contribute any changes directly via [GitHub](https:
## Version
| Name | Version |
|--------------------------|-------------------------|
|Extension Version |7.0.1 |
|Extension Version |7.0.3 |
|Controller Compatibility |4.2 + |
|IBM MQ Version tested On |7.x, 8.x, 9.x and Windows, Unix, AIX|
|Last Update |12th November, 2018 |
|Last Update |18th December, 2019 |
List of Changes to this extension can be found [here](https://github.com/Appdynamics/websphere-mq-monitoring-extension/blob/master/CHANGELOG.md)
Expand Down
2 changes: 1 addition & 1 deletion pom.xml
Original file line number Diff line number Diff line change
Expand Up @@ -12,7 +12,7 @@
<modelVersion>4.0.0</modelVersion>
<groupId>com.appdynamics.extensions</groupId>
<artifactId>websphere-mq-monitoring-extension</artifactId>
<version>7.0.1</version>
<version>7.0.3</version>
<packaging>jar</packaging>
<name>websphere-mq-monitoring-extension</name>
<url>http://maven.apache.org</url>
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -8,9 +8,13 @@
package com.appdynamics.extensions.webspheremq;

import com.appdynamics.extensions.ABaseMonitor;
import com.appdynamics.extensions.TaskInputArgs;
import com.appdynamics.extensions.TasksExecutionServiceProvider;
import com.appdynamics.extensions.crypto.CryptoUtil;
import com.appdynamics.extensions.util.AssertUtils;
import com.appdynamics.extensions.webspheremq.config.QueueManager;
import com.google.common.base.Strings;
import com.google.common.collect.Maps;
import org.codehaus.jackson.map.ObjectMapper;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
Expand Down Expand Up @@ -46,4 +50,57 @@ protected int getTaskCount() {
AssertUtils.assertNotNull(queueManagers, "The 'queueManagers' section in config.yml is not initialised");
return queueManagers.size();
}

@Override
protected void initializeMoreStuff(Map<String, String> args) {
super.initializeMoreStuff(args);
Map<String, ?> configProperties = this.getContextConfiguration().getConfigYml();
Map<String, String> sslConnection = (Map<String, String>) configProperties.get("sslConnection");

if (sslConnection != null ) {
String encryptionKey = (String) configProperties.get("encryptionKey");
logger.debug("Encryption key from config.yml set for ssl connection is " + encryptionKey);

String trustStorePath = sslConnection.get("trustStorePath");
if (!Strings.isNullOrEmpty(trustStorePath)) {
System.setProperty("javax.net.ssl.trustStore",trustStorePath);
logger.debug("System property set for javax.net.ssl.trustStore is " + trustStorePath);
String trustStorePassword = getPassword(sslConnection.get("trustStorePassword"), sslConnection.get("trustStoreEncryptedPassword"), encryptionKey);
if (!Strings.isNullOrEmpty(trustStorePassword)) {
System.setProperty("javax.net.ssl.trustStorePassword", trustStorePassword);
logger.debug("System property set for javax.net.ssl.trustStorePassword is xxxxx");
}
} else {
logger.debug("trustStorePath is not set in config.yml, ignoring setting trustStorePath as system property");
}

String keyStorePath = sslConnection.get("keyStorePath");
if (!Strings.isNullOrEmpty(keyStorePath)) {
System.setProperty("javax.net.ssl.keyStore", keyStorePath);
logger.debug("System property set for javax.net.ssl.keyStore is " + keyStorePath);
String keyStorePassword = getPassword(sslConnection.get("keyStorePassword"), sslConnection.get("keyStoreEncryptedPassword"), encryptionKey);
if (!Strings.isNullOrEmpty(keyStorePassword)) {
System.setProperty("javax.net.ssl.keyStorePassword",keyStorePassword);
logger.debug("System property set for javax.net.ssl.keyStorePassword is xxxxx");
}
} else {
logger.debug("keyStorePath is not set in config.yml, ignoring setting keyStorePath as system property");
}
} else {
logger.debug("ssl truststore and keystore are not configured in config.yml, if SSL is enabled, pass them as jvm args");
}
}

private String getPassword(String password, String encryptedPassword, String encryptionKey) {
if (!Strings.isNullOrEmpty(password)) {
return password;
}
if (!Strings.isNullOrEmpty(encryptionKey) && !Strings.isNullOrEmpty(encryptedPassword)) {
Map<String, String> cryptoMap = Maps.newHashMap();
cryptoMap.put(TaskInputArgs.ENCRYPTED_PASSWORD, encryptedPassword);
cryptoMap.put(TaskInputArgs.ENCRYPTION_KEY, encryptionKey);
return CryptoUtil.getPassword(cryptoMap);
}
return null;
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -55,27 +55,28 @@ public WMQMonitorTask(TasksExecutionServiceProvider tasksExecutionServiceProvide
}

public void run() {
logger.debug("WMQMonitor thread for queueManager " + queueManager.getName() + " started.");
String queueManagerTobeDisplayed = WMQUtil.getQueueManagerNameFromConfig(queueManager);
logger.debug("WMQMonitor thread for queueManager " + queueManagerTobeDisplayed + " started.");
long startTime = System.currentTimeMillis();
MQQueueManager ibmQueueManager = null;
PCFMessageAgent agent = null;
try {
ibmQueueManager = initMQQueueManager();
if (ibmQueueManager != null) {
logger.debug("MQQueueManager connection initiated for queueManager {} in thread {}", queueManager.getName(), Thread.currentThread().getName());
logger.debug("MQQueueManager connection initiated for queueManager {} in thread {}", queueManagerTobeDisplayed, Thread.currentThread().getName());
heartBeatMetricValue = BigDecimal.ONE;
agent = initPCFMesageAgent(ibmQueueManager);
extractAndReportMetrics(agent);
} else {
logger.error("MQQueueManager connection could not be initiated for queueManager {} in thread {} ", queueManager.getName(), Thread.currentThread().getName());
logger.error("MQQueueManager connection could not be initiated for queueManager {} in thread {} ", queueManagerTobeDisplayed, Thread.currentThread().getName());
}
} catch (Exception e) {
logger.error("Error in run of " + Thread.currentThread().getName(), e);
} finally {
cleanUp(ibmQueueManager, agent);
metricWriteHelper.printMetric(StringUtils.concatMetricPath(monitorContextConfig.getMetricPrefix(), queueManager.getName(), "HeartBeat"), heartBeatMetricValue, "AVG.AVG.IND");
metricWriteHelper.printMetric(StringUtils.concatMetricPath(monitorContextConfig.getMetricPrefix(), queueManagerTobeDisplayed, "HeartBeat"), heartBeatMetricValue, "AVG.AVG.IND");
long endTime = System.currentTimeMillis() - startTime;
logger.debug("WMQMonitor thread for queueManager " + queueManager.getName() + " ended. Time taken = " + endTime + " ms");
logger.debug("WMQMonitor thread for queueManager " + queueManagerTobeDisplayed + " ended. Time taken = " + endTime + " ms");
}
}

Expand Down Expand Up @@ -209,6 +210,7 @@ private void cleanUp(MQQueueManager ibmQueueManager, PCFMessageAgent agent) {
}

public void onTaskComplete() {
logger.info("WebSphereMQ monitor thread completed for queueManager:" + queueManager.getName());
logger.info("WebSphereMQ monitor thread completed for queueManager:" + WMQUtil.getQueueManagerNameFromConfig(queueManager));
}

}
Original file line number Diff line number Diff line change
Expand Up @@ -7,7 +7,9 @@

package com.appdynamics.extensions.webspheremq.common;

import com.appdynamics.extensions.webspheremq.config.QueueManager;
import com.appdynamics.extensions.webspheremq.config.WMQMetricOverride;
import com.google.common.base.Strings;
import com.google.common.collect.Maps;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
Expand Down Expand Up @@ -59,4 +61,12 @@ private static Map<String, WMQMetricOverride> gatherMetricNamesByApplyingInclude
}
return overrideMap;
}

public static String getQueueManagerNameFromConfig(QueueManager queueManager) {
if (!Strings.isNullOrEmpty(queueManager.getDisplayName())) {
return queueManager.getDisplayName();
} else {
return queueManager.getName();
}
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -15,7 +15,8 @@
*
*/
public class QueueManager {


private String displayName;
private String host;
private int port = -1;
private String name;
Expand Down Expand Up @@ -44,6 +45,14 @@ public class QueueManager {

List<String> writeStatsDirectory;

public String getDisplayName() {
return displayName;
}

public void setDisplayName(String displayName) {
this.displayName = displayName;
}

public String getHost() {
return host;
}
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -10,6 +10,7 @@
import com.appdynamics.extensions.MetricWriteHelper;
import com.appdynamics.extensions.conf.MonitorContextConfiguration;
import com.appdynamics.extensions.metrics.Metric;
import com.appdynamics.extensions.webspheremq.common.WMQUtil;
import com.appdynamics.extensions.webspheremq.config.ExcludeFilters;
import com.appdynamics.extensions.webspheremq.config.QueueManager;
import com.appdynamics.extensions.webspheremq.config.WMQMetricOverride;
Expand Down Expand Up @@ -103,7 +104,7 @@ protected void publishMetrics() throws TaskExecutionException {
String metrickey = itr.next();
WMQMetricOverride wmqOverride = getMetricsToReport().get(metrickey);
int metricVal = response[i].getIntParameterValue(wmqOverride.getConstantValue());
Metric metric = createMetric(metrickey, metricVal, wmqOverride, queueManager.getName(), getAtrifact(), channelName, metrickey);
Metric metric = createMetric(queueManager, metrickey, metricVal, wmqOverride, getAtrifact(), channelName, metrickey);
metrics.add(metric);
if ("Status".equals(metrickey)) {
if (metricVal == 3) {
Expand Down Expand Up @@ -133,8 +134,8 @@ protected void publishMetrics() throws TaskExecutionException {
}
}

logger.info("Active Channels in queueManager {} are {}", queueManager.getName(), activeChannels);
Metric activeChannelsCountMetric = createMetric("ActiveChannelsCount", activeChannels.size(), null, queueManager.getName(), getAtrifact(), "ActiveChannelsCount");
logger.info("Active Channels in queueManager {} are {}", WMQUtil.getQueueManagerNameFromConfig(queueManager), activeChannels);
Metric activeChannelsCountMetric = createMetric(queueManager,"ActiveChannelsCount", activeChannels.size(), null, getAtrifact(), "ActiveChannelsCount");
publishMetrics(Arrays.asList(activeChannelsCountMetric));

long exitTime = System.currentTimeMillis() - entryTime;
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -86,7 +86,7 @@ protected void publishMetrics() throws TaskExecutionException {
String metrickey = itr.next();
WMQMetricOverride wmqOverride = getMetricsToReport().get(metrickey);
int metricVal = response[i].getIntParameterValue(wmqOverride.getConstantValue());
Metric metric = createMetric(metrickey, metricVal, wmqOverride, queueManager.getName(), getAtrifact(), listenerName, metrickey);
Metric metric = createMetric(queueManager, metrickey, metricVal, wmqOverride, getAtrifact(), listenerName, metrickey);
metrics.add(metric);
}
publishMetrics(metrics);
Expand Down
Loading

0 comments on commit 62072ba

Please sign in to comment.