Small fixes; handle metrics in local testing

Change-Id: I5481fa53baabc3a962dc84fdfd2ad8ef0888261a
This commit is contained in:
Rudi Schlatte 2024-04-19 16:00:08 +02:00
parent d59b05b342
commit 6e9d2d771f
4 changed files with 46 additions and 28 deletions

View File

@ -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<String> getMetricList(NebulousApp app) {
List<String> 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);

View File

@ -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<String, Object> 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)",

View File

@ -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<Integer> {
@ -28,8 +28,12 @@ public class LocalExecution implements Callable<Integer> {
@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<Integer> {
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<Integer> {
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) {

View File

@ -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());