/******************************************************************************* * =========================================================== * 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.deployer; import java.io.File; import java.io.FileInputStream; import java.io.IOException; import java.io.InputStream; import java.io.StringReader; import java.util.ArrayList; import java.util.Arrays; import java.util.HashMap; import java.util.HashSet; import java.util.LinkedHashMap; import java.util.List; import java.util.Map; import java.util.Properties; import java.util.Set; import javax.management.MBeanServerConnection; import javax.management.ObjectName; import org.jdom.Element; import org.jdom.input.SAXBuilder; import org.yaml.snakeyaml.Yaml; import com.impetus.ankush.common.exception.AnkushException; import com.impetus.ankush.common.utils.FileNameUtils; import com.impetus.ankush.common.utils.JmxUtil; import com.impetus.ankush2.cassandra.utils.CassandraConstants; import com.impetus.ankush2.cassandra.utils.CassandraUtils; import com.impetus.ankush2.constant.Constant; import com.impetus.ankush2.framework.config.ClusterConfig; import com.impetus.ankush2.framework.config.ComponentConfig; import com.impetus.ankush2.logger.AnkushLogger; import com.impetus.ankush2.utils.AnkushUtils; import com.impetus.ankush2.utils.HostOperation; import com.impetus.ankush2.utils.SSHUtils; public class CassandraRegister { private AnkushLogger logger; private ClusterConfig clusterConfig; private ComponentConfig compConfig; /** The Constant ORG_APACHE_CASSANDRA. */ private static final String ORG_APACHE_CASSANDRA = "org.apache.cassandra."; /** The Constant CASSANDRA_JMX_OBJECT_STORAGESERVICE. */ private static final String CASSANDRA_JMX_OBJECT_STORAGESERVICE = "StorageService"; /** The Constant CASSANDRA_JMX_OBJECT_ENDPOINTSNITCHINFO. */ private static final String CASSANDRA_JMX_OBJECT_ENDPOINTSNITCHINFO = "EndpointSnitchInfo"; /** The Constant CASSANDRA_JMX_OBJECT_GETRACK. */ private static final String CASSANDRA_JMX_OBJECT_GETRACK = "getRack"; /** The Constant CASSANDRA_JMX_OBJECT_GETDATACENTER. */ private static final String CASSANDRA_JMX_OBJECT_GETDATACENTER = "getDatacenter"; /** The Constant CASSANDRA_JMX_ATTRIBUTE_LIVE_NODES. */ private static final String CASSANDRA_JMX_ATTRIBUTE_LIVE_NODES = "LiveNodes"; /** The Constant CASSANDRA_JMX_ATTRIBUTE_UNREACHABLE_NODES. */ private static final String CASSANDRA_JMX_ATTRIBUTE_UNREACHABLE_NODES = "UnreachableNodes"; /** The Constant CASSANDRA_FOLDER_CONF. */ private static final String CASSANDRA_FOLDER_CONF = "conf/"; public CassandraRegister(ClusterConfig clusterConfig) { this.clusterConfig = clusterConfig; this.logger = new AnkushLogger(this.getClass(), this.clusterConfig); this.compConfig = clusterConfig.getComponents().get( Constant.Component.Name.CASSANDRA); } public boolean createConfig() throws AnkushException { JmxUtil jmxUtil = null; Map<String, Map<String, Object>> nodes = null; Map<String, Object> nodeProperties = null; Map<String, Set<String>> nodeRoles = null; // Node set containing hostname of nodes in a cluster List<String> nodeList = null; try { // node hostname provided from UI for Cassandra Cluster registration final String registeredNodeIp = compConfig.getNodes().keySet() .iterator().next(); // creating an advanceConf Object Map<String, Object> advanceConf = compConfig.getAdvanceConf(); // JMX port to be used for making JMX connection Integer jmxPort = (Integer) advanceConf .get(CassandraConstants.ClusterProperties.JMX_PORT); // Making JMX connection jmxUtil = new JmxUtil(registeredNodeIp, jmxPort); MBeanServerConnection connection = jmxUtil.connect(); // error message String errorMsg = "Unable to access JMX credentials " + registeredNodeIp + ":" + jmxPort; // cassandra.yaml file location on node final String cassandraYamlLocation = FileNameUtils .convertToValidPath(compConfig.getHomeDir()) + CASSANDRA_FOLDER_CONF + CassandraConstants.Cassandra_Configuration_Files.CASSANDRA_YAML; // log4j-server.properties file location on node String cassandraLog4jLocation = FileNameUtils .convertToValidPath(compConfig.getHomeDir()) + CASSANDRA_FOLDER_CONF + CassandraConstants.Cassandra_Configuration_Files.CASSANDRA_LOG4J_SERVER_PROPERTIES; // TODO: Handle version check for logging configuration if (compConfig.getVersion().contains("2.1.")) { cassandraLog4jLocation = FileNameUtils .convertToValidPath(compConfig.getHomeDir()) + CASSANDRA_FOLDER_CONF + CassandraConstants.Cassandra_Configuration_Files.CASSANDRA_LOGBACK_XML; } Set<String> errMessages = new HashSet<String>(); if (connection != null) { // JMX Object for getting cluster nodes information ObjectName mObjNameStorageService = new ObjectName( ORG_APACHE_CASSANDRA + "db:type=" + CASSANDRA_JMX_OBJECT_STORAGESERVICE); // JMX Object for getting Datacenter and Rack information for // nodes ObjectName mObjNameEndpointSnitchInfo = new ObjectName( ORG_APACHE_CASSANDRA + "db:type=" + CASSANDRA_JMX_OBJECT_ENDPOINTSNITCHINFO); // JMX attribute for getting live nodes in a cluster Object attributeLiveNodes = jmxUtil.getAttribute( mObjNameStorageService, CASSANDRA_JMX_ATTRIBUTE_LIVE_NODES); // JMX attribute for getting down nodes in a cluster Object attributeUnreachableNodes = jmxUtil.getAttribute( mObjNameStorageService, CASSANDRA_JMX_ATTRIBUTE_UNREACHABLE_NODES); // Adding cluster nodes in node list nodeList = new ArrayList<String>(); nodeList.addAll((List<String>) attributeLiveNodes); nodeList.addAll((List<String>) attributeUnreachableNodes); // Getting file content of cassandra.yaml file String cassandraYamlFileContent = SSHUtils.getFileContents( cassandraYamlLocation, registeredNodeIp, clusterConfig.getAuthConf()); // Loading the yaml file content in map Map map = (Map) (new Yaml()).load(cassandraYamlFileContent); // Getting seed node string from map String seednodeStr = ((String) ((LinkedHashMap) ((ArrayList) ((LinkedHashMap) ((ArrayList) map .get("seed_provider")).get(0)).get("parameters")) .get(0)).get("seeds")); // Extracting the nodes from seednodeStr and adding them to seed // node list List<String> seeds = Arrays.asList(seednodeStr .split("\\s*,\\s*")); // Initializing nodes object nodes = new HashMap<String, Map<String, Object>>(); String opSig[] = { String.class.getName() }; // Datacenter and Rack name object Object datacenter = null; Object rack = null; boolean isSeedNode; String role = CassandraConstants.Node_Type.CASSANDRA_NON_SEED; String hostname = new String(); for (String node : nodeList) { hostname = HostOperation.getMachineHostName(node, clusterConfig.getAuthConf().getUsername(), clusterConfig.getAuthConf().getPassword(), clusterConfig.getAuthConf().getPrivateKey()); // preparing a new node properties for each node nodeProperties = new HashMap<String, Object>(); isSeedNode = false; // If seednode list contains the node , then setting its // type to seednode if (seeds.contains(hostname)) { isSeedNode = true; role = CassandraConstants.Node_Type.CASSANDRA_SEED; } // TODO: nodeProperties in seednode to handle // TODO: preparing role set and adding it to nodeconfig nodeProperties.put( CassandraConstants.NodeProperties.CASSANDRA_SEED, isSeedNode); // TODO: Adding vNodeCount to nodeProperties // Adding node with nodeProperties to node map nodes.put(hostname, nodeProperties); // Parameters to be used for invoking an operation Object opParams[] = { hostname }; // Getting Datacenter name from JMX object datacenter = connection .invoke(mObjNameEndpointSnitchInfo, CASSANDRA_JMX_OBJECT_GETDATACENTER, opParams, opSig); // Getting Rack name from JMX object rack = connection.invoke(mObjNameEndpointSnitchInfo, CASSANDRA_JMX_OBJECT_GETRACK, opParams, opSig); nodeRoles = new HashMap<String, Set<String>>(); nodeRoles.put(Constant.Component.Name.CASSANDRA, new HashSet<String>(Arrays.asList(role))); // Adding nodes to cluster nodes // skip Registration in Level1 if (!AnkushUtils.isMonitoredByAnkush(compConfig)) { AnkushUtils.addNodeToComponentConfig(clusterConfig, Constant.Component.Name.CASSANDRA, hostname, new HashMap()); } else { AnkushUtils.addNodeToClusterAndComponent(clusterConfig, hostname, new HashSet<String>(Arrays.asList(role)), Constant.Component.Name.CASSANDRA); } } // Setting component level properties // Getting a truncated home path. The path is truncated to get // the child location for setting installation path String truncatedCompHome = CassandraUtils .getTruncatedPath(compConfig.getHomeDir()); compConfig.setNodes(nodes); advanceConf.put( CassandraConstants.ClusterProperties.CLUSTER_NAME, (String) map.get("cluster_name")); advanceConf.put( CassandraConstants.ClusterProperties.PARTITIONER, (String) map.get("partitioner")); advanceConf.put(CassandraConstants.ClusterProperties.SNITCH, (String) map.get("endpoint_snitch")); advanceConf.put( CassandraConstants.ClusterProperties.SAVED_CACHES_DIR, (String) map.get("saved_caches_directory")); advanceConf.put(CassandraConstants.ClusterProperties.DATA_DIR, String.valueOf(((ArrayList) map .get("data_file_directories")).get(0))); advanceConf.put( CassandraConstants.ClusterProperties.COMMIT_LOG_DIR, (String) map.get("commitlog_directory")); advanceConf.put(CassandraConstants.ClusterProperties.RPC_PORT, String.valueOf(map.get("rpc_port"))); advanceConf.put( CassandraConstants.ClusterProperties.STORAGE_PORT, String.valueOf(map.get("storage_port"))); advanceConf.put( CassandraConstants.ClusterProperties.LOG_DIR, getCassandraLogDir(cassandraLog4jLocation, registeredNodeIp)); // TODO: Setting install path in component conf. Need to verify // whether its needed or not. compConfig.setInstallPath(truncatedCompHome.substring(0, truncatedCompHome.lastIndexOf("/"))); } else { errMessages.add(errorMsg); logger.error(errorMsg, Constant.Component.Name.CASSANDRA); } if (errMessages.size() > 0) { clusterConfig.getErrors().put( Constant.Component.Name.CASSANDRA, errMessages); } } catch (Exception e) { throw new AnkushException( "Could not create Cassandra configuration for cluster registration"); } finally { jmxUtil.disconnect(); } return true; } private String getCassandraLogDir(String cassandraLog4jLocation, String registeredNodeIp) { String logFile = null; try { // TODO: Handle version check for getting Cassandra Log dir if (compConfig.getVersion().contains("2.1.")) { logFile = getLogFileName(cassandraLog4jLocation, "appender"); } else { // Getting log4jServer.properties file content for getting log // directory location String log4jfileContent = SSHUtils.getFileContents( cassandraLog4jLocation, registeredNodeIp, clusterConfig.getAuthConf()); // Converting string into Properties. Properties properties = new Properties(); properties.load(new StringReader(log4jfileContent)); logFile = properties.getProperty("log4j.appender.R.File"); } return logFile.substring(0, logFile.lastIndexOf("/")); } catch (IOException e) { logger.error(e.getMessage()); } catch (Exception e) { logger.error(e.getMessage()); } return null; } public static String getLogFileName(String filePath, String root) { try { // creating sax builder obj. SAXBuilder builder = new SAXBuilder(); // getting file object. File xml = new File(filePath); // input file stream. InputStream inputStream = new FileInputStream(xml); // jdom document object. org.jdom.Document doc = builder.build(inputStream); // getting root element. Element elements = doc.getRootElement(); System.out.println("elements: " + elements); // getting child elements. List child = elements.getChildren(root); // iterating over the childs. for (int index = 0; index < child.size(); index++) { // getting element. Element e = (Element) child.get(index); System.out.println("e: " + e); String appenderName = e.getAttributeValue("name"); System.out.println("appenderName: " + appenderName); if (appenderName.equalsIgnoreCase("FILE")) { Element fileChild = (Element) e.getChild("file"); System.out.println("fileChild: " + fileChild); String fileName = fileChild.getValue(); System.out.println("fileName: " + fileName); return fileName; } } // closing input stream. inputStream.close(); } catch (Exception e) { // printing stack trace. e.printStackTrace(); } // returning items. return null; } }