Java tutorial
/* * Copyright (C) 2008 Universidade Federal de Campina Grande * * This file is part of OurGrid. * * OurGrid is free software: you can redistribute it and/or modify it under the * terms of the GNU Lesser General Public License as published by the Free * Software Foundation, either version 3 of the License, or (at your option) * any later version. * * This program 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 program. If not, see <http://www.gnu.org/licenses/>. * */ package org.ourgrid.common.executor.vbox; import static org.ourgrid.common.executor.ProcessUtil.buildAndRunProcess; import static org.ourgrid.common.executor.ProcessUtil.buildAndRunProcessNoWait; import java.io.BufferedWriter; import java.io.File; import java.io.FileWriter; import java.io.IOException; import java.io.PrintWriter; import java.util.LinkedList; import java.util.List; import java.util.Map; import org.apache.commons.io.FileUtils; import org.ourgrid.common.executor.ExecutorException; import org.ourgrid.common.executor.ExecutorResult; import org.ourgrid.common.executor.FolderBasedSandboxedUnixEnvironmentUtil; import org.ourgrid.common.executor.SandBoxEnvironment; import org.ourgrid.common.executor.config.ExecutorConfiguration; import org.ourgrid.common.executor.config.VirtualMachineExecutorConfiguration; import org.ourgrid.common.util.CommonUtils; import org.ourgrid.worker.WorkerConstants; import br.edu.ufcg.lsd.commune.container.logging.CommuneLogger; /** * Executor that performs application executions on a sandboxed environment. The virtual environment * is started using predetermined scripts. Currently the only virtual machine supported by this * executor is <i>VirtualBox (http://www.virtualbox.org)</i>. */ public class VirtualBoxEnvironment implements SandBoxEnvironment { private static final long serialVersionUID = 40L; /* * Constants used to build properties file that will be transfered to the virtual machine. The * file has the following syntax. * * APP_SCRIPT="value" * APP_EXIT="value" * APP_STDOUT="value" * APP_STDERR="value" * TERMINATION_FILE="value" * STORAGE_NAME="value" */ private static final String VIRTUAL_ENV_APP_SCRIPT_PROP = "APP_SCRIPT"; private static final String VIRTUAL_ENV_APP_EXIT_PROP = "APP_EXIT"; private static final String VIRTUAL_ENV_APP_STDOUT_PROP = "APP_STDOUT"; private static final String VIRTUAL_ENV_APP_STDERR_PROP = "APP_STDERR"; private static final String VIRTUAL_ENV_TERMINATION_FILE_PROP = "TERMINATION_FILE"; private static final String VIRTUAL_ENV_STORAGE_NAME_PROP = "STORAGE_NAME"; private static final String VIRTUAL_ENV_PROPS_FILES = "OG_OPTS"; /* * Constants that determine default names for output files. */ private static final String APP_EXIT = "app.exit"; private static final String APP_STDERR = "app.stderr"; private static final String APP_STDOUT = "app.stdout"; private static final String APP_SCRIPT_SH = "app.script.sh"; private static final String TERMINATED = ".terminated"; private static final String VBOX_VM_STORAGE = "storage"; /* * Location of the virtual environment properties file. */ private File virtualEnvPropertiesFile; /* * Configured commands. */ private String startvmCmd; private String stopvmCmd; private String machineName; private String vBoxLocation; /* * Class parameters to manipulate executions. */ private File terminationFile; private File execFile; private File stdOut; private File stdErr; private File exitStatus; private File vmStorage; private File playpen; private File storage; /* * Other */ private final FolderBasedSandboxedUnixEnvironmentUtil unixFolderUtil; private CommuneLogger logger; private Process execProcess; /** * Creates a new <code>VirtualMachineExecutor</code> using the * given <code>Executor</code> to perform tasks. * * @param osExecutor <code>Executor</code> that will execute scripts. * @param logger */ public VirtualBoxEnvironment(CommuneLogger logger) { this.unixFolderUtil = new FolderBasedSandboxedUnixEnvironmentUtil(); this.logger = logger; } public void setConfiguration(ExecutorConfiguration executorConfiguratrion) { this.startvmCmd = ("\"" + executorConfiguratrion.getProperty(VirtualMachineExecutorConfiguration.PROPERTY_START_VM_COMMAND) + "\""); this.stopvmCmd = ("\"" + executorConfiguratrion.getProperty(VirtualMachineExecutorConfiguration.PROPERTY_STOP_VM_COMMAND) + "\""); this.vBoxLocation = ("\"" + executorConfiguratrion.getProperty(VirtualMachineExecutorConfiguration.PROPERTY_VBOX_LOCATION) + "\""); this.machineName = executorConfiguratrion .getProperty(VirtualMachineExecutorConfiguration.PROPERTY_MACHINE_NAME); } private void initEnvironmentVariables(Map<String, String> envVars) throws ExecutorException { String uniquifier = Integer.toString((int) (Math.random() * Integer.MAX_VALUE)); this.playpen = new File(envVars.get(WorkerConstants.ENV_PLAYPEN)); this.storage = new File(envVars.get(WorkerConstants.ENV_STORAGE)); this.vmStorage = new File(playpen.getAbsolutePath() + File.separator + uniquifier + VBOX_VM_STORAGE); this.terminationFile = new File(playpen.getAbsolutePath() + File.separator + uniquifier + TERMINATED); this.execFile = new File(playpen.getAbsolutePath() + File.separator + uniquifier + APP_SCRIPT_SH); this.stdOut = new File(playpen.getAbsolutePath() + File.separator + uniquifier + APP_STDOUT); this.stdErr = new File(playpen.getAbsolutePath() + File.separator + uniquifier + APP_STDERR); this.exitStatus = new File(playpen.getAbsolutePath() + File.separator + uniquifier + APP_EXIT); this.virtualEnvPropertiesFile = new File( playpen.getAbsolutePath() + File.separator + VIRTUAL_ENV_PROPS_FILES); } public Process executeRemoteCommand(String dirName, String command, Map<String, String> envVars) throws ExecutorException { try { // String env_storage = envVars.get(WorkerConstants.ENV_STORAGE); // command = command.replace(env_storage, vmStorage.getName()); getLogger().info("Asked to run command " + command); //Defining new environment variables Map<String, String> clone = CommonUtils.createSerializableMap(); clone.putAll(envVars); clone.remove(WorkerConstants.ENV_PLAYPEN); clone.remove(WorkerConstants.ENV_STORAGE); clone.put(WorkerConstants.PROP_STORAGE_DIR, vmStorage.getName()); //Creating application script File script = unixFolderUtil.createScript(command, dirName, clone); //Writing virtual environment variables PrintWriter writer = new PrintWriter(new BufferedWriter(new FileWriter(virtualEnvPropertiesFile))); writer.println(VIRTUAL_ENV_APP_SCRIPT_PROP + "=" + execFile.getName()); writer.println(VIRTUAL_ENV_APP_EXIT_PROP + "=" + exitStatus.getName()); writer.println(VIRTUAL_ENV_APP_STDOUT_PROP + "=" + stdOut.getName()); writer.println(VIRTUAL_ENV_APP_STDERR_PROP + "=" + stdErr.getName()); writer.println(VIRTUAL_ENV_TERMINATION_FILE_PROP + "=" + terminationFile.getName()); writer.println(VIRTUAL_ENV_STORAGE_NAME_PROP + "=" + vmStorage.getName()); try { if (writer.checkError()) { throw new IOException("Unable to create Virtual environment"); } } finally { writer.close(); } //Copying files to needed location FileUtils.copyFile(script, execFile); unixFolderUtil.copyStorageFiles(storage, vmStorage); } catch (IOException e) { throw new ExecutorException("Unable to create remote execution script", e); } getLogger().debug("About to start secure environment"); //Executing command that will initiate virtual environment and execute the process Process execProcess = buildAndRunProcessNoWait(createStartVmAndExecuteCmd(), "Could not execute command"); setExecProcess(execProcess); getLogger().debug("About to wait for secure environment to exit"); return execProcess; } private List<String> createStartVmAndExecuteCmd() { List<String> cmd = new LinkedList<String>(); cmd.add(startvmCmd); cmd.add(vBoxLocation); cmd.add(machineName); cmd.add(getPlayPenPath()); return cmd; } private String getPlayPenPath() { return "\"" + playpen.getAbsolutePath() + "\""; } public ExecutorResult getResult() throws ExecutorException { if (!isExecutionInProcess()) { throw new ExecutorException("No execution is in process, probably it was killed."); } //Acquiring results ExecutorResult result = new ExecutorResult(); try { unixFolderUtil.copyStorageFiles(vmStorage, storage); unixFolderUtil.catchOutputFromFile(result, stdOut, stdErr, exitStatus); } catch (Throwable e) { throw new ExecutorException("Unable to catch output ", e); } finally { stopVm(); cleanup(); } return result; } public void killVm() throws ExecutorException { if (!isExecutionInProcess()) { throw new ExecutorException("No execution is in process"); } stopVm(); cleanup(); } private void stopVm() throws ExecutorException { getLogger().debug("About to kill secure environment"); buildAndRunProcess(createStopVmCommand(), "Unable to kill virtual environment"); Process execProcess = getExecProcess(); if (execProcess != null) { execProcess.destroy(); } } private List<String> createStopVmCommand() { List<String> cmd = new LinkedList<String>(); cmd.add(stopvmCmd); cmd.add(vBoxLocation); cmd.add(machineName); return cmd; } private void cleanup() { this.playpen = null; this.vmStorage = null; this.terminationFile = null; this.execFile = null; this.stdOut = null; this.stdErr = null; this.exitStatus = null; } protected boolean isExecutionInProcess() { return playpen != null; } public void chmod(File file, String perm) throws ExecutorException { } public void finishExecution() throws ExecutorException { } public CommuneLogger getLogger() { return logger; } public boolean hasExecutionFinished() throws ExecutorException { return exitStatus.exists(); } public void initSandboxEnvironment(Map<String, String> envVars) throws ExecutorException { initEnvironmentVariables(envVars); } public void shutDownSandBoxEnvironment() throws ExecutorException { killVm(); } public void stopPrepareAllocation() throws ExecutorException { stopVm(); cleanup(); } public Process prepareAllocation() throws ExecutorException { return null; } public void setExecProcess(Process execProcess) { this.execProcess = execProcess; } public Process getExecProcess() { return execProcess; } }