/*******************************************************************************
* ===========================================================
* 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.zookeeper;
import java.util.ArrayList;
import java.util.List;
import java.util.Map;
import net.neoremind.sshxcute.core.Result;
import net.neoremind.sshxcute.core.SSHExec;
import com.impetus.ankush.common.exception.AnkushException;
import com.impetus.ankush.common.scripting.AnkushTask;
import com.impetus.ankush.common.scripting.impl.AppendFileUsingEcho;
import com.impetus.ankush.common.scripting.impl.MakeDirectory;
import com.impetus.ankush.common.scripting.impl.Remove;
import com.impetus.ankush.common.utils.JmxMonitoringUtil;
import com.impetus.ankush2.agent.AgentUtils;
import com.impetus.ankush2.agent.ComponentService;
import com.impetus.ankush2.constant.Constant;
import com.impetus.ankush2.constant.Constant.Component;
import com.impetus.ankush2.framework.config.ClusterConfig;
import com.impetus.ankush2.framework.config.ComponentConfig;
import com.impetus.ankush2.framework.config.NodeConfig;
import com.impetus.ankush2.logger.AnkushLogger;
import com.impetus.ankush2.utils.SSHUtils;
/**
* The Class ZookeeperWorker.
*/
public class ZookeeperWorker {
/** The logger. */
private final AnkushLogger logger = new AnkushLogger(ZookeeperWorker.class);
/** The cluster config. */
private ClusterConfig clusterConfig;
/** The node config. */
private NodeConfig nodeConfig;
/** The conf. */
private ComponentConfig conf;
/** The node advance conf. */
private Map<String, Object> nodeAdvanceConf;
/** The component name. */
private String componentName;
/**
* Sets the cluster and logger.
*
* @param clusterConfig
* the cluster config
* @param componentName
* the component name
* @param nodeConfig
* the node config
*/
private void setClusterAndLogger(ClusterConfig clusterConfig,
String componentName, NodeConfig nodeConfig) {
this.clusterConfig = clusterConfig;
this.conf = clusterConfig.getComponents().get(componentName);
this.componentName = componentName;
this.nodeConfig = nodeConfig;
logger.setCluster(clusterConfig);
}
/**
* Instantiates a new zookeeper worker.
*
* @param clusterConf
* the cluster conf
* @param componentName
* the component name
* @param nodeConfig
* the node config
* @param nodeAdvanceConf
* the node advance conf
*/
public ZookeeperWorker(ClusterConfig clusterConf, String componentName,
NodeConfig nodeConfig, Map<String, Object> nodeAdvanceConf) {
this.setClusterAndLogger(clusterConf, componentName, nodeConfig);
this.nodeAdvanceConf = nodeAdvanceConf;
}
/**
* Instantiates a new zookeeper worker.
*
* @param clusterConf
* the cluster conf
* @param componentName
* the component name
* @param nodeConfig
* the node config
*/
public ZookeeperWorker(ClusterConfig clusterConf, String componentName,
NodeConfig nodeConfig) {
this.setClusterAndLogger(clusterConf, componentName, nodeConfig);
}
/**
* Creates the node.
*
* @return true, if successful
*/
public boolean createNode() {
logger.info("Starting Zookeeper Worker thread..", nodeConfig.getHost(),
this.componentName);
SSHExec connection = null;
Result res = null;
try {
// connect to remote node
connection = this.nodeConfig.getConnection();
// if connected
if (connection != null) {
logger.info("Create directory - " + this.conf.getInstallPath(),
this.componentName, this.nodeConfig.getPublicHost());
// make installation directory if not exists
AnkushTask mkInstallationPath = new MakeDirectory(
this.conf.getInstallPath());
res = connection.exec(mkInstallationPath);
if (!res.isSuccess) {
// logger.error("Could not create installation directory",
// this.componentName, this.nodeConfig.getPublicHost());
// return false;
throw new AnkushException(
"Could not create installation directory");
}
logger.info("Get and extract tarball", this.componentName,
this.nodeConfig.getPublicHost());
// get and extract tarball
boolean isSuccessfull = SSHUtils.getAndExtractComponent(
connection, this.conf,
Constant.Component.Name.ZOOKEEPER);
if (!isSuccessfull) {
throw new AnkushException(
"Could not extract bundle for Zookeeper");
}
// make data directory
AnkushTask makeDataDir = new MakeDirectory((String) this.conf
.getAdvanceConf().get(
ZookeeperConstant.Keys.DATA_DIRECTORY));
// create zoo.cfg file
AnkushTask createZooCfg = new AppendFileUsingEcho(
getZooConfContents(), this.conf.getHomeDir()
+ "/conf/zoo.cfg");
// create myid file
AnkushTask createMyId = new AppendFileUsingEcho(
String.valueOf(this.nodeAdvanceConf
.get(ZookeeperConstant.Keys.NODE_ID)),
this.conf.getAdvanceConf().get(
ZookeeperConstant.Keys.DATA_DIRECTORY)
+ "myid");
logger.info("Creating zookeeper's data directory...",
this.componentName, this.nodeConfig.getPublicHost());
if (!connection.exec(makeDataDir).isSuccess) {
throw new AnkushException(
"Couldn't create zookeeper's data directory");
}
logger.info("Creating zoo.cfg file...", this.componentName,
this.nodeConfig.getPublicHost());
if (!connection.exec(createZooCfg).isSuccess) {
throw new AnkushException("Couldn't create zoo.cfg file");
}
logger.info("Creating myid file...", this.componentName,
this.nodeConfig.getPublicHost());
if (!connection.exec(createMyId).isSuccess) {
throw new AnkushException("Couldn't create myid file");
}
logger.info("Configuring JMX monitoring for Zookeeper... ",
this.componentName, this.nodeConfig.getPublicHost());
if (!configureJMXMonitoring()) {
throw new AnkushException(
"Couldn't configure JMX monitoring for Zookeeper.");
}
if (!configure()) {
throw new AnkushException("Couldn't configure Zookeeper.");
}
logger.info("Zookeeper worker thread execution over ... ",
this.componentName, this.nodeConfig.getPublicHost());
return true;
} else {
throw new AnkushException(
Constant.Strings.ExceptionsMessage.CONNECTION_NULL_STRING);
}
} catch (AnkushException e) {
logger.error(e.getMessage(), componentName, nodeConfig.getHost(), e);
this.clusterConfig.addError(this.nodeConfig.getHost(),
componentName, e.getMessage());
} catch (Exception e) {
logger.error(e.getMessage(), componentName, nodeConfig.getHost(), e);
this.clusterConfig.addError(this.nodeConfig.getHost(),
componentName, e.getMessage());
}
return false;
}
/**
* Gets the zoo conf contents.
*
* @return the zoo conf contents
*/
public String getZooConfContents() {
// Building first part of zoo.cfg file
StringBuilder partOneBuilder = new StringBuilder();
String dataDir = (String) this.conf.getAdvanceConf().get(
ZookeeperConstant.Keys.DATA_DIRECTORY);
if ((dataDir != null) && (dataDir.endsWith("/"))) {
dataDir = dataDir.substring(0, dataDir.length() - 1);
}
partOneBuilder
.append("dataDir=")
.append(dataDir)
.append("\n")
.append("clientPort=")
.append(""
+ this.conf.getAdvanceConf().get(
ZookeeperConstant.Keys.CLIENT_PORT))
.append("\n")
.append("tickTime=")
.append(""
+ this.conf.getAdvanceConf().get(
ZookeeperConstant.Keys.TICK_TIME))
.append("\n")
.append("initLimit=")
.append(""
+ this.conf.getAdvanceConf().get(
ZookeeperConstant.Keys.INIT_LIMIT))
.append("\n")
.append("syncLimit=")
.append(""
+ this.conf.getAdvanceConf().get(
ZookeeperConstant.Keys.SYNC_LIMIT))
.append("\n");
// Building second part of zoo.cfg file
StringBuilder partTwoBuilder = new StringBuilder();
for (String host : this.conf.getNodes().keySet()) {
partTwoBuilder
.append("server.")
.append(this.conf.getNodes().get(host)
.get(ZookeeperConstant.Keys.NODE_ID)).append("=")
.append(host).append(":2888:3888").append("\n");
}
// merging both buffers
StringBuilder zooConfContent = partOneBuilder.append(partTwoBuilder);
return zooConfContent.toString();
}
/**
* Configure jmx monitoring.
*
* @return true, if successful
*/
private boolean configureJMXMonitoring() {
logger.info("Configuring JMX Monitoring for Zookeeper started ... ",
this.componentName, this.nodeConfig.getPublicHost());
boolean status = true;
String componentHome = conf.getHomeDir();
String zkServer_FilePath = componentHome
+ ZookeeperConstant.Keys.relPath_ZkServerScript;
status = JmxMonitoringUtil
.configureJmxPort(
Constant.Process.QUORUMPEERMAIN,
this.nodeConfig.getConnection(),
zkServer_FilePath,
this.conf
.getAdvanceConfIntegerProperty(ZookeeperConstant.Keys.JMX_PORT),
this.clusterConfig.getAuthConf().getPassword());
if (!status) {
logger.error("Could not update " + zkServer_FilePath + " file.",
this.componentName, this.nodeConfig.getPublicHost());
return false;
}
return true;
}
/**
* Configure.
*
* @return true, if successful
*/
private boolean configure() {
boolean statusFlag = false;
logger.info("Creating zookeeper service configuration in agent...",
this.componentName, this.nodeConfig.getPublicHost());
// Create ZOOKEEPER Service XML configuration in agent.
// Component service list
List<ComponentService> services = new ArrayList<ComponentService>();
// adding ZOOKEEPER service entry.
services.add(new ComponentService(Constant.Process.QUORUMPEERMAIN,
Constant.Role.ZOOKEEPER, Constant.ServiceType.JPS));
// Creating ZOOKEEPER service XML.
statusFlag = AgentUtils.createServiceXML(
this.nodeConfig.getConnection(), services, this.componentName,
this.clusterConfig.getAgentHomeDir());
// add warning if failed
if (!statusFlag) {
logger.warn(
"Could not create zookeeper service configuration in agent.",
this.componentName, this.nodeConfig.getPublicHost());
}
logger.info("Copying JmxTrans JSON file to Zookeeper...",
this.componentName, this.nodeConfig.getPublicHost());
// Configuring JMX Monitoring using JMX-Trans
statusFlag = JmxMonitoringUtil
.copyJmxTransJson(
this.nodeConfig.getConnection(),
this.clusterConfig.getAuthConf(),
Component.Name.ZOOKEEPER,
Constant.Process.QUORUMPEERMAIN,
conf.getAdvanceConfIntegerProperty(ZookeeperConstant.Keys.JMX_PORT),
clusterConfig.getAgentHomeDir());
if (!statusFlag) {
logger.warn("Could not copy JmxTrans JSON file for Zookeeper.",
this.componentName, this.nodeConfig.getPublicHost());
}
return statusFlag;
}
/**
* Action.
*
* @param action
* the action
* @return true, if successful
*/
// public boolean action(final String action) {
//
// SSHExec connection = null;
// try {
// File commandExecLogsFilePath = new File(
// AgentUtils.getAgentLogDirectoryPath(clusterConfig)
// + ZookeeperConstant.Keys.ZOOKEEPER_COMMAND_EXECUTION_LOG_PATH
// + ".log");
// connection = this.nodeConfig.getConnection();
// // if connected
// if (connection != null) {
// String cmd = this.conf.getHomeDir() + "bin/zkServer.sh"
// + Strings.SPACE + action;
// Result result;
// AnkushTask zooActionCommand = new AnkushTask() {
//
// @Override
// public String getCommand() {
// return conf.getHomeDir() + "bin/zkServer.sh"
// + Strings.SPACE + action;
// }
// };
// // new RunInBackground(cmd,
// // commandExecLogsFilePath.getAbsolutePath());
// result = connection.exec(zooActionCommand);
// if (result.rc != 0) {
// throw new AnkushException(result.error_msg);
// } else {
// System.out.println("result.sysout : " + result.sysout);
// if (result.sysout
// .contains("Starting zookeeper ... already running")) {
// throw new AnkushException(result.sysout);
// }
// return true;
// }
// } else {
// throw new AnkushException(
// Constant.Strings.ExceptionsMessage.CONNECTION_NULL_STRING);
// }
// } catch (AnkushException e) {
// logger.error(e.getMessage(), componentName, nodeConfig.getHost(), e);
// this.clusterConfig.addError(this.nodeConfig.getHost(),
// componentName, e.getMessage());
// } catch (Exception e) {
// logger.error(e.getMessage(), componentName, nodeConfig.getHost(), e);
// this.clusterConfig.addError(this.nodeConfig.getHost(),
// componentName, e.getMessage());
// }
// return false;
// }
/**
* Removes the node.
*
* @return true, if successful
*/
public boolean removeNode() {
SSHExec connection = null;
try {
connection = this.nodeConfig.getConnection();
if (connection != null) {
AnkushTask removeZkDir = new Remove((String) this.conf
.getAdvanceConf().get(
ZookeeperConstant.Keys.DATA_DIRECTORY));
AnkushTask removeZookeeper = new Remove(this.conf.getHomeDir());
AnkushTask removeZooCommandExecutionLog = new Remove(
AgentUtils.getAgentLogDirectoryPath(clusterConfig)
+ ZookeeperConstant.Keys.ZOOKEEPER_COMMAND_EXECUTION_LOG_PATH);
connection.exec(removeZkDir);
connection.exec(removeZookeeper);
connection.exec(removeZooCommandExecutionLog);
return true;
} else {
throw new AnkushException(
Constant.Strings.ExceptionsMessage.CONNECTION_NULL_STRING);
}
} catch (AnkushException e) {
logger.error(e.getMessage(), componentName, nodeConfig.getHost(), e);
this.clusterConfig.addError(this.nodeConfig.getHost(),
componentName, e.getMessage());
} catch (Exception e) {
logger.error(e.getMessage(), componentName, nodeConfig.getHost(), e);
this.clusterConfig.addError(this.nodeConfig.getHost(),
componentName, e.getMessage());
}
return false;
}
/**
* Register.
*
* @return true, if successful
*/
public boolean register() {
SSHExec connection = null;
try {
connection = this.nodeConfig.getConnection();
if (connection == null) {
throw new AnkushException(
Constant.Strings.ExceptionsMessage.CONNECTION_NULL_STRING);
}
return configure();
} catch (AnkushException e) {
logger.error(e.getMessage(), componentName, nodeConfig.getHost(), e);
this.clusterConfig.addError(this.nodeConfig.getHost(),
componentName, e.getMessage());
} catch (Exception e) {
logger.error(e.getMessage(), componentName, nodeConfig.getHost(), e);
this.clusterConfig.addError(this.nodeConfig.getHost(),
componentName, e.getMessage());
}
return false;
}
public boolean unregister() {
SSHExec connection = null;
boolean status = false;
try {
connection = this.nodeConfig.getConnection();
if (connection == null) {
throw new AnkushException(
Constant.Strings.ExceptionsMessage.CONNECTION_NULL_STRING);
}
logger.info("Removing " + componentName + ".xml file from Agent");
status = com.impetus.ankush2.agent.AgentUtils.removeServiceXml(
nodeConfig.getConnection(), componentName);
if (!status) {
logger.warn("Couldn't remove " + componentName
+ ".xml file from Agent", componentName,
this.nodeConfig.getHost());
}
logger.info("Removing Zookeeper JMXTrans JSON from Agent");
status = com.impetus.ankush2.agent.AgentUtils
.removeProcessJmxtransJSON(nodeConfig.getConnection(),
Constant.Process.QUORUMPEERMAIN,
clusterConfig.getAgentHomeDir());
if (!status) {
logger.warn(
"Couldn't remove Zookeeper JMXTrans JSON from Agent",
componentName, this.nodeConfig.getHost());
}
} catch (AnkushException e) {
logger.error(e.getMessage(), componentName, nodeConfig.getHost(), e);
this.clusterConfig.addError(this.nodeConfig.getHost(),
componentName, e.getMessage());
status = false;
} catch (Exception e) {
logger.error(e.getMessage(), componentName, nodeConfig.getHost(), e);
this.clusterConfig.addError(this.nodeConfig.getHost(),
componentName, e.getMessage());
status = false;
}
return status;
}
}