/* This Source Code Form is subject to the terms of the Mozilla Public
* License, v. 2.0. If a copy of the MPL was not distributed with this
* file, You can obtain one at http://mozilla.org/MPL/2.0/. */
package org.ow2.choreos.ee.nodes.cm;
import java.io.File;
import java.net.URL;
import java.util.HashMap;
import java.util.Map;
import java.util.concurrent.Callable;
import org.apache.log4j.Logger;
import org.ow2.choreos.ee.config.Locations;
import org.ow2.choreos.ee.config.QoSManagementConfiguration;
import org.ow2.choreos.invoker.Invoker;
import org.ow2.choreos.invoker.InvokerException;
import org.ow2.choreos.invoker.InvokerFactory;
import org.ow2.choreos.nodes.NodeNotAccessibleException;
import org.ow2.choreos.nodes.datamodel.CloudNode;
import org.ow2.choreos.utils.Scp;
import org.ow2.choreos.utils.ScpFailed;
/**
*
* @author leonardo, thiago
*
*/
public class NodeBootstrapper {
public static final String BOOTSTRAP_SCRIPT = "chef-solo/bootstrap.sh";
public static final String SETUP_HARAKIRI_SCRIPT = "chef-solo/setup_harakiri.sh";
public static final String SETUP_MONITORING_SCRIPT = "chef-solo/setup_ganglia.sh";
public static final String INITIAL_NODE_JSON = "chef-solo/node.json";
public static final String PREPARE_DEPLOYMENT_SCRIPT = "chef-solo/prepare_deployment.sh";
public static final String PREPARE_UNDEPLOYMENT_SCRIPT = "chef-solo/prepare_undeployment.sh";
public static final String ADD_RECIPE_SCRIPT = "chef-solo/add_recipe_to_node.sh";
public static final String REMOVE_RECIPE_FROM_NODE = "chef-solo/remove_recipe_from_node.sh";
public static final String CHEF_SOLO_FOLDER = "chef-solo";
private CloudNode node;
private boolean usingQoSManagement = false;
private Logger logger = Logger.getLogger(NodeBootstrapper.class);
public NodeBootstrapper(CloudNode node) {
this.node = node;
this.usingQoSManagement = Boolean.parseBoolean(QoSManagementConfiguration
.get(QoSManagementConfiguration.QOS_MGMT));
}
public void bootstrapNode() throws NodeNotAccessibleException, NodeNotBootstrappedException {
logger.info("Bootstrapping " + this.node.getIp());
executeBootstrapCommand();
saveFile(PREPARE_DEPLOYMENT_SCRIPT, CHEF_SOLO_FOLDER);
saveFile(PREPARE_UNDEPLOYMENT_SCRIPT, CHEF_SOLO_FOLDER);
saveFile(ADD_RECIPE_SCRIPT, CHEF_SOLO_FOLDER);
saveFile(REMOVE_RECIPE_FROM_NODE, CHEF_SOLO_FOLDER);
saveFile(INITIAL_NODE_JSON, CHEF_SOLO_FOLDER);
saveFile(INITIAL_NODE_JSON, CHEF_SOLO_FOLDER + "/node.json.backup");
if (usingQoSManagement) {
setUpHarakiri();
setUpMonitoring();
}
logger.info("Bootstrap completed at " + this.node);
}
private void executeBootstrapCommand() throws NodeNotBootstrappedException {
Map<String, String> substitutions = new HashMap<String, String>();
String cookbooksUrl = Locations.get("COOKBOOKS");
if (cookbooksUrl == null || cookbooksUrl.isEmpty()) {
logger.error("Field COOKBOOKS in locations.properties should be filled!");
throw new NodeNotBootstrappedException(node.getId());
}
substitutions.put("$THE_COOKBOOKS_URL", cookbooksUrl);
int timeout = 3;
NodeSetup bootstrapSetup = NodeSetup.getInstance(node, BOOTSTRAP_SCRIPT, timeout, substitutions);
try {
bootstrapSetup.setup();
} catch (NodeSetupException e) {
logger.error("Could not bootstrap node " + node.getId());
throw new NodeNotBootstrappedException(node.getId());
}
}
private void setUpHarakiri() {
Map<String, String> substitutions = new HashMap<String, String>();
String enactmentEngineURL = QoSManagementConfiguration.get(QoSManagementConfiguration.ENACTMENT_ENGINE_URL);
substitutions.put("$THE_URL", enactmentEngineURL);
substitutions.put("$THE_ID", node.getId());
int timeout = 1;
NodeSetup harakiriSetup = NodeSetup.getInstance(node, SETUP_HARAKIRI_SCRIPT, timeout, substitutions);
try {
harakiriSetup.setup();
} catch (NodeSetupException e) {
logger.error("Could not properly setup harakiri on node " + node.getId());
}
}
private void setUpMonitoring() {
Map<String, String> substitutions = new HashMap<String, String>();
substitutions.put("$THE_IP",
QoSManagementConfiguration.get(QoSManagementConfiguration.RESOURCE_METRIC_AGGREGATOR));
int timeout = 1;
NodeSetup monitoringSetup = NodeSetup.getInstance(node, SETUP_MONITORING_SCRIPT, timeout, substitutions);
try {
monitoringSetup.setup();
} catch (NodeSetupException e) {
logger.error("Could not properly setup monitoring on node " + node.getId());
}
}
private void saveFile(String source, String target) throws NodeNotBootstrappedException {
ScpTask task = new ScpTask(source, target);
InvokerFactory<Void> factory = new InvokerFactory<Void>();
Invoker<Void> invoker = factory.geNewInvokerInstance("SCP", task);
try {
invoker.invoke();
} catch (InvokerException e) {
File file = getFile(source);
logger.error("It was not possible to save " + file.getName() + " on node " + node.getId());
throw new NodeNotBootstrappedException(node.getId());
}
}
private File getFile(String path) {
URL url = this.getClass().getClassLoader().getResource(path);
File file = new File(url.getFile());
if (!file.exists()) {
logger.error(path + " not found! Should never happen!");
throw new IllegalStateException();
}
return file;
}
private class ScpTask implements Callable<Void> {
String source, target;
public ScpTask(String source, String target) {
this.source = source;
this.target = target;
}
@Override
public Void call() throws Exception {
Scp scp = Scp.getInstance(node.getIp(), node.getUser(), node.getPrivateKeyFile());
File file = getFile(source);
try {
scp.sendFile(file.getAbsolutePath(), target);
} catch (ScpFailed e) {
logger.error("It was not possible to save " + file.getName() + " on node " + node.getId());
throw new NodeNotBootstrappedException(node.getId());
}
return null;
}
}
}