/**
*
*/
package org.ourgrid.common.executor.vmware;
import static org.ourgrid.common.executor.ProcessUtil.buildAndRunProcess;
import static org.ourgrid.common.executor.ProcessUtil.buildAndRunProcessNoWait;
import static org.ourgrid.common.executor.ProcessUtil.waitForProcess;
import java.io.File;
import java.io.IOException;
import java.util.Map;
import org.ourgrid.common.executor.ExecutorException;
import org.ourgrid.common.executor.ExecutorResult;
import org.ourgrid.common.executor.FolderBasedSandboxedUnixEnvironmentUtil;
import org.ourgrid.common.executor.OutputCatcher;
import org.ourgrid.common.executor.ProcessUtil;
import org.ourgrid.common.executor.SandBoxEnvironment;
import org.ourgrid.common.executor.config.ExecutorConfiguration;
import org.ourgrid.common.executor.config.VMWareExecutorConfiguration;
import org.ourgrid.worker.WorkerConfiguration;
import org.ourgrid.worker.WorkerConstants;
import br.edu.ufcg.lsd.commune.container.logging.CommuneLogger;
public class VMWareSandBoxEnvironment implements SandBoxEnvironment {
// scripts
private String vmImagePath;
/*
* These file contains the standard and error execution output. Also the
* execution exit value
*/
private File stdOutput;
private File errorOutput;
private File exitValueOutput;
private ExecutorConfiguration configuration;
private FolderBasedSandboxedUnixEnvironmentUtil unixFolderUtil = new FolderBasedSandboxedUnixEnvironmentUtil();
private String host_playpen_path;
private String host_storage_path;
// execution environment in Virtual Machine
private String playpenDirInVm;
private String storageDirInVM;
private VMWareCommandFactory commandFactory;
private CommuneLogger logger;
public VMWareSandBoxEnvironment(CommuneLogger logger) {
this.logger = logger;
}
/*
* (non-Javadoc)
*
* @see org.ourgrid.common.executor.SandBoxEnvironment#setConfiguration(org.ourgrid.common.executor.config.ExecutorConfiguration)
*/
public void setConfiguration(ExecutorConfiguration executorConfiguration) {
this.vmImagePath = executorConfiguration
.getProperty(WorkerConfiguration.PREFIX + VMWareExecutorConfiguration.PROPERTIES.VM_IMAGE_PATH.toString());
this.configuration = executorConfiguration;
this.playpenDirInVm = executorConfiguration
.getProperty(WorkerConfiguration.PREFIX + VMWareExecutorConfiguration.PROPERTIES.PLAYPEN_DIR_IN_VM.toString());
this.storageDirInVM = executorConfiguration
.getProperty(WorkerConfiguration.PREFIX + VMWareExecutorConfiguration.PROPERTIES.STORAGE_DIR_IN_VM.toString());
this.commandFactory = new VMWareCommandFactory(configuration);
}
public Process prepareAllocation() throws ExecutorException {
// init Virtual Machine
return buildAndRunProcessNoWait(commandFactory.createInitCommand(), "Could not init VMWare");
}
/*
* (non-Javadoc)
*
* @see org.ourgrid.common.executor.SandBoxEnvironment#initSandboxEnvironment(java.util.Map)
*/
public void initSandboxEnvironment(Map<String, String> envVars)
throws ExecutorException {
this.host_playpen_path = envVars.get(WorkerConstants.ENV_PLAYPEN);
this.stdOutput = new File(
host_playpen_path,
configuration
.getProperty(VMWareExecutorConfiguration.PROPERTIES.APP_STD_OUTPUT_FILE_NAME.toString()));
this.errorOutput = new File(
host_playpen_path,
configuration
.getProperty(VMWareExecutorConfiguration.PROPERTIES.APP_STD_ERROR_FILE_NAME.toString()));
this.exitValueOutput = new File(
host_playpen_path,
configuration
.getProperty(VMWareExecutorConfiguration.PROPERTIES.APP_STD_EXITVALUE_FILE_NAME.toString()));
}
private void createVMExecutionEnvironment(String tempStorage)throws ExecutorException {
createDirInGuest(playpenDirInVm);
createDirInGuest(storageDirInVM);
createDirInGuest("/tmp/vm/out");
// copy the playpen from host to VM
buildAndRunProcess(commandFactory.createCopyFromHostCommand(host_playpen_path,
playpenDirInVm), "Could not copy files from Host to VM.");
// copy storage from host to VM
buildAndRunProcess(commandFactory.createCopyFromHostCommand(tempStorage,
storageDirInVM), "Could not copy files from Host to VM.");
}
private void createDirInGuest(String dirPath) throws ExecutorException {
buildAndRunProcess(commandFactory.createNewDirCommand(dirPath),
"Could not create new dir in VM");
}
/*
* (non-Javadoc)
*
* @see org.ourgrid.common.executor.SandBoxEnvironment#executeRemoteCommand(java.lang.String,
* java.lang.String, java.util.Map)
*/
public Process executeRemoteCommand(String dirName, String command,
Map<String, String> envVars) throws ExecutorException {
logger.info( "Asked to run remote command " + command);
if(!isSandBoxUp()){
IllegalStateException illegalStateException
= new IllegalStateException("VMware environment is not running. Can not execute commands.");
throw new ExecutorException( illegalStateException );
}
return executeRemoteCommand(command, envVars);
}
/**
* @throws ExecutorException
* @throws IOException
*/
private void copyFilesFromVMToHost(String pathOnVM, String pathOnHost) throws ExecutorException, IOException {
buildAndRunProcess(commandFactory.createCopyFromGuestCommand(pathOnVM, pathOnHost),
"Could not copy file.");
}
private Process executeRemoteCommand(String cmd, Map<String, String> envVars) throws ExecutorException {
host_storage_path = envVars.get(WorkerConstants.ENV_STORAGE);
createVMExecutionEnvironment(host_storage_path);
String errorMessage = "Could not execute command.";
//create a execution script with the command on VM
Process proc = buildAndRunProcessNoWait(commandFactory.creteExecutionScriptCommand(cmd, envVars), errorMessage);
boolean normalTermination = waitForProcess(proc);
if (!normalTermination) {
throw new ExecutorException(errorMessage);
}
try {
//copy out, error and exit files from VM to host
copyFilesFromVMToHost("/tmp/vm/out", host_playpen_path);
} catch (IOException e) {
throw new ExecutorException("Could not copy files from VM to host.");
}
return proc;
}
private boolean isSandBoxUp() throws ExecutorException {
//execute list-vm.bat script
Process process = ProcessUtil.buildAndRunProcessNoWait(commandFactory.createVerifyCommand(),
"Could not list started VMs");
//get all started VMs
ExecutorResult result = getResultFromProcess(process);
if (result.getExitValue() != 0) {
logger.error("Unable to execute isSandBoxUp command. Standard Out message: " +
result.getStdout() + " Error message: " + result.getStderr());
throw new ExecutorException("Unable to execute isSandBoxUp command: " + result.getStderr());
} else {
String stdOut = result.getStdout();
//verify if this vm is up
return isSandBoxUp(vmImagePath, stdOut);
}
}
private ExecutorResult getResultFromProcess(Process process) throws ExecutorException {
ExecutorResult result = new ExecutorResult();
OutputCatcher stdOutput = new OutputCatcher( process.getInputStream() );
OutputCatcher stdErr = new OutputCatcher( process.getErrorStream() );
try {
result.setExitValue( process.waitFor() );
result.setStdout( stdOutput.getResult() );
result.setStderr( stdErr.getResult() );
} catch (InterruptedException e) {
throw new ExecutorException(e.getCause());
}
return result;
}
private boolean isSandBoxUp(String vm_image_path, String virtualMachines) {
//remove quotes from vm_image_path string
vm_image_path = vm_image_path.substring(1, vm_image_path.length() - 1);
return virtualMachines.indexOf(vm_image_path) != -1;
}
/*
* (non-Javadoc)
*
* @see org.ourgrid.common.executor.SandBoxEnvironment#getResult()
*/
public ExecutorResult getResult() throws ExecutorException {
logger.debug( "Getting result of execution..." );
ExecutorResult result = new ExecutorResult();
try {
unixFolderUtil.catchOutputFromFile(result, stdOutput, errorOutput,
exitValueOutput);
} catch (Exception e) {
throw new ExecutorException("Unable to catch output ", e);
}
logger.debug( "Finished getResult. Single Execution released." );
return result;
}
/*
* (non-Javadoc)
*
* @see org.ourgrid.common.executor.SandBoxEnvironment#hasExecutionFinished()
*/
public boolean hasExecutionFinished() throws ExecutorException {
return exitValueOutput.exists();
}
/*
* (non-Javadoc)
*
* @see org.ourgrid.common.executor.SandBoxEnvironment#shutDownSandBoxEnvironment()
*/
public void shutDownSandBoxEnvironment() throws ExecutorException {
buildAndRunProcess(commandFactory.createStopCommand(), "Could not stop VM.");
}
public void finishExecution() throws ExecutorException {
try {
//copy the result execution files from VM to host
copyFilesFromVMToHost(playpenDirInVm, host_playpen_path);
copyFilesFromVMToHost(storageDirInVM, host_storage_path);
} catch (IOException e) {
throw new ExecutorException("Could not copy files from VM to host.");
}
}
public void stopPrepareAllocation() throws ExecutorException {
}
public CommuneLogger getLogger() {
return logger;
}
}