jobserv/src/main/java/JobServ/JobServClient.java
2019-05-23 23:29:41 -07:00

296 lines
8.5 KiB
Java

/*
* JobServClient
*
* v1.0
*
* May 18, 2019
*/
package JobServ;
import io.grpc.netty.GrpcSslContexts;
import io.grpc.ManagedChannel;
import java.util.InputMismatchException;
import io.grpc.ManagedChannelBuilder;
import io.netty.handler.ssl.SslContext;
import io.netty.handler.ssl.SslContextBuilder;
import javax.net.ssl.SSLException;
import io.grpc.netty.NettyChannelBuilder;
import java.util.Scanner;
import java.io.File;
/*
* The JobServClient class extends the gRPC stub code
* Additionally, it plugs a command line interface into the API code.
*/
public class JobServClient {
private final String serversideTimeoutErrorMessage = "Timeout locking process control on server\n"+
"Server could be under heavy load\nConsider trying again.";
private JobServClientAPIConnector api;
private String[] programArgs;
/*
* Constructor
* takes program arguments and an api connector object
*/
public JobServClient(String[] args, JobServClientAPIConnector api) {
this.programArgs = args;
this.api = api;
}
/*
* getPidArg()
* reentrant code was found in all commands except newjob
* this function pulls the pid argument and wraps around the integer cast
* returns -1 (an invalid PID) if bad index or unparsable int
*/
private int getPidArg(int index) {
if (this.programArgs.length < index) {
System.out.println("Improper formatting, try client --help");
return -1;
}
try {
return Integer.parseInt(this.programArgs[index]);
} catch (NumberFormatException e) {
System.out.println(this.programArgs[index] + " is not a valid integer");
return -1;
}
}
/*
* outputHelp()
* writes help information about all commands in the shell to screen
*/
public static void outputHelp() {
System.out.println("... new (command)\n"+
"Starts a new process on the server\n"+
"example: ./client key.pem cert.crt ca.crt localhost 8448 new echo hello world!\n\n"+
"... output (pid) (lines)\n"+
"Garners (lines) lines of output from process (pid) on server\n"+
"example: ./client key.pem cert.crt ca.crt localhost 8448 output 0 5\n\n"+
"... status (pid)\n"+
"Returns whether process on server is running"+
"example: ./client key.pem cert.crt ca.crt localhost 8448 status 0\n\n"+
"... return (pid)\n"+
"Collects return code from remote process\n"+
"example: ./client key.pem cert.crt ca.crt localhost 8448 return 0\n\n"+
"... kill (pid)"+
"Immediately destroys remote process"+
"example: ./client key.pem cert.crt ca.crt localhost 8448 kill 0\n\n");
}
/*
* makeNewProcess
* makes a new process
*/
public void makeNewProcess() {
String command = "";
for (int token = 6; token < this.programArgs.length; token++) {
command += " " + this.programArgs[token];
}
int newProcess = this.api.sendNewJobMessage(command);
switch(newProcess) {
case -1:
System.out.println("Server failed to spawn process. Bad command.");
break;
case -2:
// error logged by API Connector
break;
default:
System.out.printf("Process started, assigned pid is %d\n", newProcess);
break;
}
return;
}
/*
* getOutput
* gets output from a process
*/
public void getOutput() {
if (this.programArgs.length < 8) {
System.out.println("Improper formatting, need a lines and a pid argument.");
return;
}
int candidatePid = this.getPidArg(6);
int lines = this.getPidArg(7);
if (candidatePid < 0) {
return;
}
String processOutput = this.api.getProcessOutput(candidatePid, lines);
System.out.println(processOutput);
}
/*
* getStatus
* gets the running status of a process
*/
public void getStatus() {
int candidatePid = this.getPidArg(6);
if (candidatePid < 0) {
return;
}
int processStatus = this.api.getProcessStatus(candidatePid);
switch(processStatus) {
case 0:
System.out.println("Process is running");
break;
case 1:
System.out.println("Process is not running");
break;
case 2:
System.out.println("A client killed the process already");
break;
case 3:
System.out.println("Process does not exist");
break;
case 4:
System.out.println(this.serversideTimeoutErrorMessage);
break;
}
}
/*
* killProcess
* kills a process
*/
public void killProcess() {
int candidatePid = this.getPidArg(6);
if (candidatePid < 0) {
return;
}
int finalStatus = this.api.killProcess(candidatePid);
switch(finalStatus) {
case 0:
System.out.println("Process is still running");
break;
case 1:
System.out.println("Process was killed");
break;
case 2:
System.out.println("Process does not exist");
break;
case 3:
System.out.println(this.serversideTimeoutErrorMessage);
break;
case 4:
// error logged in API Connector
break;
}
}
/*
* getReturn
* gets return code from a process
*/
public void getReturn() {
int candidatePid = this.getPidArg(6);
if (candidatePid < 0) {
return;
}
int returnCode = this.api.getProcessReturn(candidatePid);
switch(returnCode){
case 256:
System.out.println("Process is still running");
break;
case 257:
System.out.println("Process was killed manually by a client");
break;
case 258:
System.out.println("Process does not exist");
break;
case 259:
System.out.println(this.serversideTimeoutErrorMessage);
break;
case 260:
// error logged in getProcesReturn
break;
default:
System.out.println("Process Exit Code: " + Integer.toString(returnCode));
}
}
/*
* main()
* Client entrypoint
* Parses arguments, initializes client, and calls the correct functions
*/
public static void main(String[] args) throws Exception {
// check args
if (args.length < 7) {
System.out.println("Usage: $ ./jobserv-client privatekey, cert, truststore, host, port, command, args");
System.out.println("Or try $ ./jobserv-client help");
outputHelp();
return;
}
JobServClientAPIConnector api;
try {
SslContextBuilder builder = GrpcSslContexts.forClient();
builder.trustManager(new File(args[2]));
builder.keyManager(new File(args[1]), new File(args[0]));
ManagedChannel channel = NettyChannelBuilder.forAddress(args[3], Integer.parseInt(args[4]))
.sslContext(builder.build())
.build();
api = new JobServClientAPIConnector(channel);
// Likely bad port
} catch (NumberFormatException e) {
System.out.println("Invalid Port");
return;
// bad cert or key format
} catch (SSLException e) {
System.out.println(e.getMessage());
return;
}
JobServClient client = new JobServClient(args, api);
// parse remaining args
switch (args[5]) {
case "new":
client.makeNewProcess();
break;
case "output":
client.getOutput();
break;
case "status":
client.getStatus();
break;
case "kill":
client.killProcess();
break;
case "return":
client.getReturn();
break;
default:
System.out.println("Improper command, try 'help'");
break;
}
}
}