package org.ow2.choreos.ee;
import java.util.HashMap;
import java.util.HashSet;
import java.util.List;
import java.util.Map;
import java.util.Set;
import java.util.concurrent.Callable;
import java.util.concurrent.ExecutorService;
import java.util.concurrent.Executors;
import org.apache.log4j.Logger;
import org.ow2.choreos.chors.EnactmentException;
import org.ow2.choreos.ee.rest.RESTClientsRetriever;
import org.ow2.choreos.invoker.Invoker;
import org.ow2.choreos.invoker.InvokerException;
import org.ow2.choreos.invoker.InvokerFactory;
import org.ow2.choreos.nodes.NodePoolManager;
import org.ow2.choreos.nodes.datamodel.CloudNode;
import org.ow2.choreos.services.datamodel.DeployableService;
import org.ow2.choreos.utils.Concurrency;
import org.ow2.choreos.utils.TimeoutsAndTrials;
public class NodesUpdater {
private static final String TASK_NAME = "UPDATE_NODE";
private List<DeployableService> services;
private String chorId;
private Set<CloudNode> nodesToUpdate;
private Map<CloudNode, String> owners = new HashMap<CloudNode, String>();
private ExecutorService executor;
private int totalTimeout;
private Logger logger = Logger.getLogger(NodesUpdater.class);
public NodesUpdater(List<DeployableService> services, String chorId) {
this.services = services;
this.chorId = chorId;
int timeout = TimeoutsAndTrials.get("UPDATE_NODE_TIMEOUT");
int trials = TimeoutsAndTrials.get("UPDATE_NODE_TRIALS");
int pause = TimeoutsAndTrials.get("UPDATE_NODE_PAUSE");
this.totalTimeout = (timeout + pause) * trials;
this.totalTimeout += totalTimeout * 0.1;
}
public void updateNodes() throws EnactmentException {
logger.info("Going to update nodes of choreography " + chorId);
setNodesToUpdate();
submitUpdates();
waitUpdates();
}
private void setNodesToUpdate() {
nodesToUpdate = new HashSet<CloudNode>();
for (DeployableService deployable : services) {
for (CloudNode node : deployable.getSelectedNodes()) {
nodesToUpdate.add(node);
String owner = deployable.getSpec().getOwner();
owners.put(node, owner);
}
}
}
private void submitUpdates() {
executor = Executors.newFixedThreadPool(nodesToUpdate.size());
for (CloudNode node : nodesToUpdate) {
String nodeId = node.getId();
String owner = owners.get(node);
UpdateNodeInvoker updater = new UpdateNodeInvoker(nodeId, owner);
executor.submit(updater);
}
}
private void waitUpdates() {
Concurrency.waitExecutor(executor, totalTimeout, "Could not properly update all the nodes of chor " + chorId);
}
private class UpdateNodeInvoker implements Callable<Void> {
String nodeId, owner;
public UpdateNodeInvoker(String nodeId, String owner) {
this.nodeId = nodeId;
this.owner = owner;
}
@Override
public Void call() {
UpdateNodeTask task = new UpdateNodeTask(nodeId, owner);
InvokerFactory<Void> factory = new InvokerFactory<Void>();
Invoker<Void> invoker = factory.geNewInvokerInstance(TASK_NAME, task);
try {
invoker.invoke();
} catch (InvokerException e) {
logger.error("Bad response from updating node " + nodeId + "; maybe some service is not deployed");
}
return null;
}
}
private class UpdateNodeTask implements Callable<Void> {
String nodeId, owner;
public UpdateNodeTask(String nodeId, String owner) {
this.nodeId = nodeId;
this.owner = owner;
}
@Override
public Void call() throws Exception {
NodePoolManager npm = RESTClientsRetriever.getNodePoolManager(owner);
npm.updateNode(nodeId);
return null;
}
}
}