package org.batfish.coordinator;
import java.io.ByteArrayOutputStream;
import java.io.File;
import java.io.FileNotFoundException;
import java.io.FileOutputStream;
import java.io.FilenameFilter;
import java.io.IOException;
import java.io.InputStream;
import java.io.OutputStream;
import java.nio.file.Files;
import java.nio.file.Path;
import java.nio.file.Paths;
import java.security.AccessControlException;
import java.util.ArrayList;
import java.util.Arrays;
import java.util.HashSet;
import java.util.Iterator;
import java.util.List;
import java.util.Map;
import java.util.Set;
import java.util.TreeMap;
import java.util.UUID;
import java.util.concurrent.Executors;
import java.util.concurrent.TimeUnit;
import javax.ws.rs.ProcessingException;
import javax.ws.rs.client.Client;
import javax.ws.rs.client.ClientBuilder;
import javax.ws.rs.client.WebTarget;
import javax.ws.rs.core.MediaType;
import javax.ws.rs.core.Response;
import org.apache.commons.io.FileExistsException;
import org.apache.commons.io.FileUtils;
import org.apache.commons.lang.exception.ExceptionUtils;
import org.batfish.common.BatfishLogger;
import org.batfish.common.BfConsts;
import org.batfish.common.BfConsts.TaskStatus;
import org.batfish.common.Task;
import org.batfish.common.util.BatfishObjectMapper;
import org.batfish.common.util.CommonUtil;
import org.batfish.common.util.UnzipUtility;
import org.batfish.common.util.ZipUtility;
import org.batfish.common.WorkItem;
import org.codehaus.jettison.json.JSONArray;
import org.codehaus.jettison.json.JSONException;
import org.codehaus.jettison.json.JSONObject;
import org.glassfish.jersey.uri.UriComponent;
public class WorkMgr {
final class AssignWorkTask implements Runnable {
@Override
public void run() {
Main.getWorkMgr().checkTask();
Main.getWorkMgr().assignWork();
}
}
final class CheckTaskTask implements Runnable {
@Override
public void run() {
Main.getWorkMgr().checkTask();
}
}
private static final Set<String> ENV_FILENAMES = initEnvFilenames();
// private Runnable _checkWorkTask;
// private Runnable _assignWorkTask;
//
// private ScheduledExecutorService _checkService;
// private ScheduledExecutorService _assignService;
//
// private ScheduledFuture<?> _checkFuture;
// private ScheduledFuture<?> _assignFuture;
private static Set<String> initEnvFilenames() {
Set<String> envFilenames = new HashSet<>();
envFilenames.add(BfConsts.RELPATH_NODE_BLACKLIST_FILE);
envFilenames.add(BfConsts.RELPATH_INTERFACE_BLACKLIST_FILE);
envFilenames.add(BfConsts.RELPATH_EDGE_BLACKLIST_FILE);
envFilenames.add(BfConsts.RELPATH_ENVIRONMENT_BGP_TABLES);
envFilenames.add(BfConsts.RELPATH_ENVIRONMENT_ROUTING_TABLES);
envFilenames.add(BfConsts.RELPATH_EXTERNAL_BGP_ANNOUNCEMENTS);
return envFilenames;
}
private BatfishLogger _logger;
private WorkQueueMgr _workQueueMgr;
public WorkMgr(BatfishLogger logger) {
_logger = logger;
_workQueueMgr = new WorkQueueMgr();
}
private void assignWork() {
try {
QueuedWork work = _workQueueMgr.getWorkForAssignment();
// get out if no work was found
if (work == null) {
// _logger.info("WM:AssignWork: No unassigned work\n");
return;
}
String idleWorker = Main.getPoolMgr().getWorkerForAssignment();
// get out if no idle worker was found, but release the work first
if (idleWorker == null) {
_workQueueMgr.markAssignmentFailure(work);
_logger.info("WM:AssignWork: No idle worker\n");
return;
}
assignWork(work, idleWorker);
}
catch (Exception e) {
String stackTrace = ExceptionUtils.getFullStackTrace(e);
_logger.error("Got exception in assignWork: " + stackTrace);
}
}
private void assignWork(QueuedWork work, String worker) {
_logger.info("WM:AssignWork: Trying to assign " + work + " to " + worker
+ " \n");
boolean assignmentError = false;
boolean assigned = false;
try {
// get the task and add other standard stuff
JSONObject task = work.getWorkItem().toTask();
Path containerDir = Paths.get(
Main.getSettings().getContainersLocation(),
work.getWorkItem().getContainerName());
String testrigName = work.getWorkItem().getTestrigName();
Path testrigBaseDir = containerDir.resolve(testrigName)
.toAbsolutePath();
task.put(BfConsts.ARG_CONTAINER_DIR,
containerDir.toAbsolutePath().toString());
task.put(BfConsts.ARG_TESTRIG, testrigName);
task.put(BfConsts.ARG_LOG_FILE,
testrigBaseDir
.resolve(
work.getId().toString() + BfConsts.SUFFIX_LOG_FILE)
.toString());
task.put(BfConsts.ARG_ANSWER_JSON_PATH,
testrigBaseDir.resolve(
work.getId().toString() + BfConsts.SUFFIX_ANSWER_JSON_FILE)
.toString());
Client client = ClientBuilder.newClient();
WebTarget webTarget = client
.target(String.format("http://%s%s/%s", worker,
BfConsts.SVC_BASE_RSC, BfConsts.SVC_RUN_TASK_RSC))
.queryParam(BfConsts.SVC_TASKID_KEY,
UriComponent.encode(work.getId().toString(),
UriComponent.Type.QUERY_PARAM_SPACE_ENCODED))
.queryParam(BfConsts.SVC_TASK_KEY,
UriComponent.encode(task.toString(),
UriComponent.Type.QUERY_PARAM_SPACE_ENCODED));
Response response = webTarget.request(MediaType.APPLICATION_JSON)
.get();
if (response.getStatus() != Response.Status.OK.getStatusCode()) {
_logger.error("WM:AssignWork: Got non-OK response "
+ response.getStatus() + "\n");
}
else {
String sobj = response.readEntity(String.class);
JSONArray array = new JSONArray(sobj);
_logger
.info(String.format("WM:AssignWork: response: %s [%s] [%s]\n",
array.toString(), array.get(0), array.get(1)));
if (!array.get(0).equals(BfConsts.SVC_SUCCESS_KEY)) {
_logger.error(String.format("ERROR in assigning task: %s %s\n",
array.get(0), array.get(1)));
assignmentError = true;
}
else {
assigned = true;
}
}
}
catch (ProcessingException e) {
String stackTrace = ExceptionUtils.getFullStackTrace(e);
_logger.error(String.format("unable to connect to %s: %s\n", worker,
stackTrace));
}
catch (Exception e) {
String stackTrace = ExceptionUtils.getFullStackTrace(e);
_logger.error(String.format("exception: %s\n", stackTrace));
}
// mark the assignment results for both work and worker
if (assignmentError) {
_workQueueMgr.markAssignmentError(work);
}
else if (assigned) {
_workQueueMgr.markAssignmentSuccess(work, worker);
}
else {
_workQueueMgr.markAssignmentFailure(work);
}
Main.getPoolMgr().markAssignmentResult(worker, assigned);
}
private void checkTask() {
try {
QueuedWork work = _workQueueMgr.getWorkForChecking();
if (work == null) {
// _logger.info("WM:checkTask: No assigned work\n");
return;
}
String assignedWorker = work.getAssignedWorker();
if (assignedWorker == null) {
_logger.error("WM:CheckWork no assinged worker for " + work + "\n");
_workQueueMgr.makeWorkUnassigned(work);
return;
}
checkTask(work, assignedWorker);
}
catch (Exception e) {
_logger.error("Got exception in assignWork: " + e.getMessage());
}
}
private void checkTask(QueuedWork work, String worker) {
_logger.info(
"WM:CheckWork: Trying to check " + work + " on " + worker + " \n");
Task task = new Task();
task.setStatus(TaskStatus.UnreachableOrBadResponse);
try {
Client client = ClientBuilder.newClient();
WebTarget webTarget = client
.target(String.format("http://%s%s/%s", worker,
BfConsts.SVC_BASE_RSC, BfConsts.SVC_GET_TASKSTATUS_RSC))
.queryParam(BfConsts.SVC_TASKID_KEY,
UriComponent.encode(work.getId().toString(),
UriComponent.Type.QUERY_PARAM_SPACE_ENCODED));
Response response = webTarget.request(MediaType.APPLICATION_JSON)
.get();
if (response.getStatus() != Response.Status.OK.getStatusCode()) {
_logger.error("WM:CheckTask: Got non-OK response "
+ response.getStatus() + "\n");
}
else {
String sobj = response.readEntity(String.class);
JSONArray array = new JSONArray(sobj);
_logger.info(String.format("response: %s [%s] [%s]\n",
array.toString(), array.get(0), array.get(1)));
if (!array.get(0).equals(BfConsts.SVC_SUCCESS_KEY)) {
_logger.error(
String.format("got error while refreshing status: %s %s\n",
array.get(0), array.get(1)));
}
else {
String taskStr = array.get(1).toString();
BatfishObjectMapper mapper = new BatfishObjectMapper();
task = mapper.readValue(taskStr, Task.class);
if (task.getStatus() == null) {
_logger.error(String
.format("did not see status key in json response\n"));
}
}
}
}
catch (ProcessingException e) {
String stackTrace = ExceptionUtils.getFullStackTrace(e);
_logger.error(String.format("unable to connect to %s: %s\n", worker,
stackTrace));
}
catch (Exception e) {
String stackTrace = ExceptionUtils.getFullStackTrace(e);
_logger.error(String.format("exception: %s\n", stackTrace));
}
_workQueueMgr.processTaskCheckResult(work, task);
// if the task ended, send a hint to the pool manager to look up worker
// status
if (task.getStatus() == TaskStatus.TerminatedAbnormally
|| task.getStatus() == TaskStatus.TerminatedNormally) {
Main.getPoolMgr().refreshWorkerStatus(worker);
}
}
public void configureAnalysis(String containerName, boolean newAnalysis,
String aName, InputStream addQuestionsFileStream,
String delQuestionsStr) throws Exception {
File containerDir = getdirContainer(containerName);
File aDir = Paths.get(containerDir.getAbsolutePath(),
BfConsts.RELPATH_ANALYSES_DIR, aName).toFile();
if (aDir.exists() && newAnalysis) {
throw new FileExistsException("Analysis " + aName
+ " already exists for container " + containerName);
}
if (!aDir.exists()) {
if (!newAnalysis) {
throw new FileExistsException("Analysis " + aName
+ " does not exists for container " + containerName);
}
if (!aDir.mkdirs()) {
throw new Exception("failed to create analyses directory "
+ aDir.getAbsolutePath());
}
}
File questionsDir = Paths
.get(aDir.getAbsolutePath(), BfConsts.RELPATH_QUESTIONS_DIR)
.toFile();
if (addQuestionsFileStream != null) {
ByteArrayOutputStream questions = new ByteArrayOutputStream();
int read = 0;
final byte[] buffer = new byte[1024];
while ((read = addQuestionsFileStream.read(buffer)) != -1) {
questions.write(buffer, 0, read);
}
JSONObject jObject = new JSONObject(questions.toString("UTF-8"));
Iterator<?> keys = jObject.keys();
while (keys.hasNext()) {
String qName = (String) keys.next();
JSONObject qJson = jObject.getJSONObject(qName);
File qDir = Paths.get(questionsDir.getAbsolutePath(), qName)
.toFile();
if (qDir.exists()) {
throw new FileExistsException("Question " + qName
+ " already exists for analysis " + aName);
}
if (!qDir.mkdirs()) {
throw new Exception("failed to create question directory "
+ qDir.getAbsolutePath());
}
File qFile = Paths
.get(qDir.getAbsolutePath(), BfConsts.RELPATH_QUESTION_FILE)
.toFile();
FileUtils.writeStringToFile(qFile, qJson.toString(1));
}
}
if (delQuestionsStr != null && !delQuestionsStr.equals("")) {
JSONArray delQuestionsArray = new JSONArray(delQuestionsStr);
for (int index = 0; index < delQuestionsArray.length(); index++) {
String qName = delQuestionsArray.getString(index);
File qDir = Paths.get(questionsDir.getAbsolutePath(), qName)
.toFile();
if (!qDir.exists()) {
throw new FileExistsException("Question " + qName
+ " does not exist for analysis " + aName);
}
FileUtils.deleteDirectory(qDir);
}
}
}
public void delAnalysis(String containerName, String aName)
throws Exception {
File aDir = getdirContainerAnalysis(containerName, aName);
FileUtils.deleteDirectory(aDir);
}
public void delContainer(String containerName) throws Exception {
File containerDir = getdirContainer(containerName);
FileUtils.deleteDirectory(containerDir);
}
public void delEnvironment(String containerName, String testrigName,
String envName) throws Exception {
File envDir = getdirEnvironment(containerName, testrigName, envName);
FileUtils.deleteDirectory(envDir);
}
public void delTestrig(String containerName, String testrigName)
throws Exception {
File testrigDir = getdirTestrig(containerName, testrigName);
FileUtils.deleteDirectory(testrigDir);
}
public void delTestrigQuestion(String containerName, String testrigName,
String qName) throws Exception {
File qDir = getdirTestrigQuestion(containerName, testrigName, qName);
FileUtils.deleteDirectory(qDir);
}
// public String getAnswer(String containerName, String testrigName,
// String analysisName, String questionName) throws FileNotFoundException {
//
// File questionDir = getExistingTestrigQuestionDir(containerName,
// analysisName, questionName);
//
// File questionFile = Paths.get(questionDir.getAbsolutePath(),
// BfConsts.RELPATH_QUESTION_FILE).toFile();
// if (!questionFile.exists()) {
// throw new FileNotFoundException(
// "Question file not found for " + questionName);
// }
//
// File answerDir = getExistingAnalysisAnswerDir(containerName, testrigName,
// analysisName, questionName);
//
// File answerFile = Paths.get(answerDir.getAbsolutePath(),
// BfConsts.RELPATH_ANSWER_JSON).toFile();
// if (!answerFile.exists()) {
// return null;
// }
//
// if (answerFile.lastModified() < questionFile.lastModified()) {
// throw new FileNotFoundException("The answer file is stale");
// }
//
// return CommonUtil.readFile(answerFile.toPath());
// }
public Map<String, String> getAnalysisAnswers(String containerName,
String baseTestrig, String baseEnv, String deltaTestrig,
String deltaEnv, String analysisName, boolean pretty)
throws FileNotFoundException {
File analysisDir = getdirContainerAnalysis(containerName, analysisName);
File testrigDir = getdirTestrig(containerName, baseTestrig);
String[] questions = listAnalysisQuestions(containerName, analysisName);
Map<String, String> retMap = new TreeMap<>();
for (String questionName : questions) {
String answer = "unknown";
File questionFile = Paths.get(analysisDir.getAbsolutePath(),
BfConsts.RELPATH_QUESTIONS_DIR, questionName,
BfConsts.RELPATH_QUESTION_FILE).toFile();
if (!questionFile.exists()) {
throw new FileNotFoundException(
"Question file for question " + questionName + "not found");
}
String answerFilename = pretty ? BfConsts.RELPATH_ANSWER_PRETTY_JSON
: BfConsts.RELPATH_ANSWER_JSON;
Path answerDir = Paths.get(testrigDir.getAbsolutePath(),
BfConsts.RELPATH_ANALYSES_DIR, analysisName,
BfConsts.RELPATH_QUESTIONS_DIR, questionName,
BfConsts.RELPATH_ENVIRONMENTS_DIR, baseEnv);
if (deltaTestrig != null) {
answerDir = answerDir.resolve(
Paths.get(BfConsts.RELPATH_DELTA, deltaTestrig, deltaEnv)
.toString());
}
File answerFile = answerDir.resolve(answerFilename).toFile();
if (!answerFile.exists()) {
answer = "Not answered";
}
else {
if (questionFile.lastModified() > answerFile.lastModified()) {
answer = "Not fresh";
}
else {
answer = CommonUtil.readFile(answerFile.toPath());
}
}
retMap.put(questionName, answer);
}
return retMap;
}
public String getAnalysisQuestion(String containerName, String analysisName,
String questionName) throws Exception {
File questionDir = getdirAnalysisQuestion(containerName, analysisName,
questionName);
Path qFile = Paths.get(questionDir.getAbsolutePath(),
BfConsts.RELPATH_QUESTION_FILE);
if (!qFile.toFile().exists()) {
throw new FileExistsException(
"Question file not found for " + questionName);
}
return CommonUtil.readFile(qFile);
}
public String getAnswer(String containerName, String baseTestrig,
String baseEnv, String deltaTestrig, String deltaEnv,
String questionName, boolean pretty) throws FileNotFoundException {
File questionDir = getdirTestrigQuestion(containerName, baseTestrig,
questionName);
File questionFile = Paths
.get(questionDir.getAbsolutePath(), BfConsts.RELPATH_QUESTION_FILE)
.toFile();
if (!questionFile.exists()) {
throw new FileNotFoundException(
"Question file not found for " + questionName);
}
Path answerDir = Paths.get(questionDir.getAbsolutePath(),
BfConsts.RELPATH_ENVIRONMENTS_DIR, baseEnv);
if (deltaTestrig != null) {
answerDir = answerDir.resolve(Paths.get(answerDir.toString(),
BfConsts.RELPATH_DELTA, deltaTestrig, deltaEnv));
}
String answerFilename = pretty ? BfConsts.RELPATH_ANSWER_PRETTY_JSON
: BfConsts.RELPATH_ANSWER_JSON;
File answerFile = answerDir.resolve(answerFilename).toFile();
String answer = "unknown";
if (!answerFile.exists()) {
answer = "Not answered";
}
else {
if (questionFile.lastModified() > answerFile.lastModified()) {
answer = "Not fresh";
}
else {
answer = CommonUtil.readFile(answerFile.toPath());
}
}
return answer;
}
private File getdirAnalysisQuestion(String containerName,
String analysisName, String qName) throws FileNotFoundException {
File analysisDir = getdirContainerAnalysis(containerName, analysisName);
File qDir = Paths.get(analysisDir.getAbsolutePath(),
BfConsts.RELPATH_QUESTIONS_DIR, qName).toFile();
if (!qDir.exists()) {
throw new FileNotFoundException(
"Question " + qName + " does not exist");
}
return qDir;
}
private File getdirContainer(String containerName)
throws FileNotFoundException {
File containerDir = Paths
.get(Main.getSettings().getContainersLocation(), containerName)
.toFile();
if (!containerDir.exists()) {
throw new FileNotFoundException(
"Container " + containerName + " does not exist");
}
return containerDir;
}
private File getdirContainerAnalysis(String containerName,
String analysisName) throws FileNotFoundException {
File containerDir = getdirContainer(containerName);
File aDir = Paths.get(containerDir.getAbsolutePath(),
BfConsts.RELPATH_ANALYSES_DIR, analysisName).toFile();
if (!aDir.exists()) {
throw new FileNotFoundException("Analysis " + analysisName
+ " does not exists for container " + containerName);
}
return aDir;
}
private File getdirEnvironment(String containerName, String testrigName,
String envName) throws FileNotFoundException {
File testrigDir = getdirTestrig(containerName, testrigName);
File envDir = Paths.get(testrigDir.getAbsolutePath(),
BfConsts.RELPATH_ENVIRONMENTS_DIR, envName).toFile();
if (!envDir.exists()) {
throw new FileNotFoundException(
"Environment " + envName + " does not exist");
}
return envDir;
}
private File getdirTestrig(String containerName, String testrigName)
throws FileNotFoundException {
File containerDir = getdirContainer(containerName);
File testrigDir = Paths.get(containerDir.getAbsolutePath(),
BfConsts.RELPATH_TESTRIGS_DIR, testrigName).toFile();
if (!testrigDir.exists()) {
throw new FileNotFoundException(
"testrig " + testrigName + " does not exist");
}
return testrigDir;
}
private File getdirTestrigQuestion(String containerName, String testrigName,
String qName) throws FileNotFoundException {
File testrigDir = getdirTestrig(containerName, testrigName);
File qDir = Paths.get(testrigDir.getAbsolutePath(),
BfConsts.RELPATH_QUESTIONS_DIR, qName).toFile();
if (!qDir.exists()) {
throw new FileNotFoundException(
"Question " + qName + " does not exist");
}
return qDir;
}
public JSONObject getStatusJson() throws JSONException {
return _workQueueMgr.getStatusJson();
}
public String getTestrigInfo(String containerName, String testrigName)
throws Exception {
File testrigDir = getdirTestrig(containerName, testrigName);
File submittedTestrigDir = Paths
.get(testrigDir.getAbsolutePath(), BfConsts.RELPATH_TEST_RIG_DIR)
.toFile();
if (!submittedTestrigDir.exists()) {
return "Missing folder " + BfConsts.RELPATH_TEST_RIG_DIR + " for testrig " + testrigName + "\n";
}
StringBuilder retStringBuilder = new StringBuilder();
File[] subFiles = submittedTestrigDir.listFiles();
Arrays.sort(subFiles);
for (File subFile : subFiles) {
retStringBuilder.append(subFile.getName());
if (subFile.isDirectory()) {
File[] subSubFiles = subFile.listFiles();
Arrays.sort(subSubFiles);
retStringBuilder.append("/\n");
// now append a maximum of 10
for (int index = 0; index < subSubFiles.length
&& index < 10; index++) {
retStringBuilder
.append(" " + subSubFiles[index].getName() + "\n");
}
if (subSubFiles.length > 10) {
retStringBuilder.append(" ...... " + (subSubFiles.length - 10)
+ " more entries\n");
}
}
else {
retStringBuilder.append("\n");
}
}
return retStringBuilder.toString();
}
public File getTestrigObject(String containerName, String testrigName,
String objectName) throws Exception {
File testrigDir = getdirTestrig(containerName, testrigName);
File file = Paths.get(testrigDir.getAbsolutePath(), objectName).toFile();
// check if we got an object name outside of the testrig folder,
// perhaps because of ".." in the name; disallow it
if (!file.getCanonicalPath().contains(testrigDir.getCanonicalPath())) {
throw new AccessControlException("Illegal object name: " + objectName);
}
if (file.isFile()) {
return file;
}
else if (file.isDirectory()) {
File zipfile = new File(file.getAbsolutePath() + ".zip");
if (zipfile.exists()) {
zipfile.delete();
}
// AppZip appZip = new AppZip();
// appZip.zip();
ZipUtility.zipFiles(file.getAbsolutePath(), zipfile.getAbsolutePath());
// TODO: delete the zipfile
return zipfile;
}
return null;
}
public QueuedWork getWork(UUID workItemId) {
return _workQueueMgr.getWork(workItemId);
}
public String initContainer(String containerPrefix) throws Exception {
String containerName = containerPrefix + "_" + UUID.randomUUID();
File containerDir = Paths
.get(Main.getSettings().getContainersLocation(), containerName)
.toFile();
if (containerDir.exists()) {
throw new FileExistsException(
"Container " + containerName + " already exists!");
}
if (!containerDir.mkdirs()) {
throw new Exception(
"failed to create directory " + containerDir.getAbsolutePath());
}
return containerName;
}
private boolean isEnvFile(File file) {
String name = file.getName();
return ENV_FILENAMES.contains(name);
}
public String[] listAnalyses(String containerName) throws Exception {
File containerDir = getdirContainer(containerName);
File analysesDir = Paths
.get(containerDir.getAbsolutePath(), BfConsts.RELPATH_ANALYSES_DIR)
.toFile();
if (!analysesDir.exists()) {
return new String[0];
}
String[] directories = analysesDir.list(new FilenameFilter() {
@Override
public boolean accept(File current, String name) {
return new File(current, name).isDirectory();
}
});
return directories;
}
public String[] listAnalysisQuestions(String containerName,
String analysisName) throws FileNotFoundException {
File analysisDir = getdirContainerAnalysis(containerName, analysisName);
File questionsDir = Paths
.get(analysisDir.getAbsolutePath(), BfConsts.RELPATH_QUESTIONS_DIR)
.toFile();
if (!questionsDir.exists()) {
return new String[0];
}
String[] directories = questionsDir.list(new FilenameFilter() {
@Override
public boolean accept(File current, String name) {
return new File(current, name).isDirectory();
}
});
return directories;
}
public String[] listContainers(String apiKey) throws Exception {
File containersDir = new File(Main.getSettings().getContainersLocation());
if (!containersDir.exists()) {
containersDir.mkdirs();
}
List<String> containers = new ArrayList<>();
File[] files = containersDir.listFiles();
Arrays.sort(files);
for (File file : files) {
if (file.isDirectory() && Main.getAuthorizer()
.isAccessibleContainer(apiKey, file.getName(), false)) {
containers.add(file.getName());
}
}
return containers.toArray(new String[containers.size()]);
}
public String[] listEnvironments(String containerName, String testrigName)
throws Exception {
File testrigDir = getdirTestrig(containerName, testrigName);
File environmentsDir = Paths.get(testrigDir.getAbsolutePath(),
BfConsts.RELPATH_ENVIRONMENTS_DIR).toFile();
if (!environmentsDir.exists()) {
return new String[0];
}
String[] directories = environmentsDir.list(new FilenameFilter() {
@Override
public boolean accept(File current, String name) {
return new File(current, name).isDirectory();
}
});
return directories;
}
public String[] listQuestions(String containerName, String testrigName)
throws Exception {
File testrigDir = getdirTestrig(containerName, testrigName);
File questionsDir = Paths
.get(testrigDir.getAbsolutePath(), BfConsts.RELPATH_QUESTIONS_DIR)
.toFile();
if (!questionsDir.exists()) {
return new String[0];
}
String[] directories = questionsDir.list(new FilenameFilter() {
@Override
public boolean accept(File current, String name) {
return new File(current, name).isDirectory();
}
});
return directories;
}
public String[] listTestrigs(String containerName) throws Exception {
File containerDir = getdirContainer(containerName);
File testrigsDir = Paths
.get(containerDir.getAbsolutePath(), BfConsts.RELPATH_TESTRIGS_DIR)
.toFile();
if (!testrigsDir.exists()) {
return new String[0];
}
String[] directories = containerDir.list(new FilenameFilter() {
@Override
public boolean accept(File current, String name) {
return new File(current, name).isDirectory();
}
});
return directories;
}
private void moveByCopy(File srcFile, File destFile) throws IOException {
if (srcFile.isDirectory()) {
FileUtils.copyDirectory(srcFile, destFile);
FileUtils.deleteDirectory(srcFile);
}
else {
FileUtils.copyFile(srcFile, destFile);
if (!srcFile.delete()) {
throw new IOException(
"Failed to delete srcFile: " + srcFile.toString());
}
}
}
public void putObject(String containerName, String testrigName,
String objectName, InputStream fileStream) throws Exception {
File testrigDir = getdirTestrig(containerName, testrigName);
File file = Paths.get(testrigDir.getAbsolutePath(), objectName).toFile();
// check if we got an object name outside of the testrig folder,
// perhaps because of ".." in the name; disallow it
if (!file.getCanonicalPath().contains(testrigDir.getCanonicalPath())) {
throw new Exception("Illegal object name: " + objectName);
}
File parentFolder = file.getParentFile();
if (!parentFolder.exists()) {
if (!parentFolder.mkdirs()) {
throw new Exception("failed to create directory "
+ parentFolder.getAbsolutePath());
}
}
else {
if (!parentFolder.isDirectory()) {
throw new Exception(parentFolder.getAbsolutePath()
+ " already exists but is not a folder");
}
}
try (OutputStream fileOutputStream = new FileOutputStream(file)) {
int read = 0;
final byte[] bytes = new byte[1024];
while ((read = fileStream.read(bytes)) != -1) {
fileOutputStream.write(bytes, 0, read);
}
}
}
public boolean queueWork(WorkItem workItem) throws Exception {
File testrigDir = Paths
.get(Main.getSettings().getContainersLocation(),
workItem.getContainerName(), workItem.getTestrigName())
.toFile();
if (workItem.getTestrigName().isEmpty() || !testrigDir.exists()) {
throw new Exception("Non-existent testrig");
}
boolean success = _workQueueMgr
.queueUnassignedWork(new QueuedWork(workItem));
// as an optimization trigger AssignWork to see if we can schedule this
// (or another) work
if (success) {
Thread thread = new Thread() {
@Override
public void run() {
assignWork();
}
};
thread.start();
}
return success;
}
public void startWorkManager() {
// for some bizarre reason, this ordering of scheduling checktask before
// assignwork, is important
// in the other order, assignwork never fires
// TODO: track this down
// _checkWorkTask = new CheckTaskTask();
// _checkService = Executors.newScheduledThreadPool(1);
// _checkFuture = _checkService.scheduleAtFixedRate(_checkWorkTask, 0,
// Main.getSettings().getPeriodCheckWorkMs(),
// TimeUnit.MILLISECONDS);
Executors.newScheduledThreadPool(1).scheduleAtFixedRate(
new AssignWorkTask(), 0, Main.getSettings().getPeriodAssignWorkMs(),
TimeUnit.MILLISECONDS);
}
public void uploadEnvironment(String containerName, String testrigName,
String envName, InputStream fileStream) throws Exception {
File testrigDir = getdirTestrig(containerName, testrigName);
File envDir = Paths.get(testrigDir.getAbsolutePath(),
BfConsts.RELPATH_ENVIRONMENTS_DIR, envName).toFile();
if (envDir.exists()) {
throw new FileExistsException(
"environment " + envName + " exists for testrig " + testrigName);
}
if (!envDir.mkdirs()) {
throw new Exception(
"failed to create directory " + envDir.getAbsolutePath());
}
File zipFile = Files
.createTempFile("coordinatortmpuploadenvironment", ".zip").toFile();
try (OutputStream fileOutputStream = new FileOutputStream(zipFile)) {
int read = 0;
final byte[] bytes = new byte[1024];
while ((read = fileStream.read(bytes)) != -1) {
fileOutputStream.write(bytes, 0, read);
}
}
// now unzip
File unzipDir = Paths
.get(envDir.getAbsolutePath(), BfConsts.RELPATH_ENV_DIR).toFile();
UnzipUtility unzipper = new UnzipUtility();
unzipper.unzip(zipFile, unzipDir.getAbsolutePath());
// sanity check what we got
// 1. there should be just one top-level folder
File[] fileList = unzipDir.listFiles();
if (fileList.length != 1 || !fileList[0].isDirectory()) {
FileUtils.deleteDirectory(envDir);
throw new Exception(
"Unexpected packaging of environment. There should be just one top-level folder");
}
File[] subFileList = fileList[0].listFiles();
// things look ok, now make the move
for (File file : subFileList) {
File target = Paths.get(unzipDir.toString(), file.getName()).toFile();
moveByCopy(file, target);
}
// delete the empty directory and the zip file
fileList[0].delete();
zipFile.delete();
}
public void uploadQuestion(String containerName, String testrigName,
String qName, InputStream fileStream, InputStream paramFileStream)
throws Exception {
File testrigDir = getdirTestrig(containerName, testrigName);
File qDir = Paths.get(testrigDir.getAbsolutePath(),
BfConsts.RELPATH_QUESTIONS_DIR, qName).toFile();
if (qDir.exists()) {
throw new FileExistsException(
"question " + qName + " exists for testrig " + testrigName);
}
if (!qDir.mkdirs()) {
throw new Exception(
"failed to create directory " + qDir.getAbsolutePath());
}
File file = Paths
.get(qDir.getAbsolutePath(), BfConsts.RELPATH_QUESTION_FILE)
.toFile();
try (OutputStream fileOutputStream = new FileOutputStream(file)) {
int read = 0;
final byte[] bytes = new byte[1024];
while ((read = fileStream.read(bytes)) != -1) {
fileOutputStream.write(bytes, 0, read);
}
}
}
public void uploadTestrig(String containerName, String testrigName,
InputStream fileStream) throws Exception {
File containerDir = getdirContainer(containerName);
File testrigDir = Paths.get(containerDir.getAbsolutePath(),
BfConsts.RELPATH_TESTRIGS_DIR, testrigName).toFile();
if (testrigDir.exists()) {
throw new FileExistsException(
"Testrig with name " + testrigName + " already exists");
}
if (!testrigDir.mkdirs()) {
throw new Exception(
"failed to create directory " + testrigDir.getAbsolutePath());
}
File zipFile = Files.createTempFile("testrig", ".zip").toFile();
try (OutputStream fileOutputStream = new FileOutputStream(zipFile)) {
int read = 0;
final byte[] bytes = new byte[1024];
while ((read = fileStream.read(bytes)) != -1) {
fileOutputStream.write(bytes, 0, read);
}
}
// now unzip
File unzipDir = Paths
.get(testrigDir.getAbsolutePath(), BfConsts.RELPATH_TEST_RIG_DIR)
.toFile();
UnzipUtility unzipper = new UnzipUtility();
unzipper.unzip(zipFile, unzipDir.getAbsolutePath());
// sanity check what we got
// 1. there should be just one top-level folder
// 2. there should be a directory called configs in that folder
File[] fileList = unzipDir.listFiles();
if (fileList.length != 1 || !fileList[0].isDirectory()) {
FileUtils.deleteDirectory(testrigDir);
throw new Exception(
"Unexpected packaging of test rig. There should be just one top-level folder. Got "
+ fileList.length);
}
File[] subFileList = fileList[0].listFiles();
// boolean foundConfigs = false;
// for (File file : subFileList) {
// if (file.isDirectory() && file.getName().equals("configs")) {
// foundConfigs = true;
// break;
// }
// }
//
// if (!foundConfigs) {
// FileUtils.deleteDirectory(testrigDir);
// throw new Exception(
// "Unexpected packaging of test rig. Did not find configs folder inside
// the top-level folder");
// }
// create empty default environment
File defaultEnvironmentLeafDir = Paths.get(testrigDir.getAbsolutePath(),
BfConsts.RELPATH_ENVIRONMENTS_DIR,
BfConsts.RELPATH_DEFAULT_ENVIRONMENT_NAME, BfConsts.RELPATH_ENV_DIR)
.toFile();
defaultEnvironmentLeafDir.mkdirs();
// things look ok, now make the move
for (File file : subFileList) {
File target;
if (isEnvFile(file)) {
target = Paths.get(defaultEnvironmentLeafDir.getAbsolutePath(),
file.getName()).toFile();
}
else {
target = Paths.get(unzipDir.toString(), file.getName()).toFile();
}
moveByCopy(file, target);
}
// delete the empty directory and the zip file
fileList[0].delete();
zipFile.delete();
}
}