
org.gridkit.lab.gridant.RemoteExecTask Maven / Gradle / Ivy
The newest version!
package org.gridkit.lab.gridant;
import static org.gridkit.nanocloud.VX.CONSOLE;
import java.io.File;
import java.io.IOException;
import java.io.PrintStream;
import java.io.Serializable;
import java.lang.management.ManagementFactory;
import java.net.InetAddress;
import java.net.URL;
import java.rmi.Remote;
import java.util.ArrayList;
import java.util.Enumeration;
import java.util.HashMap;
import java.util.Hashtable;
import java.util.List;
import java.util.Map;
import java.util.TreeMap;
import java.util.concurrent.Callable;
import java.util.concurrent.ExecutionException;
import java.util.concurrent.ExecutorService;
import java.util.concurrent.Executors;
import java.util.concurrent.Future;
import java.util.concurrent.ThreadFactory;
import org.apache.tools.ant.BuildException;
import org.apache.tools.ant.BuildLogger;
import org.apache.tools.ant.DefaultLogger;
import org.apache.tools.ant.Location;
import org.apache.tools.ant.MagicNames;
import org.apache.tools.ant.Project;
import org.apache.tools.ant.ProjectHelper;
import org.apache.tools.ant.ProjectHelperRepository;
import org.apache.tools.ant.RuntimeConfigurable;
import org.apache.tools.ant.Target;
import org.apache.tools.ant.Task;
import org.apache.tools.ant.TaskContainer;
import org.apache.tools.ant.UnknownElement;
import org.apache.tools.ant.helper.AntXMLContext;
import org.apache.tools.ant.types.resources.URLResource;
import org.gridkit.vicluster.MassExec;
import org.gridkit.vicluster.ViGroup;
import org.gridkit.vicluster.ViNode;
import org.gridkit.zeroio.WrapperOutputStream;
public class RemoteExecTask extends Task implements TaskContainer {
private String origPattern;
private List patterns = new ArrayList();
private List tasks = new ArrayList();
private RemoteExecutionHost execHost;
public static String getLocalhost() {
try {
return InetAddress.getLocalHost().getHostName();
}
catch(Exception e) {
String name = ManagementFactory.getRuntimeMXBean().getName();
if (name.indexOf('@') > 0) {
return name.substring(name.indexOf('@') + 1);
}
else {
return name;
}
}
}
public void setServers(String servers) {
origPattern = servers;
String[] sp = servers.split("[,]");
for(String p: sp) {
p = p.trim();
if (p.length() > 0) {
patterns.add(p);
}
}
}
@Override
public void addTask(Task task) {
tasks.add(new TaskData((UnknownElement)task));
}
@Override
public void execute() throws BuildException {
CloudContext cc = CloudContext.getInstance(getProject());
Map targets = new TreeMap();
for(String pattern: patterns) {
for(ViNode node: cc.getNodeSet().listNodes(pattern)) {
String name = node.toString();
targets.put(name, node);
}
}
if (targets.isEmpty()) {
System.out.println("Target execution set '" + origPattern + "' has been resolved to empty list");
}
else {
// touch
cc.getNodeSet().nodes(patterns.toArray(new String[0])).touch();
List> submissions = new ArrayList>();
for(ViNode node: targets.values()) {
final String hostname = node.exec(new Callable(){
@Override
public String call() throws Exception {
return getLocalhost();
}
});
final LatentProject slave = createSlaveProject(node.toString(), hostname);
final List script = tasks;
final String nodeName = node.toString();
final String sourceFile = filename(getLocation().getFileName());
final int sourceLine = getLocation().getLineNumber();
// node.setProp("gridkit.isolate.trace-classes", "true");
Future future = node.submit(new Callable(){
@Override
public Void call() throws Exception {
executeRemoteTasks(slave, hostname, sourceFile, sourceLine, script);
System.out.flush();
System.err.flush();
return null;
}
});
System.out.println(" -> " + hostname + " (" + nodeName + ")");
submissions.add(future);
}
try {
MassExec.waitAll(submissions);
exceptionMark();
}
catch(ExecutionException e) {
System.err.println("Task execution exception");
e.getCause().printStackTrace();
System.err.flush();
throwUncheked(e);
}
ViGroup.group(targets.values()).x(CONSOLE).flush();
}
}
private String filename(String fileName) {
int c = fileName.lastIndexOf('/');
if (c >= 0) {
return fileName.substring(c + 1);
}
c = fileName.lastIndexOf('\\');
if (c >= 0) {
return fileName.substring(c + 1);
}
return fileName;
}
private LatentProject createSlaveProject(String id, String hostname) {
try {
if (execHost == null) {
execHost = new RemoteExecutionHost(getProject());
}
// TODO a couple of hacks here to
AntXMLContext xctx = getProject().getReference("ant.parsing.context");
URL buildFile = xctx.getBuildFileURL();
if (buildFile == null) {
buildFile = xctx.getBuildFile().toURI().toURL();
}
SlaveProject slave = new SlaveProject();
slave.name = getProject().getName();
slave.id = id;
slave.hostname = hostname;
slave.executor = execHost;
slave.buildFile = buildFile.toURI().toString();
slave.logger = new RemoteBuildLogger(createRemoteLogger(id), getProject());
slave.props = new HashMap();
for(String pname: getProject().getProperties().keySet()) {
Object vp = getProject().getProperty(pname);
if (vp instanceof String) {
slave.props.put(pname, (String) vp);
}
}
slave.taskDefinitions = new HashMap>();
Hashtable> tbl = getProject().getTaskDefinitions();
for(String task: tbl.keySet()) {
slave.taskDefinitions.put(task, tbl.get(task));
}
return slave;
} catch(Exception e) {
throw new RuntimeException(e);
}
}
private static interface LatentProject {
public Project getProject();
}
private static class SlaveProject implements LatentProject, Serializable {
private static final long serialVersionUID = 20130715L;
String id;
String name;
String hostname;
BuildLogger logger;
MasterExecutor executor;
String buildFile;
Map props;
Map> taskDefinitions;
@Override
public Project getProject() {
try {
MasterURLHandler mh = new MasterURLHandler(executor);
URL rurl = new URL(buildFile);
URL buildFileUrl = new URL(rurl, rurl.getFile(), mh);
URLResource res = new URLResource(buildFileUrl);
Project project = new Project();
for(String prop: props.keySet()) {
project.setProperty(prop, props.get(prop));
}
ProjectHelper helper = ProjectHelperRepository.getInstance().getProjectHelperForBuildFile(res);
project.addReference(MagicNames.REFID_PROJECT_HELPER, helper);
project.addReference(GridAntRefs.MASTER_EXECUTOR, executor);
String baseDir = System.getProperty(GridAntProps.REMOTE_ANT_BASE_DIR);
if (baseDir != null) {
new File(baseDir).mkdirs();
project.setProperty("basedir", baseDir);
}
else {
project.setProperty("basedir", ".");
}
project.setProperty("ant.file", buildFile);
project.setProperty(GridAntProps.SLAVE_HOSTNAME, hostname);
project.setProperty(GridAntProps.SLAVE_ID, id);
for(String task: taskDefinitions.keySet()) {
try {
project.addTaskDefinition(task, taskDefinitions.get(task));
}
catch(NoClassDefFoundError e) {
System.out.println("cannot load task definition: " + task);
// When running Maven antrun plugin, some Maven specific tasks may be added to project.
// Maven classpath is not fully replicated though
}
}
helper.parse(project, res);
project.setName(name + " @ " + hostname);
project.addBuildListener(logger);
return project;
} catch (BuildException e) {
throw new RuntimeException(e);
} catch (IOException e) {
throw new RuntimeException(e);
}
}
}
private static BuildLogger createRemoteLogger(String serverId) {
BuildLogger logger = null;
logger = new DefaultLogger();
logger.setMessageOutputLevel(Project.MSG_INFO);
logger.setOutputPrintStream(new PrintStream(new WrapperOutputStream("(" + serverId + ") -> ", OutputStreamHelper.stdOut)));
logger.setErrorPrintStream(new PrintStream(new WrapperOutputStream("(" + serverId + ") -> ", OutputStreamHelper.stdErr)));
logger.setEmacsMode(false);
return logger;
}
private static void executeRemoteTasks(LatentProject lp, String hostname, String buildSource, int sourceLine, List script) {
Project project = lp.getProject();
Target target = new Target();
String targetName = buildSource + ":" + sourceLine + " @ " + hostname;
target.setName(targetName);
target.setProject(project);
for(TaskData td: script) {
Task task = td.instantiate(project);
target.addTask(task);
}
project.addTarget(target);
OutputStreamHelper.activate(project);
project.executeTarget(targetName);
OutputStreamHelper.restore();
}
private static class TaskData implements Serializable {
private static final long serialVersionUID = 20130715L;
String tag;
String namespace;
String qname;
String taskType;
String taskName;
Location location;
RuntimeConfigurable conf;
List children = new ArrayList();
public TaskData(UnknownElement task) {
tag = task.getTag();
namespace = task.getNamespace();
qname = task.getQName();
taskType = task.getTaskType();
taskName = task.getTaskName();
location = task.getLocation();
conf = new RuntimeConfigurable(new ProxyMock(), task.getTaskName());
conf.setPolyType(task.getWrapper().getPolyType());
Map m = task.getWrapper().getAttributeMap();
for (Map.Entry entry : m.entrySet()) {
conf.setAttribute(entry.getKey(), (String) entry.getValue());
}
conf.addText(task.getWrapper().getText().toString());
for (Enumeration e = task.getWrapper().getChildren(); e.hasMoreElements();) {
RuntimeConfigurable r = e.nextElement();
UnknownElement ueChild = (UnknownElement) r.getProxy();
TaskData child = new TaskData(ueChild);
children.add(child);
}
}
public UnknownElement instantiate(Project project) {
UnknownElement ret = new UnknownElement(tag);
ret.setNamespace(namespace);
ret.setProject(project);
ret.setQName(qname);
ret.setTaskType(taskType);
ret.setTaskName(taskName);
ret.setLocation(location);
RuntimeConfigurable rc = new RuntimeConfigurable(ret, taskName);
rc.setPolyType(conf.getPolyType());
Map m = conf.getAttributeMap();
for (Map.Entry entry : m.entrySet()) {
rc.setAttribute(entry.getKey(), (String) entry.getValue());
}
rc.addText(conf.getText().toString());
for(TaskData child: children) {
UnknownElement ue = child.instantiate(project);
rc.addChild(ue.getRuntimeConfigurableWrapper());
ret.addChild(ue);
}
return ret;
}
}
private static class ProxyMock implements Serializable {
private static final long serialVersionUID = 20130715L;
}
private interface RemoteMasterExecutor extends MasterExecutor, Remote {
}
private class RemoteExecutionHost implements RemoteMasterExecutor {
private Project project;
private ExecutorService service = Executors.newCachedThreadPool(new ThreadFactory() {
@Override
public Thread newThread(Runnable r) {
Thread t = new Thread(r);
t.setDaemon(true);
return t;
}
});
public RemoteExecutionHost(Project project) {
this.project = project;
}
@Override
public T exec(final MasterCallable task) {
try {
return service.submit(new Callable(){
@Override
public T call() throws Exception {
return task.call(project);
}
}).get();
} catch (InterruptedException e) {
throwUncheked(e);
throw new Error("Unreachable");
} catch (ExecutionException e) {
throwUncheked(e.getCause());
throw new Error("Unreachable");
}
}
}
private static void exceptionMark() throws ExecutionException {
}
private static void throwUncheked(Throwable e) {
RemoteExecTask.throwAny(e);
}
@SuppressWarnings("unchecked")
private static void throwAny(Throwable e) throws E {
throw (E)e;
}
}
© 2015 - 2025 Weber Informatics LLC | Privacy Policy