Compare commits

..

10 commits

Author SHA1 Message Date
Aidan Hahn
92fb02b0bf
fixed manager trying to release locks it didnt have 2019-06-01 15:36:13 -07:00
Aidan Hahn
4aa0a648f9
forgot to set file to executable 2019-06-01 15:28:44 -07:00
Aidan Hahn
6a88ffdd03
deja vu... 2019-06-01 15:24:07 -07:00
Aidan Hahn
eaae46a452
merging in changes from master 2019-06-01 15:23:16 -07:00
Aidan Hahn
ee48ef241f
bring back buildwrapper as a wrapper for external scripts 2019-06-01 15:20:27 -07:00
Aidan Hahn
2582da5def Merge branch 'CICD' into 'master'
merge in refactored CI/CD

See merge request whom/jobserv!4
2019-06-01 22:15:57 +00:00
Aidan Hahn
e74c74b909 Merge branch 'raceConditions' into 'CICD'
Race conditions fixed, all tests in CI pass

See merge request whom/jobserv!5
2019-06-01 22:10:52 +00:00
Aidan Hahn
2deaff99f7
lol I forgot to actually release the lock 2019-06-01 15:03:18 -07:00
Aidan Hahn
18a7fcc0b3
refactored mutexes to use java ReentrantLock 2019-06-01 14:59:16 -07:00
Aidan Hahn
5871e1b152
fix test and deploy stages 2019-06-01 13:49:56 -07:00
6 changed files with 80 additions and 76 deletions

View file

@ -17,8 +17,13 @@ compile:
tests:
stage: test
script: "./gradlew test"
script:
- "./certs-gen.sh"
- "./gradlew test"
package:
stage: deploy
script: "./package.sh"
script:
- "./certs-gen.sh"
- "./gradlew build"
- "./package.sh"

5
buildwrapper.sh Executable file
View file

@ -0,0 +1,5 @@
#!/bin/sh
./certs-gen.sh
./gradlew clean build
./package.sh

View file

@ -13,6 +13,7 @@ if [ -z "$CLTNAME" ]; then
CLTNAME=localhost
fi
SERVER_CA_CN=jobserv-server-ca
SERVER_PATH=resources/server
CLIENT_CA_CN=jobserv-client-ca
@ -95,3 +96,4 @@ echo "[+] Converting private keys to X.509"
openssl pkcs8 -topk8 -nocrypt -in $CLIENT_PATH/private.key -out $CLIENT_PATH/private.pem
openssl pkcs8 -topk8 -nocrypt -in $SERVER_PATH/private.key -out $SERVER_PATH/private.pem
openssl pkcs8 -topk8 -nocrypt -in $TEST_PATH/private.key -out $TEST_PATH/private.pem

View file

@ -8,11 +8,14 @@
package JobServ;
import java.io.IOException;
import java.io.InputStream;
import java.io.OutputStream;
import java.io.IOException;
import java.io.InputStreamReader;
import java.io.BufferedReader;
import java.io.InputStreamReader;
import java.util.concurrent.locks.Lock;
import java.util.concurrent.TimeUnit;
import java.util.concurrent.locks.ReentrantLock;
/*
* ProcessController
@ -33,18 +36,23 @@ class ProcessController {
private BufferedReader reader;
private Process process;
private Boolean killedManually = false;
private Lock lock;
private int lockTimeout; // seconds
/*
* Constructor
* Takes a command and spawns it in a new process
* Redirects IO streams and assigns a fake PID
*/
public ProcessController(String command) throws IOException {
public ProcessController(String command, int lockTimeout) throws IOException {
this.pid = ProcessController.nextPid;
ProcessController.nextPid += 1;
this.lock = new ReentrantLock();
this.lockTimeout = lockTimeout;
this.process = Runtime.getRuntime().exec(command);
this.output = this.process.getOutputStream();
this.input = this.process.getInputStream();
@ -54,6 +62,28 @@ class ProcessController {
JobServServer.logger.write("Job " + String.valueOf(this.pid) + ": " + command);
}
/*
* getLock()
* attempts to get the lock for lockTimeout seconds
* or throws exceptions if interrupted
*/
public boolean getLock() throws InterruptedException {
return this.lock.tryLock(this.lockTimeout, TimeUnit.SECONDS);
}
/*
* releaseLock()
* releases lock on process
*/
public void releaseLock() {
try {
this.lock.unlock();
} catch (IllegalMonitorStateException e) {
JobServServer.logger.write("Thread tried to release a lock it didnt have! " + e.getMessage());
}
}
/*
* getPid()
* returns translated pid of this process

View file

@ -40,7 +40,6 @@ class ProcessManager {
* processMap
*/
protected ConcurrentHashMap<Integer, ProcessController> processMap;
protected ConcurrentHashMap<Integer, Boolean> lockMap;
private ExecutorService threadPool = Executors.newCachedThreadPool();
/*
@ -49,7 +48,6 @@ class ProcessManager {
*/
public ProcessManager() {
processMap = new ConcurrentHashMap<Integer, ProcessController>();
lockMap = new ConcurrentHashMap<Integer, Boolean>();
/* TODO: In a long running server over a large period of time
* It is possible that the streams used to redirect IO in the
* Processes may become a significant use of resources.
@ -68,12 +66,8 @@ class ProcessManager {
public int newProcess(String command) {
try {
ProcessController newProc = new ProcessController(command);
// we dont need to lock the map yet
this.lockMap.put(newProc.getPid(), true);
ProcessController newProc = new ProcessController(command, this.LOCK_TIMEOUT);
this.processMap.put(newProc.getPid(), newProc);
this.releaseLock(newProc.getPid());
return newProc.getPid();
} catch (IOException e) {
@ -95,14 +89,13 @@ class ProcessManager {
public int getProcessStatus(int pid) {
try {
if(!this.getLock(pid)) {
return 3;
// lock could not be grabbed before timeout
JobServServer.logger.write("Timeout getting process status: " + String.valueOf(pid));
return 4;
}
} catch (TimeoutException e) {
// lock could not be grabbed before timeout
JobServServer.logger.write("Timeout getting process " +
String.valueOf(pid) + " status: " + e.getMessage());
return 4;
} catch (IndexOutOfBoundsException e) {
return 3;
}
ProcessController candidate = this.processMap.get(pid);
@ -123,13 +116,12 @@ class ProcessManager {
public int getProcessReturn(int pid) {
try {
if(!this.getLock(pid)) {
return 258;
JobServServer.logger.write("Timeout getting process return: " + String.valueOf(pid));
return 259;
}
} catch (TimeoutException e) {
JobServServer.logger.write("Timeout getting process " +
String.valueOf(pid) + " return: " + e.getMessage());
return 259;
} catch (IndexOutOfBoundsException e) {
return 258;
}
ProcessController candidate = this.processMap.get(pid);
@ -146,13 +138,12 @@ class ProcessManager {
public String getProcessOutput(int pid, int lines) {
try {
if(!this.getLock(pid)) {
return "[-] SERVER: Process not found";
JobServServer.logger.write("Timeout getting process output: " + String.valueOf(pid));
return "[-] SERVER: Timeout grabbing lock to access process information";
}
} catch (TimeoutException e) {
JobServServer.logger.write("Timeout getting process " +
String.valueOf(pid) + " output: " + e.getMessage());
return "[-] SERVER: Timeout grabbing lock to access process information";
} catch (IndexOutOfBoundsException e) {
return "[-] SERVER: Process not found";
}
ProcessController candidate = this.processMap.get(pid);
@ -172,13 +163,13 @@ class ProcessManager {
public int killProcess(int pid) {
try {
if(!this.getLock(pid)) {
return 2;
JobServServer.logger.write("Timeout killing process: " + String.valueOf(pid));
return 3;
}
} catch (TimeoutException e) {
JobServServer.logger.write("Timeout killing process " +
String.valueOf(pid) + ": " + e.getMessage());
return 3;
} catch (IndexOutOfBoundsException e) {
return 2;
}
ProcessController candidate = this.processMap.get(pid);
@ -194,45 +185,20 @@ class ProcessManager {
* Function is synchronized to prevent multiple threads accessing the same lock at once
* (ConcurrentHashMap will report whatever lock value was last to successfully update)
*/
protected synchronized Boolean getLock(int pid) throws TimeoutException {
if (!lockMap.containsKey(pid)) {
return false;
protected synchronized Boolean getLock(int pid) throws IndexOutOfBoundsException {
ProcessController candidate = this.processMap.get(pid);
if (candidate == null) {
throw new IndexOutOfBoundsException();
}
Future<Object> future = this.threadPool.submit(
new Callable<Object>() {
public Object call() {
while(lockMap.get(pid)) {
continue; // spin!
}
lockMap.replace(pid, true);
return 1;
}
});
try {
future.get(this.LOCK_TIMEOUT, TimeUnit.SECONDS);
Boolean success = candidate.getLock();
return success;
} catch (InterruptedException e) {
JobServServer.logger.write("[!] Couldnt get lock " +
String.valueOf(pid) + ": "+ e.getMessage());
future.cancel(true);
// in case lock was grabbed after exception
this.releaseLock(pid);
return false;
} catch (ExecutionException e) {
JobServServer.logger.write("[!] Couldnt get lock " +
String.valueOf(pid) + ": "+ e.getMessage());
future.cancel(true);
// in case lock was grabbed after exception
this.releaseLock(pid);
return false;
// cancel the attempt to grab the lock
}
/*
@ -247,8 +213,6 @@ class ProcessManager {
* mediate access to the ProcessManager
* object for fresh calls as well.
*/
return true;
}
/*
@ -256,7 +220,13 @@ class ProcessManager {
* releases mutex so other threads can operate on processqueue
*/
protected void releaseLock(int pid) {
this.lockMap.put(pid, false);
ProcessController candidate = this.processMap.get(pid);
if (candidate == null) {
JobServServer.logger.write("Tried to release lock of process that doesnt exist!");
return;
}
candidate.releaseLock();
}
/*

View file

@ -27,18 +27,10 @@ class ProcessManagerTestImplementation extends ProcessManager {
super.releaseLock(pid);
} catch (TimeoutException e) {
System.err.println("[!!] Long Call wasnt able to grab lock!");
return;
} catch (InterruptedException e) {
super.releaseLock(pid); // this doesnt happen, dont cancel this task
System.err.println("[3] Released lock: interrupted");
return;
}
}
public Boolean reportLockState(int pid) {
return super.lockMap.get(pid);
}
}