/*******************************************************************************
* ===========================================================
* Ankush : Big Data Cluster Management Solution
* ===========================================================
*
* (C) Copyright 2014, by Impetus Technologies
*
* This is free software; you can redistribute it and/or modify it under
* the terms of the GNU Lesser General Public License (LGPL v3) as
* published by the Free Software Foundation;
*
* This software is distributed in the hope that it will be useful, but
* WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.
* See the GNU Lesser General Public License for more details.
*
* You should have received a copy of the GNU Lesser General Public License
* along with this software; if not, write to the Free Software Foundation,
* Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
******************************************************************************/
package com.impetus.ankush2.cassandra.monitor;
import java.text.DecimalFormat;
import java.util.ArrayList;
import java.util.Arrays;
import java.util.HashMap;
import java.util.LinkedHashMap;
import java.util.List;
import java.util.Map;
import javax.management.MBeanServerConnection;
import javax.management.MalformedObjectNameException;
import javax.management.ObjectName;
import com.impetus.ankush.common.exception.AnkushException;
import com.impetus.ankush.common.utils.JmxUtil;
import com.impetus.ankush2.cassandra.utils.CassandraConstants;
import com.impetus.ankush2.logger.AnkushLogger;
public class CassandraJMX {
/** The logger. */
private static AnkushLogger LOG = new AnkushLogger(CassandraJMX.class);
private static DecimalFormat df = new DecimalFormat("###.##");
private JmxUtil jmxUtil;
private MBeanServerConnection connection;
public CassandraJMX(String hostname, int jmxPort) throws Exception {
jmxUtil = new JmxUtil(hostname, jmxPort);
// connect to node
connection = jmxUtil.connect();
if (connection == null) {
throw new AnkushException("Could not create JMX connection.");
}
}
private List<String> getKeyspaces() {
ObjectName mObjNameStorageService;
try {
mObjNameStorageService = new ObjectName(
CassandraConstants.ORG_APACHE_CASSANDRA
+ "db:type="
+ CassandraConstants.Cassandra_JMX_Attributes.CASSANDRA_JMX_OBJECT_STORAGESERVICE);
Object attrKeyspace = jmxUtil
.getAttribute(
mObjNameStorageService,
CassandraConstants.Cassandra_JMX_Attributes.CASSANDRA_JMX_ATTRIBUTE_KEYSPACES);
return (List<String>) attrKeyspace;
} catch (MalformedObjectNameException e) {
LOG.error("Could not fetch keyspaces.", e);
}
return null;
}
private Map<String, String> getOwnershipMap() {
Map<String, String> ownershipMap = null;
try {
ObjectName mObjNameStorageService = new ObjectName(
CassandraConstants.ORG_APACHE_CASSANDRA
+ "db:type="
+ CassandraConstants.Cassandra_JMX_Attributes.CASSANDRA_JMX_OBJECT_STORAGESERVICE);
Object attrOwnership = jmxUtil
.getAttribute(
mObjNameStorageService,
CassandraConstants.Cassandra_JMX_Attributes.CASSANDRA_JMX_ATTRIBUTE_OWNERSHIP);
LinkedHashMap ownership = (LinkedHashMap) attrOwnership;
ownershipMap = new HashMap<String, String>();
for (Object key : ownership.keySet()) {
ownershipMap
.put(key.toString().substring(
key.toString().lastIndexOf("/") + 1),
String.valueOf(df.format(((Float) ownership
.get(key)) * 100)) + " %");
}
} catch (MalformedObjectNameException e) {
LOG.error("Could not get ownership details.", e);
}
return ownershipMap;
}
private Map<String, String> getLoadMap() {
Map<String, String> loadMap = null;
ObjectName mObjNameStorageService;
try {
mObjNameStorageService = new ObjectName(
CassandraConstants.ORG_APACHE_CASSANDRA
+ "db:type="
+ CassandraConstants.Cassandra_JMX_Attributes.CASSANDRA_JMX_OBJECT_STORAGESERVICE);
// Getting load
Object attrLoadMap = jmxUtil
.getAttribute(
mObjNameStorageService,
CassandraConstants.Cassandra_JMX_Attributes.CASSANDRA_JMX_ATTRIBUTE_LOADMAP);
Map<String, String> load = (HashMap<String, String>) attrLoadMap;
loadMap = new HashMap<String, String>();
for (Map.Entry<String, String> entry : load.entrySet()) {
loadMap.put(entry.getKey().trim(), entry.getValue().trim());
}
} catch (MalformedObjectNameException e) {
LOG.error("Could not get load details.", e);
}
return loadMap;
}
private Map<String, String> getHostIdMap() {
Map<String, String> hostIdMap = null;
try {
ObjectName mObjNameStorageService = new ObjectName(
CassandraConstants.ORG_APACHE_CASSANDRA
+ "db:type="
+ CassandraConstants.Cassandra_JMX_Attributes.CASSANDRA_JMX_OBJECT_STORAGESERVICE);
Object attrHostIdMap = jmxUtil
.getAttribute(
mObjNameStorageService,
CassandraConstants.Cassandra_JMX_Attributes.CASSANDRA_JMX_ATTRIBUTE_HOSTIDMAP);
Map<String, String> hostId = (HashMap<String, String>) attrHostIdMap;
hostIdMap = new HashMap<String, String>();
for (Map.Entry<String, String> entry : hostId.entrySet()) {
hostIdMap.put(entry.getKey().trim(), entry.getValue().trim());
}
} catch (MalformedObjectNameException e) {
LOG.error("Could not get host Id details.", e);
}
return hostIdMap;
}
private Map<String, String> getStateMap() {
Map<String, String> stateMap = null;
try {
ObjectName mObjNameFailureDetector = new ObjectName(
CassandraConstants.ORG_APACHE_CASSANDRA
+ "net:type="
+ CassandraConstants.Cassandra_JMX_Attributes.CASSANDRA_JMX_OBJECT_FAILUREDETECTOR);
// Getting status
Object attrStatus = jmxUtil
.getAttribute(
mObjNameFailureDetector,
CassandraConstants.Cassandra_JMX_Attributes.CASSANDRA_JMX_ATTRIBUTE_SIMPLESTATES);
Map<String, String> status = (Map) attrStatus;
;
stateMap = new HashMap<String, String>();
for (Map.Entry<String, String> entry : status.entrySet()) {
stateMap.put(
entry.getKey().substring(
entry.getKey().lastIndexOf("/") + 1),
entry.getValue());
}
} catch (MalformedObjectNameException e) {
LOG.error("Could not get host Id details.", e);
}
return stateMap;
}
// TODO: Can be eliminated using keys retrun from above functions.
private List<String> getNodeList() {
List<String> nodes = null;
try {
ObjectName mObjNameStorageService = new ObjectName(
CassandraConstants.ORG_APACHE_CASSANDRA
+ "db:type="
+ CassandraConstants.Cassandra_JMX_Attributes.CASSANDRA_JMX_OBJECT_STORAGESERVICE);
Object attributeLiveNodes = jmxUtil
.getAttribute(
mObjNameStorageService,
CassandraConstants.Cassandra_JMX_Attributes.CASSANDRA_JMX_ATTRIBUTE_LIVE_NODES);
Object attributeUnreachableNodes = jmxUtil
.getAttribute(
mObjNameStorageService,
CassandraConstants.Cassandra_JMX_Attributes.CASSANDRA_JMX_ATTRIBUTE_UNREACHABLE_NODES);
nodes = new ArrayList<String>();
nodes.addAll((List<String>) attributeLiveNodes);
nodes.addAll((List<String>) attributeUnreachableNodes);
} catch (MalformedObjectNameException e) {
LOG.error("Could not get node list.", e);
}
return nodes;
}
public List<CassandraNode> getCassandraNodeList() {
List<CassandraNode> nodeList = null;
Map<String, String> ownershipMap = getOwnershipMap();
Map<String, String> loadMap = getLoadMap();
Map<String, String> hostIdMap = getHostIdMap();
Map<String, String> stateMap = getStateMap();
List<String> nodes = getNodeList();
if (ownershipMap == null || loadMap == null || hostIdMap == null
|| stateMap == null || nodes == null) {
LOG.error("Missing details.");
return null;
}
try {
ObjectName mObjNameStorageService = new ObjectName(
CassandraConstants.ORG_APACHE_CASSANDRA
+ "db:type="
+ CassandraConstants.Cassandra_JMX_Attributes.CASSANDRA_JMX_OBJECT_STORAGESERVICE);
ObjectName mObjNameEndPointSnitchInfo = new ObjectName(
CassandraConstants.ORG_APACHE_CASSANDRA
+ "db:type="
+ CassandraConstants.Cassandra_JMX_Attributes.CASSANDRA_JMX_OBJECT_ENDPOINT_SNITCH_INFO);
ObjectName mObjNameFailureDetector = new ObjectName(
CassandraConstants.ORG_APACHE_CASSANDRA
+ "net:type="
+ CassandraConstants.Cassandra_JMX_Attributes.CASSANDRA_JMX_OBJECT_FAILUREDETECTOR);
nodeList = new ArrayList<CassandraNode>();
// getting topology information
for (String cNodeConf : nodes) {
Object opParams[] = { cNodeConf };
String opSig[] = { String.class.getName() };
CassandraNode node = new CassandraNode();
Object result = connection
.invoke(mObjNameEndPointSnitchInfo,
CassandraConstants.JMX_Operations.CASSANDRA_JMX_ATTRIBUTE_GETRACK,
opParams, opSig);
node.setRack((String) result);
result = connection
.invoke(mObjNameEndPointSnitchInfo,
CassandraConstants.JMX_Operations.CASSANDRA_JMX_ATTRIBUTE_GETDATACENTER,
opParams, opSig);
node.setDataCenter((String) result);
node.setHost(cNodeConf);
node.setOwnership(ownershipMap.get(cNodeConf));
node.setLoad((loadMap.get(cNodeConf) != null
&& !loadMap.get(cNodeConf).isEmpty() ? loadMap
.get(cNodeConf) : "?"));
node.setStatus(stateMap.get(cNodeConf));
node.setHostId(hostIdMap.get(cNodeConf));
result = connection
.invoke(mObjNameFailureDetector,
CassandraConstants.JMX_Operations.CASSANDRA_JMX_ATTRIBUTE_ENDPOINTSTATE,
opParams, opSig);
String strResult = (String) result;
List<String> sysoutList = new ArrayList<String>(
Arrays.asList(strResult.split("\n")));
for (String outData : sysoutList) {
List<String> paramList = new ArrayList<String>(
Arrays.asList(outData.split(":")));
String key = paramList.get(0).trim();
if (key.equals("STATUS")) {
node.setState((!paramList.get(1).trim().split(",")[0]
.isEmpty() ? paramList.get(1).trim().split(",")[0]
: "?"));
break;
}
}
// Getting tokens
result = connection
.invoke(mObjNameStorageService,
CassandraConstants.JMX_Operations.CASSANDRA_JMX_ATTRIBUTE_TOKENS,
opParams, opSig);
List<String> tokens = (List<String>) result;
node.setTokenCount(String.valueOf(tokens.size()));
nodeList.add(node);
}
} catch (Exception e) {
LOG.error("Could not get Cassandra node list.", e);
nodeList = null;
}
return nodeList;
}
@Override
protected void finalize() throws Throwable {
if (jmxUtil != null) {
jmxUtil.disconnect();
}
super.finalize();
}
}