/*******************************************************************************
* ===========================================================
* 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.preprocessor;
import java.io.File;
import java.util.List;
import java.util.Set;
import java.util.concurrent.Semaphore;
import net.neoremind.sshxcute.core.Result;
import net.neoremind.sshxcute.core.SSHExec;
import net.neoremind.sshxcute.task.CustomTask;
import com.impetus.ankush.AppStoreWrapper;
import com.impetus.ankush.common.exception.AnkushException;
import com.impetus.ankush.common.scripting.impl.ExecSudoCommand;
import com.impetus.ankush.common.utils.FileNameUtils;
import com.impetus.ankush.common.utils.FileUtils;
import com.impetus.ankush2.constant.Constant;
import com.impetus.ankush2.framework.AbstractDeployer;
import com.impetus.ankush2.framework.config.ClusterConfig;
import com.impetus.ankush2.framework.utils.ObjectFactory;
import com.impetus.ankush2.logger.AnkushLogger;
import com.impetus.ankush2.utils.AnkushUtils;
import com.impetus.ankush2.utils.SSHUtils;
public class DependencyDeployer extends AbstractDeployer {
private ClusterConfig clusterConfig;
/** DependencyDeployer logger */
private AnkushLogger logger = new AnkushLogger(DependencyDeployer.class);
private boolean addClusterError(String error, Throwable t) {
return addClusterError(error, null, t);
}
@Override
public String getComponentName() {
return Constant.Component.Name.DEPENDENCY;
}
private boolean addClusterError(String error, String host, Throwable t) {
if (host != null) {
this.clusterConfig.addError(host, getComponentName(), error);
logger.error(error, getComponentName(), host, t);
} else {
this.clusterConfig.addError(getComponentName(), error);
logger.error(error, getComponentName(), t);
}
return false;
}
@Override
public boolean deploy(ClusterConfig conf) {
logger.info("Installing dependencies for cluster deployment.",
getComponentName());
try {
return installDependencies(conf);
} catch (AnkushException e) {
return addClusterError(e.getMessage(), e);
} catch (Exception e) {
return addClusterError("Exception while deploying dependencies", e);
}
}
private boolean installDependencies(ClusterConfig clusterConfig)
throws AnkushException {
boolean status = true;
try {
for (String component : clusterConfig.getComponents().keySet()) {
if (!component.equalsIgnoreCase(Constant.Component.Name.AGENT)) {
Set<String> nodesForDependenciesDeployment = ObjectFactory
.getDeployerObject(component)
.getNodesForDependenciesDeployment(clusterConfig);
if (nodesForDependenciesDeployment == null) {
continue;
}
status = installDependencyOnNodes(component,
nodesForDependenciesDeployment, clusterConfig)
&& status;
}
}
return status;
} catch (AnkushException e) {
throw e;
} catch (Exception e) {
throw new AnkushException(
"Exception while installing dependencies on nodes"
+ getExceptionString(e), e);
}
}
@Override
public boolean addNode(ClusterConfig conf, ClusterConfig newConf) {
try {
this.clusterConfig = conf;
this.logger.setCluster(clusterConfig);
return installDependencies(newConf);
} catch (AnkushException e) {
return addClusterError(e.getMessage(), e);
} catch (Exception e) {
return addClusterError("Could not add node to "
+ getComponentName() + " cluster" + getExceptionString(e),
e);
}
}
private boolean installDependencyOnNodes(final String component,
Set<String> nodes, final ClusterConfig clusterConfig)
throws AnkushException {
try {
logger.info("Installing " + component + " dependencies",
getComponentName());
final Semaphore nodeSemaphore = new Semaphore(nodes.size());
for (final String node : nodes) {
nodeSemaphore.acquire();
AppStoreWrapper.getExecutor().execute(new Runnable() {
@Override
public void run() {
clusterConfig
.getNodes()
.get(node)
.setStatus(
installDependency(node, component,
clusterConfig));
if (nodeSemaphore != null) {
nodeSemaphore.release();
}
}
});
}
nodeSemaphore.acquire(nodes.size());
logger.info("Installing " + component + " dependencies done.",
getComponentName());
return AnkushUtils.getStatus(clusterConfig.getNodes());
} catch (Exception e) {
throw new AnkushException(
"Exception while creating threads for installing dependencies"
+ getExceptionString(e), e);
}
}
private boolean installDependency(String node, String componentName,
ClusterConfig clusterConfig) {
try {
logger.info("Installing " + componentName + " dependencies on "
+ node, getComponentName(), node);
SSHExec connection = getConnection(node, clusterConfig);
String password = getPassword();
// Getting the OS Name of the Node.
String osName = SSHUtils.getOS(connection, node);
if (osName == null || osName.isEmpty()) {
throw new AnkushException("Could not identify OS details for "
+ node + ".");
}
// Getting the dependency file name for the fetched os
// name
String dependencyFileName = FileNameUtils.getDependencyFileName(
osName, componentName);
File file = new File(dependencyFileName);
if (file.exists()) {
// Getting list of dependency installation commands
// from dependency file.
List<String> depListCmds = FileUtils
.loadLines(dependencyFileName);
for (String installCmd : depListCmds) {
if (!installCmd.isEmpty()) {
// Executing the dependency installation
// command.
CustomTask execTask = new ExecSudoCommand(password,
installCmd);
Result rs = connection.exec(execTask);
if (rs.rc != 0) {
throw new AnkushException(installCmd + " failed.");
}
}
}
}
logger.info("Installing " + componentName + " dependencies on "
+ node + " done.", getComponentName(), node);
return true;
} catch (AnkushException e) {
return addClusterError(e.getMessage(), node, e);
} catch (Exception e) {
return addClusterError(
"Exception while installing dependencies on node"
+ getExceptionString(e), node, e);
}
}
/**
* Provides node's connection object
*
* @param host
* {@link String}
* @return {@link SSHExec}
*/
private SSHExec getConnection(String host, ClusterConfig clusterConfig)
throws AnkushException {
try {
return clusterConfig.getNodes().get(host).getConnection();
} catch (Exception e) {
throw new AnkushException(
"Exception while getting node's connection object.");
}
}
private String getPassword() {
return clusterConfig.getAuthConf().getPassword() != null ? clusterConfig
.getAuthConf().getPassword() : null;
}
private String getExceptionString(Exception e) {
return e.getMessage() != null ? ": " + e.getMessage() : "";
}
@Override
public boolean createConfig(ClusterConfig conf) {
try {
this.clusterConfig = conf;
this.logger.setCluster(clusterConfig);
return true;
} catch (Exception e) {
logger.error(
"Exception while creating configuration for dependencies deployment",
getComponentName());
return false;
}
}
}