summaryrefslogtreecommitdiffstats
path: root/controller-server
diff options
context:
space:
mode:
authorJon Marius Venstad <jonmv@users.noreply.github.com>2018-08-16 21:16:14 +0200
committerGitHub <noreply@github.com>2018-08-16 21:16:14 +0200
commitc255e79e890acaab18c73888a9f8ed142bfcae5d (patch)
tree1cc4612436eddd9eed6eaeaeff63b8e220da002c /controller-server
parent27fffd89c3432e6ff677d17aeab801e5132acec9 (diff)
parentaa98e37b26ad796f5d5b0efbcd74146615f314d3 (diff)
Merge pull request #6605 from vespa-engine/jvenstad/testrunner-logging
Jvenstad/testrunner logging
Diffstat (limited to 'controller-server')
-rw-r--r--controller-server/src/main/java/com/yahoo/vespa/hosted/controller/deployment/InternalStepRunner.java7
-rw-r--r--controller-server/src/main/java/com/yahoo/vespa/hosted/controller/deployment/Run.java20
-rw-r--r--controller-server/src/main/java/com/yahoo/vespa/hosted/controller/persistence/LogRecordSerializer.java64
-rw-r--r--controller-server/src/main/java/com/yahoo/vespa/hosted/controller/persistence/RunSerializer.java7
-rw-r--r--controller-server/src/test/java/com/yahoo/vespa/hosted/controller/deployment/InternalStepRunnerTest.java6
-rw-r--r--controller-server/src/test/java/com/yahoo/vespa/hosted/controller/persistence/LogSerializerTest.java65
-rw-r--r--controller-server/src/test/java/com/yahoo/vespa/hosted/controller/persistence/RunSerializerTest.java1
-rw-r--r--controller-server/src/test/java/com/yahoo/vespa/hosted/controller/persistence/testdata/logs.json32
-rw-r--r--controller-server/src/test/java/com/yahoo/vespa/hosted/controller/persistence/testdata/run-status.json1
-rw-r--r--controller-server/src/test/java/com/yahoo/vespa/hosted/controller/restapi/application/JobControllerApiHandlerHelperTest.java2
10 files changed, 186 insertions, 19 deletions
diff --git a/controller-server/src/main/java/com/yahoo/vespa/hosted/controller/deployment/InternalStepRunner.java b/controller-server/src/main/java/com/yahoo/vespa/hosted/controller/deployment/InternalStepRunner.java
index 2812ee0d4dd..f0258e2321d 100644
--- a/controller-server/src/main/java/com/yahoo/vespa/hosted/controller/deployment/InternalStepRunner.java
+++ b/controller-server/src/main/java/com/yahoo/vespa/hosted/controller/deployment/InternalStepRunner.java
@@ -25,7 +25,6 @@ import com.yahoo.vespa.hosted.controller.api.integration.zone.ZoneId;
import com.yahoo.vespa.hosted.controller.application.ApplicationPackage;
import com.yahoo.vespa.hosted.controller.application.ApplicationVersion;
import com.yahoo.vespa.hosted.controller.application.DeploymentJobs;
-import com.yahoo.vespa.hosted.controller.deployment.Step.Status;
import java.io.ByteArrayOutputStream;
import java.io.IOException;
@@ -57,9 +56,6 @@ import static com.yahoo.vespa.hosted.controller.deployment.RunStatus.error;
import static com.yahoo.vespa.hosted.controller.deployment.RunStatus.installationFailed;
import static com.yahoo.vespa.hosted.controller.deployment.RunStatus.running;
import static com.yahoo.vespa.hosted.controller.deployment.RunStatus.testFailure;
-import static com.yahoo.vespa.hosted.controller.deployment.Step.Status.failed;
-import static com.yahoo.vespa.hosted.controller.deployment.Step.Status.succeeded;
-import static com.yahoo.vespa.hosted.controller.deployment.Step.Status.unfinished;
import static java.util.logging.Level.INFO;
import static java.util.logging.Level.WARNING;
@@ -333,7 +329,6 @@ public class InternalStepRunner implements StepRunner {
case NOT_STARTED:
throw new IllegalStateException("Tester reports tests not started, even though they should have!");
case RUNNING:
- logger.log("Tests still running ...");
return Optional.empty();
case FAILURE:
logger.log("Tests failed.");
@@ -508,7 +503,7 @@ public class InternalStepRunner implements StepRunner {
}
static ByteArrayLogger of(ApplicationId id, JobType type, Step step) {
- return new ByteArrayLogger(parent, String.format(".%s.%s.%s", id.serializedForm(), type.jobName(), step));
+ return new ByteArrayLogger(parent, String.format(".%s.%s.%s", id.toString(), type.jobName(), step));
}
@Override
diff --git a/controller-server/src/main/java/com/yahoo/vespa/hosted/controller/deployment/Run.java b/controller-server/src/main/java/com/yahoo/vespa/hosted/controller/deployment/Run.java
index 0d7977c6a9d..70670430bf4 100644
--- a/controller-server/src/main/java/com/yahoo/vespa/hosted/controller/deployment/Run.java
+++ b/controller-server/src/main/java/com/yahoo/vespa/hosted/controller/deployment/Run.java
@@ -6,7 +6,6 @@ import com.yahoo.vespa.hosted.controller.api.integration.deployment.RunId;
import java.time.Instant;
import java.util.Collections;
import java.util.EnumMap;
-import java.util.EnumSet;
import java.util.List;
import java.util.Map;
import java.util.Optional;
@@ -31,22 +30,24 @@ public class Run {
private final Instant start;
private final Optional<Instant> end;
private final RunStatus status;
+ private final long lastTestRecord;
// For deserialisation only -- do not use!
- public Run(RunId id, Map<Step, Step.Status> steps, Versions versions,
- Instant start, Optional<Instant> end, RunStatus status) {
+ public Run(RunId id, Map<Step, Step.Status> steps, Versions versions, Instant start,
+ Optional<Instant> end, RunStatus status, long lastTestRecord) {
this.id = id;
this.steps = Collections.unmodifiableMap(new EnumMap<>(steps));
this.versions = versions;
this.start = start;
this.end = end;
this.status = status;
+ this.lastTestRecord = lastTestRecord;
}
public static Run initial(RunId id, Versions versions, Instant now) {
EnumMap<Step, Step.Status> steps = new EnumMap<>(Step.class);
JobProfile.of(id.type()).steps().forEach(step -> steps.put(step, unfinished));
- return new Run(id, steps, requireNonNull(versions), requireNonNull(now), Optional.empty(), running);
+ return new Run(id, steps, requireNonNull(versions), requireNonNull(now), Optional.empty(), running, -1);
}
/** Returns a new Run with the new status, and with the status of the given, completed step set accordingly. */
@@ -60,21 +61,21 @@ public class Run {
EnumMap<Step, Step.Status> steps = new EnumMap<>(this.steps);
steps.put(step.get(), Step.Status.of(status));
- return new Run(id, steps, versions, start, end, this.status == running ? status : this.status); // Keep first terminal status.
+ return new Run(id, steps, versions, start, end, this.status == running ? status : this.status, lastTestRecord);
}
public Run finished(Instant now) {
if (hasEnded())
throw new AssertionError("This run ended at " + end.get() + " -- it can't be ended again!");
- return new Run(id, new EnumMap<>(steps), versions, start, Optional.of(now), status == running ? success : status);
+ return new Run(id, new EnumMap<>(steps), versions, start, Optional.of(now), status == running ? success : status, lastTestRecord);
}
public Run aborted() {
if (hasEnded())
throw new AssertionError("This run ended at " + end.get() + " -- it can't be aborted now!");
- return new Run(id, new EnumMap<>(steps), versions, start, end, aborted);
+ return new Run(id, new EnumMap<>(steps), versions, start, end, aborted, lastTestRecord);
}
/** Returns the id of this run. */
@@ -116,6 +117,11 @@ public class Run {
return versions;
}
+ /** Returns the sequence id of the last test record received from the tester, for the test logs of this run. */
+ public long lastTestRecord() {
+ return lastTestRecord;
+ }
+
@Override
public boolean equals(Object o) {
if (this == o) return true;
diff --git a/controller-server/src/main/java/com/yahoo/vespa/hosted/controller/persistence/LogRecordSerializer.java b/controller-server/src/main/java/com/yahoo/vespa/hosted/controller/persistence/LogRecordSerializer.java
new file mode 100644
index 00000000000..f582b240260
--- /dev/null
+++ b/controller-server/src/main/java/com/yahoo/vespa/hosted/controller/persistence/LogRecordSerializer.java
@@ -0,0 +1,64 @@
+package com.yahoo.vespa.hosted.controller.persistence;
+
+import com.google.common.collect.ImmutableList;
+import com.google.common.collect.ImmutableMap;
+import com.yahoo.log.LogLevel;
+import com.yahoo.slime.ArrayTraverser;
+import com.yahoo.slime.Cursor;
+import com.yahoo.slime.Inspector;
+import com.yahoo.slime.ObjectTraverser;
+import com.yahoo.slime.Slime;
+import com.yahoo.vespa.hosted.controller.deployment.Step;
+
+import java.util.List;
+import java.util.Map;
+import java.util.logging.LogRecord;
+
+/**
+ * Serialisation of LogRecord objects. Not all fields are stored!
+ *
+ * @author jonmv
+ */
+class LogRecordSerializer {
+
+ private static final String idField = "id";
+ private static final String levelField = "level";
+ private static final String timestampField = "at";
+ private static final String messageField = "message";
+
+ Slime recordsToSlime(Map<Step, List<LogRecord>> stepRecords) {
+ Slime root = new Slime();
+ Cursor recordsObject = root.setObject();
+ stepRecords.forEach((step, records) -> {
+ Cursor recordsArray = recordsObject.setArray(RunSerializer.valueOf(step));
+ records.forEach(record -> toSlime(record, recordsArray.addObject()));
+ });
+ return root;
+ }
+
+ void toSlime(LogRecord record, Cursor recordObject) {
+ recordObject.setLong(idField, record.getSequenceNumber());
+ recordObject.setString(levelField, LogLevel.getVespaLogLevel(record.getLevel()).getName());
+ recordObject.setLong(timestampField, record.getMillis());
+ recordObject.setString(messageField, record.getMessage());
+ }
+
+ Map<Step, List<LogRecord>> recordsFromSlime(Slime slime) {
+ ImmutableMap.Builder<Step, List<LogRecord>> stepRecords = ImmutableMap.builder();
+ slime.get().traverse((ObjectTraverser) (step, recordsArray) -> {
+ ImmutableList.Builder<LogRecord> records = ImmutableList.builder();
+ recordsArray.traverse((ArrayTraverser) (__, recordObject) -> records.add(fromSlime(recordObject)));
+ stepRecords.put(RunSerializer.stepOf(step), records.build());
+ });
+ return stepRecords.build();
+ }
+
+ private LogRecord fromSlime(Inspector recordObject) {
+ LogRecord record = new LogRecord(LogLevel.parse(recordObject.field(levelField).asString()),
+ recordObject.field(messageField).asString());
+ record.setSequenceNumber(recordObject.field(idField).asLong());
+ record.setMillis(recordObject.field(timestampField).asLong());
+ return record;
+ }
+
+}
diff --git a/controller-server/src/main/java/com/yahoo/vespa/hosted/controller/persistence/RunSerializer.java b/controller-server/src/main/java/com/yahoo/vespa/hosted/controller/persistence/RunSerializer.java
index 12d629f334d..a71e6a393ac 100644
--- a/controller-server/src/main/java/com/yahoo/vespa/hosted/controller/persistence/RunSerializer.java
+++ b/controller-server/src/main/java/com/yahoo/vespa/hosted/controller/persistence/RunSerializer.java
@@ -51,7 +51,7 @@ import static com.yahoo.vespa.hosted.controller.deployment.Step.endTests;
*
* @author jonmv
*/
-public class RunSerializer {
+class RunSerializer {
private static final String stepsField = "steps";
private static final String applicationField = "id";
@@ -67,6 +67,7 @@ public class RunSerializer {
private static final String commitField = "commit";
private static final String buildField = "build";
private static final String sourceField = "source";
+ private static final String lastTestRecordField = "lastTestRecord";
Run runFromSlime(Slime slime) {
return runFromSlime(slime.get());
@@ -96,7 +97,8 @@ public class RunSerializer {
Optional.of(runObject.field(endField))
.filter(Inspector::valid)
.map(end -> Instant.ofEpochMilli(end.asLong())),
- runStatusOf(runObject.field(statusField).asString()));
+ runStatusOf(runObject.field(statusField).asString()),
+ runObject.field(lastTestRecordField).asLong());
}
private Versions versionsFromSlime(Inspector versionsObject) {
@@ -138,6 +140,7 @@ public class RunSerializer {
runObject.setLong(startField, run.start().toEpochMilli());
run.end().ifPresent(end -> runObject.setLong(endField, end.toEpochMilli()));
runObject.setString(statusField, valueOf(run.status()));
+ runObject.setLong(lastTestRecordField, run.lastTestRecord());
Cursor stepsObject = runObject.setObject(stepsField);
run.steps().forEach((step, status) -> stepsObject.setString(valueOf(step), valueOf(status)));
diff --git a/controller-server/src/test/java/com/yahoo/vespa/hosted/controller/deployment/InternalStepRunnerTest.java b/controller-server/src/test/java/com/yahoo/vespa/hosted/controller/deployment/InternalStepRunnerTest.java
index 84487b1802f..66756dc4415 100644
--- a/controller-server/src/test/java/com/yahoo/vespa/hosted/controller/deployment/InternalStepRunnerTest.java
+++ b/controller-server/src/test/java/com/yahoo/vespa/hosted/controller/deployment/InternalStepRunnerTest.java
@@ -304,7 +304,7 @@ public class InternalStepRunnerTest {
cloud.set("Failure!".getBytes(), TesterCloud.Status.FAILURE);
runner.run();
assertEquals(failed, jobs.run(id).get().steps().get(Step.endTests));
- assertLogMessages(id, Step.endTests, "Tests still running ...", "Tests failed.", "Failure!");
+ assertLogMessages(id, Step.endTests, "Tests failed.", "Failure!");
}
@Test
@@ -313,7 +313,7 @@ public class InternalStepRunnerTest {
cloud.set("Error!".getBytes(), TesterCloud.Status.ERROR);
runner.run();
assertEquals(failed, jobs.run(id).get().steps().get(Step.endTests));
- assertLogMessages(id, Step.endTests, "Tests still running ...", "Tester failed running its tests!", "Error!");
+ assertLogMessages(id, Step.endTests, "Tester failed running its tests!", "Error!");
}
@Test
@@ -335,7 +335,7 @@ public class InternalStepRunnerTest {
cloud.set("Success!".getBytes(), TesterCloud.Status.SUCCESS);
runner.run();
assertEquals(succeeded, jobs.run(id).get().steps().get(Step.endTests));
- assertLogMessages(id, Step.endTests, "Tests still running ...", "Tests still running ...", "Tests completed successfully.", "Success!");
+ assertLogMessages(id, Step.endTests, "Tests completed successfully.", "Success!");
}
private void assertLogMessages(RunId id, Step step, String... messages) {
diff --git a/controller-server/src/test/java/com/yahoo/vespa/hosted/controller/persistence/LogSerializerTest.java b/controller-server/src/test/java/com/yahoo/vespa/hosted/controller/persistence/LogSerializerTest.java
new file mode 100644
index 00000000000..554e30637f9
--- /dev/null
+++ b/controller-server/src/test/java/com/yahoo/vespa/hosted/controller/persistence/LogSerializerTest.java
@@ -0,0 +1,65 @@
+package com.yahoo.vespa.hosted.controller.persistence;
+
+import com.google.common.collect.ImmutableList;
+import com.google.common.collect.ImmutableMap;
+import com.yahoo.log.LogLevel;
+import com.yahoo.vespa.config.SlimeUtils;
+import com.yahoo.vespa.hosted.controller.deployment.Step;
+import org.junit.Test;
+
+import java.io.IOException;
+import java.nio.file.Files;
+import java.nio.file.Path;
+import java.nio.file.Paths;
+import java.util.List;
+import java.util.Map;
+import java.util.logging.Level;
+import java.util.logging.LogRecord;
+
+import static com.yahoo.vespa.hosted.controller.deployment.Step.deployReal;
+import static com.yahoo.vespa.hosted.controller.deployment.Step.deployTester;
+import static org.junit.Assert.assertEquals;
+
+/**
+ * @author jonmv
+ */
+public class LogSerializerTest {
+
+ private static final LogRecordSerializer serializer = new LogRecordSerializer();
+ private static final Path logsFile = Paths.get("src/test/java/com/yahoo/vespa/hosted/controller/persistence/testdata/logs.json");
+
+ @Test
+ public void testSerialization() throws IOException {
+ // Local, because it's not supposed to be used for anything else than verifying equality here!
+ class EgalitarianLogRecord extends LogRecord {
+ private EgalitarianLogRecord(Level level, String msg) {
+ super(level, msg);
+ }
+ @Override
+ public boolean equals(Object o) {
+ if ( ! (o instanceof LogRecord)) return false;
+ LogRecord record = (LogRecord) o;
+ return getSequenceNumber() == record.getSequenceNumber()
+ && getLevel() == record.getLevel()
+ && getMillis() == record.getMillis()
+ && getMessage().equals(record.getMessage());
+ }
+ @Override
+ public int hashCode() { throw new AssertionError(); }
+ }
+
+ LogRecord first = new EgalitarianLogRecord(LogLevel.INFO, "First"); first.setMillis( 0); first.setSequenceNumber(1);
+ LogRecord second = new EgalitarianLogRecord(LogLevel.INFO, "Second"); second.setMillis( 0); second.setSequenceNumber(2);
+ LogRecord third = new EgalitarianLogRecord(LogLevel.DEBUG, "Third"); third.setMillis(1000); third.setSequenceNumber(3);
+ LogRecord fourth = new EgalitarianLogRecord(LogLevel.WARNING, "Fourth"); fourth.setMillis(2000); fourth.setSequenceNumber(4);
+
+ Map<Step, List<LogRecord>> expected = ImmutableMap.of(deployReal, ImmutableList.of(first, third),
+ deployTester, ImmutableList.of(second, fourth));
+
+ Map<Step, List<LogRecord>> stepRecords = serializer.recordsFromSlime(SlimeUtils.jsonToSlime(Files.readAllBytes(logsFile)));
+ assertEquals(expected, stepRecords);
+
+ assertEquals(expected, serializer.recordsFromSlime(serializer.recordsToSlime(stepRecords)));
+ }
+
+}
diff --git a/controller-server/src/test/java/com/yahoo/vespa/hosted/controller/persistence/RunSerializerTest.java b/controller-server/src/test/java/com/yahoo/vespa/hosted/controller/persistence/RunSerializerTest.java
index 1085c2a1b70..10537f42c0b 100644
--- a/controller-server/src/test/java/com/yahoo/vespa/hosted/controller/persistence/RunSerializerTest.java
+++ b/controller-server/src/test/java/com/yahoo/vespa/hosted/controller/persistence/RunSerializerTest.java
@@ -66,6 +66,7 @@ public class RunSerializerTest {
assertEquals(start, run.start());
assertFalse(run.hasEnded());
assertEquals(running, run.status());
+ assertEquals(3, run.lastTestRecord());
assertEquals(ImmutableMap.<Step, Step.Status>builder()
.put(deployInitialReal, unfinished)
.put(installInitialReal, failed)
diff --git a/controller-server/src/test/java/com/yahoo/vespa/hosted/controller/persistence/testdata/logs.json b/controller-server/src/test/java/com/yahoo/vespa/hosted/controller/persistence/testdata/logs.json
new file mode 100644
index 00000000000..1135e63e464
--- /dev/null
+++ b/controller-server/src/test/java/com/yahoo/vespa/hosted/controller/persistence/testdata/logs.json
@@ -0,0 +1,32 @@
+{
+ "deployReal":
+ [
+ {
+ "id": 1,
+ "level": "info",
+ "at": 0,
+ "message": "First"
+ },
+ {
+ "id": 3,
+ "level": "debug",
+ "at": 1000,
+ "message": "Third"
+ }
+ ],
+ "deployTester":
+ [
+ {
+ "id": 2,
+ "level": "info",
+ "at": 0,
+ "message": "Second"
+ },
+ {
+ "id": 4,
+ "level": "warning",
+ "at": 2000,
+ "message": "Fourth"
+ }
+ ]
+} \ No newline at end of file
diff --git a/controller-server/src/test/java/com/yahoo/vespa/hosted/controller/persistence/testdata/run-status.json b/controller-server/src/test/java/com/yahoo/vespa/hosted/controller/persistence/testdata/run-status.json
index 31e57902d22..0e0149897fc 100644
--- a/controller-server/src/test/java/com/yahoo/vespa/hosted/controller/persistence/testdata/run-status.json
+++ b/controller-server/src/test/java/com/yahoo/vespa/hosted/controller/persistence/testdata/run-status.json
@@ -5,6 +5,7 @@
"number": 112358,
"start": 1196676930000,
"status": "running",
+ "lastTestRecord": 3,
"steps": {
"deployInitialReal": "unfinished",
"installInitialReal": "failed",
diff --git a/controller-server/src/test/java/com/yahoo/vespa/hosted/controller/restapi/application/JobControllerApiHandlerHelperTest.java b/controller-server/src/test/java/com/yahoo/vespa/hosted/controller/restapi/application/JobControllerApiHandlerHelperTest.java
index aff7d511d84..f0cb7ca645d 100644
--- a/controller-server/src/test/java/com/yahoo/vespa/hosted/controller/restapi/application/JobControllerApiHandlerHelperTest.java
+++ b/controller-server/src/test/java/com/yahoo/vespa/hosted/controller/restapi/application/JobControllerApiHandlerHelperTest.java
@@ -142,7 +142,7 @@ public class JobControllerApiHandlerHelperTest {
RunStatus status = end.isPresent() && lastStepStatus.equals(Optional.of(RunStatus.running))
? RunStatus.success
: lastStepStatus.orElse(RunStatus.running);
- return new Run(runId, stepStatusMap, versions, start, end, status);
+ return new Run(runId, stepStatusMap, versions, start, end, status, -1);
}
private void compare(HttpResponse response, String expected) {