diff --git a/controller/.env b/controller/.env
index 3fedf8df..22c10642 100644
--- a/controller/.env
+++ b/controller/.env
@@ -1,4 +1,4 @@
JOBS_MQ_URL=service_mq
JOBS_MQ_USER=guest
JOBS_MQ_PASSWORD=guest
-JOBS_MQ_PORT=guest
\ No newline at end of file
+JOBS_MQ_PORT=guest
diff --git a/controller/pom.xml b/controller/pom.xml
index ae52daef..09ea25a3 100644
--- a/controller/pom.xml
+++ b/controller/pom.xml
@@ -17,6 +17,11 @@
21
+
+ com.myjeeva.digitalocean
+ digitalocean-api-client
+ 2.15
+
org.springframework.boot
spring-boot-starter
diff --git a/controller/src/main/java/com/workup/controller/CLIHandler.java b/controller/src/main/java/com/workup/controller/CLIHandler.java
index 693265e3..c82bdd31 100644
--- a/controller/src/main/java/com/workup/controller/CLIHandler.java
+++ b/controller/src/main/java/com/workup/controller/CLIHandler.java
@@ -2,138 +2,209 @@
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 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 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!";
+ }
+ 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!";
+ }
+ 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!";
+ }
+
+ @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),
- "",
- 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 = "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";
}
- if (maxDBConn > 100 || maxDBConn < 1) {
- return "Error: Max threads must have a value between 1 and 100";
+
+ @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),
- "",
- 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 = "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!!";
}
- rabbitTemplate.convertAndSend(appQueueMap.get(app), "", ContinueRequest.builder().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!";
+ }
+ 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!!";
+ }
- @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!";
+ 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();
}
- 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 = "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";
}
- // 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!";
+
+ 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, and sets it to join the swarm with the token and the ip")
+ public String spawnMachine(String dropletName, String swarmToken, String swarmIP) {
+ 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);
+
+ String gistURL = "https://shorturl.at/ZEU34";
+
+ newDroplet.setUserData(
+ "#!/bin/bash\nwget -O /tmp/setupmachine.sh " + gistURL + " && cd /tmp && chmod +x setupmachine.sh && ./setupmachine.sh " + swarmToken + " " + swarmIP + " && touch /finished.txt ");
+
+ 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";
- }
+
}
diff --git a/controller/src/main/resources/application.properties b/controller/src/main/resources/application.properties
index d44c2a7f..79af63db 100644
--- a/controller/src/main/resources/application.properties
+++ b/controller/src/main/resources/application.properties
@@ -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
\ No newline at end of file