diff --git a/optimiser-controller/src/main/java/eu/nebulouscloud/optimiser/controller/AMPLGenerator.java b/optimiser-controller/src/main/java/eu/nebulouscloud/optimiser/controller/AMPLGenerator.java index 8edf851..98f9a98 100644 --- a/optimiser-controller/src/main/java/eu/nebulouscloud/optimiser/controller/AMPLGenerator.java +++ b/optimiser-controller/src/main/java/eu/nebulouscloud/optimiser/controller/AMPLGenerator.java @@ -2,6 +2,7 @@ package eu.nebulouscloud.optimiser.controller; import java.io.PrintWriter; import java.io.StringWriter; +import java.util.ArrayList; import java.util.HashSet; import java.util.List; import java.util.Set; @@ -25,6 +26,17 @@ import static net.logstash.logback.argument.StructuredArguments.keyValue; */ @Slf4j public class AMPLGenerator { + + /** + * Generate the app's metric list. + */ + public static List getMetricList(NebulousApp app) { + List metrics = new ArrayList<>(); + app.getRawMetrics().forEach((k, v) -> metrics.add(k)); + app.getCompositeMetrics().forEach((k, v) -> metrics.add(k)); + return metrics; + } + /** * Generate AMPL code for the app, based on the parameter definition(s). * Public for testability, not because we'll be calling it outside of its @@ -172,7 +184,7 @@ public class AMPLGenerator { out.format("param %s; # %s%n", name, m.get("name").asText()); } } - + out.println("## Composite metrics"); for (final JsonNode m : app.getCompositeMetrics().values()) { String name = m.get("name").asText(); @@ -216,7 +228,7 @@ public class AMPLGenerator { if (allMetrics.contains(name)) result.add(name); }); } - + return result; } @@ -282,7 +294,7 @@ public class AMPLGenerator { int lengthDiff = 0; while (matcher.find()) { String var = matcher.group(1); - + JsonNode re = StreamSupport.stream(Spliterators.spliteratorUnknownSize(mappings.elements(), Spliterator.ORDERED), false) .filter(v -> v.at("/name").asText().equals(var)) .findFirst().orElse(null); diff --git a/optimiser-controller/src/main/java/eu/nebulouscloud/optimiser/controller/ExnConnector.java b/optimiser-controller/src/main/java/eu/nebulouscloud/optimiser/controller/ExnConnector.java index 9b8e18c..abf91d4 100644 --- a/optimiser-controller/src/main/java/eu/nebulouscloud/optimiser/controller/ExnConnector.java +++ b/optimiser-controller/src/main/java/eu/nebulouscloud/optimiser/controller/ExnConnector.java @@ -143,9 +143,9 @@ public class ExnConnector { labelNodes = new SyncedPublisher("labelNodes", "eu.nebulouscloud.exn.sal.cluster.label", true, true); deployCluster = new SyncedPublisher("deployCluster", "eu.nebulouscloud.exn.sal.cluster.deploy", true, true); deployApplication = new SyncedPublisher("deployApplication", "eu.nebulouscloud.exn.sal.cluster.deployapplication", true, true); - scaleOut = new SyncedPublisher("scaleOut", "eu.nebulouscloud.exn.sal.scale.out", true, true); - scaleIn = new SyncedPublisher("scaleIn", "eu.nebulouscloud.exn.sal.scale.in", true, true); - deleteCluster = new SyncedPublisher("deployCluster", "eu.nebulouscloud.exn.sal.cluster.delete", true, true); + scaleOut = new SyncedPublisher("scaleOut", "eu.nebulouscloud.exn.sal.cluster.scaleout", true, true); + scaleIn = new SyncedPublisher("scaleIn", "eu.nebulouscloud.exn.sal.cluster.scalein", true, true); + deleteCluster = new SyncedPublisher("deleteCluster", "eu.nebulouscloud.exn.sal.cluster.delete", true, true); conn = new Connector("optimiser_controller", callback, @@ -699,7 +699,7 @@ public class ExnConnector { superfluousNodes.forEach(nodeName -> body.add(nodeName)); Map msg; try { - msg = Map.of("metaData", Map.of("user", "admin"), + msg = Map.of("metaData", Map.of("user", "admin", "clusterName", clusterName), "body", mapper.writeValueAsString(body)); } catch (JsonProcessingException e) { log.error("Could not convert JSON to string (this should never happen)", diff --git a/optimiser-controller/src/main/java/eu/nebulouscloud/optimiser/controller/LocalExecution.java b/optimiser-controller/src/main/java/eu/nebulouscloud/optimiser/controller/LocalExecution.java index 0b481ff..f0fe0db 100644 --- a/optimiser-controller/src/main/java/eu/nebulouscloud/optimiser/controller/LocalExecution.java +++ b/optimiser-controller/src/main/java/eu/nebulouscloud/optimiser/controller/LocalExecution.java @@ -19,7 +19,7 @@ import picocli.CommandLine.ParentCommand; @Slf4j @Command(name = "local", aliases = {"l"}, - description = "Handle a single app creation message from the command line, printing its AMPL. If an ActiveMQ connection is specified, additionally send a message to the solver.", + description = "Start single app from the command line.", mixinStandardHelpOptions = true) public class LocalExecution implements Callable { @@ -28,8 +28,12 @@ public class LocalExecution implements Callable { @ParentCommand private Main main; - @Parameters(description = "The file containing a JSON app creation message") - private Path app_creation_msg; + @Parameters(description = "The file containing a JSON app creation message, as sent by the GUI") + private Path appCreationMessage; + + @Parameters(description = "The file containing a JSON performance indicator message, as sent by the utility evaluator") + private Path perfIndicatorMessage; + @Option(names = { "--deploy" }, description = "Deploy application (default true).", @@ -37,12 +41,6 @@ public class LocalExecution implements Callable { negatable = true) private boolean deploy; - @Option(names = { "--ampl" }, - description = "Send AMPL file to solver (default true).", - defaultValue = "true", fallbackValue = "true", - negatable = true) - private boolean sendAMPL; - @Override public Integer call() { ObjectMapper mapper = new ObjectMapper(); CountDownLatch exn_synchronizer = new CountDownLatch(1); @@ -50,24 +48,32 @@ public class LocalExecution implements Callable { if (connector != null) { connector.start(exn_synchronizer); } - JsonNode msg; + JsonNode app_msg = null; + JsonNode perf_msg = null; try { - msg = mapper.readTree(Files.readString(app_creation_msg, StandardCharsets.UTF_8)); + app_msg = mapper.readTree(Files.readString(appCreationMessage, StandardCharsets.UTF_8)); + perf_msg = mapper.readTree(Files.readString(perfIndicatorMessage, StandardCharsets.UTF_8)); } catch (IOException e) { - log.error("Could not read an input file: {}", app_creation_msg, e); + log.error("Could not read an input file: {}", + app_msg == null ? appCreationMessage : perfIndicatorMessage, e); return 1; } - NebulousApp app = NebulousApp.newFromAppMessage(msg, connector); + NebulousApp app = NebulousApp.newFromAppMessage(app_msg, connector); + app.setStateReady(perf_msg); if (connector != null) { - if (sendAMPL) { - log.debug("Sending AMPL to channel {}", connector.getAmplMessagePublisher()); - app.sendAMPL(); - System.out.println(AMPLGenerator.generateAMPL(app)); - } if (deploy) { log.debug("Deploying application", connector.getAmplMessagePublisher()); - app.setStateReady(null); // TODO: insert second file here app.deployUnmodifiedApplication(); + } else { + String ampl = AMPLGenerator.generateAMPL(app); + System.out.println("--------------------"); + System.out.println("AMPL"); + System.out.println("--------------------"); + System.out.println(ampl); + System.out.println("--------------------"); + System.out.println("Metrics"); + System.out.println("--------------------"); + AMPLGenerator.getMetricList(app).forEach(System.out::println); } } if (connector != null) { diff --git a/optimiser-controller/src/main/java/eu/nebulouscloud/optimiser/controller/NebulousApp.java b/optimiser-controller/src/main/java/eu/nebulouscloud/optimiser/controller/NebulousApp.java index 57d8868..273ef20 100644 --- a/optimiser-controller/src/main/java/eu/nebulouscloud/optimiser/controller/NebulousApp.java +++ b/optimiser-controller/src/main/java/eu/nebulouscloud/optimiser/controller/NebulousApp.java @@ -106,6 +106,7 @@ public class NebulousApp { private static final ObjectMapper yamlMapper = new ObjectMapper(new YAMLFactory()); /** General-purpose object mapper */ + @Getter private static final ObjectMapper jsonMapper = new ObjectMapper(); // ---------------------------------------- @@ -559,8 +560,7 @@ public class NebulousApp { Publisher metricsChannel = exnConnector.getMetricListPublisher(); ObjectNode msg = jsonMapper.createObjectNode(); ArrayNode metricNames = msg.withArray("/metrics"); - getRawMetrics().forEach((k, v) -> metricNames.add(k)); - getCompositeMetrics().forEach((k, v) -> metricNames.add(k)); + AMPLGenerator.getMetricList(this).forEach(metricNames::add); log.info("Sending metric list", keyValue("appId", UUID)); metricsChannel.send(jsonMapper.convertValue(msg, Map.class), getUUID(), true); Main.logFile("metric-names-" + getUUID() + ".json", msg.toPrettyString());