Skip to content

Commit

Permalink
added commands for spawning and listing droplets
Browse files Browse the repository at this point in the history
  • Loading branch information
Kemosalamy committed May 19, 2024
1 parent 4488b96 commit ec797e3
Show file tree
Hide file tree
Showing 4 changed files with 185 additions and 113 deletions.
2 changes: 1 addition & 1 deletion controller/.env
Original file line number Diff line number Diff line change
@@ -1,4 +1,4 @@
JOBS_MQ_URL=service_mq
JOBS_MQ_USER=guest
JOBS_MQ_PASSWORD=guest
JOBS_MQ_PORT=guest
JOBS_MQ_PORT=guest
5 changes: 5 additions & 0 deletions controller/pom.xml
Original file line number Diff line number Diff line change
Expand Up @@ -17,6 +17,11 @@
<java.version>21</java.version>
</properties>
<dependencies>
<dependency>
<groupId>com.myjeeva.digitalocean</groupId>
<artifactId>digitalocean-api-client</artifactId>
<version>2.15</version>
</dependency>
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter</artifactId>
Expand Down
290 changes: 178 additions & 112 deletions controller/src/main/java/com/workup/controller/CLIHandler.java
Original file line number Diff line number Diff line change
Expand Up @@ -2,138 +2,204 @@

import asg.cliche.CLIException;
import asg.cliche.Command;
import com.myjeeva.digitalocean.DigitalOcean;
import com.myjeeva.digitalocean.pojo.*;
import com.workup.shared.commands.controller.*;
import com.workup.shared.enums.ControllerQueueNames;

import java.io.IOException;
import java.util.HashMap;
import java.util.Map;

import javassist.*;
import org.apache.logging.log4j.Level;
import org.springframework.amqp.core.AmqpTemplate;
import org.springframework.beans.factory.annotation.Autowired;
import com.myjeeva.digitalocean.impl.DigitalOceanClient;
import org.springframework.core.env.Environment;
import com.myjeeva.digitalocean.pojo.Droplet;

public class CLIHandler {
@Autowired AmqpTemplate rabbitTemplate;
private static final Map<String, String> appQueueMap = new HashMap<>();

static {
appQueueMap.put("jobs", ControllerQueueNames.JOBS);
appQueueMap.put("users", ControllerQueueNames.USERS);
appQueueMap.put("payments", ControllerQueueNames.PAYMENTS);
appQueueMap.put("contracts", ControllerQueueNames.CONTRACTS);
}

@Command(description = "Set the maximum number of threads for a specific app")
public String maxThreads(String app, int maxThreads) throws CLIException {
app = app.toLowerCase();
if (!appQueueMap.containsKey(app)) {
return "Error: app can only be jobs, users, contracts or payments!";
@Autowired
AmqpTemplate rabbitTemplate;
@Autowired
Environment environment;
private static final Map<String, String> appQueueMap = new HashMap<>();

static {
appQueueMap.put("jobs", ControllerQueueNames.JOBS);
appQueueMap.put("users", ControllerQueueNames.USERS);
appQueueMap.put("payments", ControllerQueueNames.PAYMENTS);
appQueueMap.put("contracts", ControllerQueueNames.CONTRACTS);
}
rabbitTemplate.convertAndSend(
appQueueMap.get(app),
"",
SetMaxThreadsRequest.builder().withMaxThreads(maxThreads).build());
return "Command sent";
}

@Command(description = "Set the maximum number of DB connections for a specific app")
public String maxdb(String app, int maxDBConn) {
app = app.toLowerCase();
if (!appQueueMap.containsKey(app)) {
return "Error: app can only be jobs, users, contracts or payments!";

@Command(description = "Set the maximum number of threads for a specific app")
public String maxThreads(String app, int maxThreads) throws CLIException {
app = app.toLowerCase();
if (!appQueueMap.containsKey(app)) {
return "Error: app can only be jobs, users, contracts or payments!";
}
rabbitTemplate.convertAndSend(
appQueueMap.get(app),
"",
SetMaxThreadsRequest.builder().withMaxThreads(maxThreads).build());
return "Command sent";
}
if (maxDBConn > 100 || maxDBConn < 1) {
return "Error: Max threads must have a value between 1 and 100";

@Command(description = "Set the maximum number of DB connections for a specific app")
public String maxdb(String app, int maxDBConn) {
app = app.toLowerCase();
if (!appQueueMap.containsKey(app)) {
return "Error: app can only be jobs, users, contracts or payments!";
}
if (maxDBConn > 100 || maxDBConn < 1) {
return "Error: Max threads must have a value between 1 and 100";
}
rabbitTemplate.convertAndSend(
appQueueMap.get(app),
"",
SetMaxDBConnectionsRequest.builder().withMaxDBConnections(maxDBConn).build());
return "Command Sent!";
}
rabbitTemplate.convertAndSend(
appQueueMap.get(app),
"",
SetMaxDBConnectionsRequest.builder().withMaxDBConnections(maxDBConn).build());
return "Command Sent!";
}

@Command(description = "Adds a new command")
public String addCommand(String app, String commandName, String className) throws Exception {
return updateCommand(app, commandName, className);
}

@Command(description = "starts a specific app")
public String start(String app) {
app = app.toLowerCase();
if (!appQueueMap.containsKey(app)) {
return "Error: app can only be jobs, users, contracts or payments!";

@Command(description = "Adds a new command")
public String addCommand(String app, String commandName, String className) throws Exception {
return updateCommand(app, commandName, className);
}

rabbitTemplate.convertAndSend(appQueueMap.get(app), "", ContinueRequest.builder().build());
return "Command sent";
}
@Command(description = "starts a specific app")
public String start(String app) {
app = app.toLowerCase();
if (!appQueueMap.containsKey(app)) {
return "Error: app can only be jobs, users, contracts or payments!";
}

rabbitTemplate.convertAndSend(appQueueMap.get(app), "", ContinueRequest.builder().build());
return "Command sent";
}

@Command(description = "stops a specific app")
public String freeze(String app) {
app = app.toLowerCase();
if (!appQueueMap.containsKey(app)) {
return "Error: app can only be jobs, users, contracts or payments!";
@Command(description = "stops a specific app")
public String freeze(String app) {
app = app.toLowerCase();
if (!appQueueMap.containsKey(app)) {
return "Error: app can only be jobs, users, contracts or payments!";
}
rabbitTemplate.convertAndSend(appQueueMap.get(app), "", FreezeRequest.builder().build());
return "Command sent";
}
rabbitTemplate.convertAndSend(appQueueMap.get(app), "", FreezeRequest.builder().build());
return "Command sent";
}

@Command(description = "sets a logging level")
public String setLoggingLevel(String app, String level) {
app = app.toLowerCase();
if (!appQueueMap.containsKey(app)) {
return "Error: app can only be jobs, users, contracts or payments!";

@Command(description = "sets a logging level")
public String setLoggingLevel(String app, String level) {
app = app.toLowerCase();
if (!appQueueMap.containsKey(app)) {
return "Error: app can only be jobs, users, contracts or payments!";
}
// To throw an error in case an invalid level is provided :)
Level.valueOf(level);
rabbitTemplate.convertAndSend(
appQueueMap.get(app), "", SetLoggingLevelRequest.builder().withLevel(level).build());
return "Command sent!!";
}
// To throw an error in case an invalid level is provided :)
Level.valueOf(level);
rabbitTemplate.convertAndSend(
appQueueMap.get(app), "", SetLoggingLevelRequest.builder().withLevel(level).build());
return "Command sent!!";
}

@Command(description = "Updates an existing command")
public String updateCommand(String app, String commandName, String className) throws Exception {
app = app.toLowerCase();
if (!appQueueMap.containsKey(app)) {
return "Error: app can only be jobs, users, contracts or payments!";

@Command(description = "Updates an existing command")
public String updateCommand(String app, String commandName, String className) throws Exception {
app = app.toLowerCase();
if (!appQueueMap.containsKey(app)) {
return "Error: app can only be jobs, users, contracts or payments!";
}
try {
byte[] byteArray = getByteCode(commandName, className);
rabbitTemplate.convertAndSend(
appQueueMap.get(app),
"",
UpdateCommandRequest.builder()
.withCommandName(commandName)
.withClassName(className)
.withByteCode(byteArray)
.build());
} catch (Exception ex) {
ex.printStackTrace();
}
return "Command sent!!";
}

private byte[] getByteCode(String commandName, String className)
throws InstantiationException,
IllegalAccessException,
NotFoundException,
IOException,
CannotCompileException {
ClassPool pool = ClassPool.getDefault();
pool.insertClassPath(new ClassClassPath(ControllerApplication.class));
CtClass ctClass = pool.get(className);
// That's the compiled class byte code
return ctClass.toBytecode();
}

@Command(description = "Deletes an existing command")
public String deleteCommand(String app, String commandName) {
app = app.toLowerCase();
if (!appQueueMap.containsKey(app)) {
return "Error: app can only be jobs, users, contracts or payments!";
}
rabbitTemplate.convertAndSend(
appQueueMap.get(app), "", DeleteCommandRequest.builder().commandName(commandName).build());
return "Command sent";
}

private DigitalOceanClient setupClient() {
String apiToken = environment.getProperty("digitalocean.api.token");

DigitalOceanClient digitalOceanClient = new DigitalOceanClient(apiToken);

return digitalOceanClient;
}
try {
byte[] byteArray = getByteCode(commandName, className);
rabbitTemplate.convertAndSend(
appQueueMap.get(app),
"",
UpdateCommandRequest.builder()
.withCommandName(commandName)
.withClassName(className)
.withByteCode(byteArray)
.build());
} catch (Exception ex) {
ex.printStackTrace();

@Command(description = "Spawns a new droplet instance")
public String spawnMachine(String dropletName) {
DigitalOceanClient client = setupClient();

try {
Droplet newDroplet = new Droplet();
newDroplet.setName(dropletName);
newDroplet.setSize("s-4vcpu-8gb-240gb-intel");
newDroplet.setImage(new Image("ubuntu-24-04-x64")); // Replace with actual image ID
newDroplet.setRegion(new Region("lon1")); // Replace with actual region slug
newDroplet.setInstallMonitoring(true);

Droplet createdDroplet = client.createDroplet(newDroplet);

return "Created Droplet" + createdDroplet;

} catch (Exception e) {
e.printStackTrace();
return "ERROR: Failed to create droplet";
}


}
return "Command sent!!";
}

private byte[] getByteCode(String commandName, String className)
throws InstantiationException,
IllegalAccessException,
NotFoundException,
IOException,
CannotCompileException {
ClassPool pool = ClassPool.getDefault();
pool.insertClassPath(new ClassClassPath(ControllerApplication.class));
CtClass ctClass = pool.get(className);
// That's the compiled class byte code
return ctClass.toBytecode();
}

@Command(description = "Deletes an existing command")
public String deleteCommand(String app, String commandName) {
app = app.toLowerCase();
if (!appQueueMap.containsKey(app)) {
return "Error: app can only be jobs, users, contracts or payments!";

@Command(description = "Lists existing droplet instances")
public String listMachine() {

String apiToken = environment.getProperty("digitalocean.api.token");

DigitalOceanClient digitalOceanClient = new DigitalOceanClient(apiToken);


try {
Account account = digitalOceanClient.getAccountInfo();

Droplets droplets = digitalOceanClient.getAvailableDroplets(1, 10);
for (Droplet droplet : droplets.getDroplets()) {
System.out.println("Droplet: " + droplet);
}
} catch (Exception e) {
e.printStackTrace();
}


return "Listed Successfully";
}
rabbitTemplate.convertAndSend(
appQueueMap.get(app), "", DeleteCommandRequest.builder().commandName(commandName).build());
return "Command sent";
}

}
1 change: 1 addition & 0 deletions controller/src/main/resources/application.properties
Original file line number Diff line number Diff line change
Expand Up @@ -3,3 +3,4 @@ spring.rabbitmq.host=46.101.90.9
spring.rabbitmq.port=5672
spring.rabbitmq.username=guest
spring.rabbitmq.password=guest
digitalocean.api.token=dop_v1_de3cb0b48c1313eae0b98bbb438b614f221c18af0111bc3e1b5f5f0800240e6b

0 comments on commit ec797e3

Please sign in to comment.