summaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
-rw-r--r--cloud-tenant-cd/src/main/java/ai/vespa/hosted/cd/cloud/impl/VespaTestRuntime.java12
-rw-r--r--configserver/src/test/java/com/yahoo/vespa/config/server/deploy/HostedDeployTest.java26
-rw-r--r--controller-server/src/main/java/com/yahoo/vespa/hosted/controller/deployment/InternalStepRunner.java39
-rw-r--r--controller-server/src/main/java/com/yahoo/vespa/hosted/controller/deployment/JobController.java10
-rw-r--r--controller-server/src/main/java/com/yahoo/vespa/hosted/controller/deployment/TestConfigSerializer.java14
-rw-r--r--controller-server/src/main/java/com/yahoo/vespa/hosted/controller/maintenance/JobRunner.java2
-rw-r--r--controller-server/src/main/java/com/yahoo/vespa/hosted/controller/restapi/application/ApplicationApiHandler.java12
-rw-r--r--controller-server/src/main/java/com/yahoo/vespa/hosted/controller/restapi/application/JobControllerApiHandlerHelper.java3
-rw-r--r--controller-server/src/test/java/com/yahoo/vespa/hosted/controller/deployment/DeploymentContext.java62
-rw-r--r--controller-server/src/test/java/com/yahoo/vespa/hosted/controller/deployment/DeploymentTester.java4
-rw-r--r--controller-server/src/test/java/com/yahoo/vespa/hosted/controller/deployment/InternalStepRunnerTest.java64
-rw-r--r--controller-server/src/test/java/com/yahoo/vespa/hosted/controller/deployment/TestConfigSerializerTest.java6
-rw-r--r--controller-server/src/test/java/com/yahoo/vespa/hosted/controller/restapi/application/responses/test-config-dev.json3
-rw-r--r--controller-server/src/test/java/com/yahoo/vespa/hosted/controller/restapi/application/responses/test-config.json3
-rw-r--r--controller-server/src/test/resources/testConfig.json3
-rw-r--r--hosted-api/src/main/java/ai/vespa/hosted/api/TestConfig.java26
-rw-r--r--hosted-api/src/test/java/ai/vespa/hosted/api/TestConfigTest.java4
-rw-r--r--hosted-api/src/test/resources/test-config.json3
-rw-r--r--tenant-cd-api/abi-spec.json8
-rw-r--r--tenant-cd-api/src/main/java/ai/vespa/hosted/cd/Deployment.java11
-rw-r--r--tenant-cd-api/src/main/java/ai/vespa/hosted/cd/TestRuntime.java3
-rw-r--r--tenant-cd-commons/src/main/java/ai/vespa/hosted/cd/commons/HttpDeployment.java25
-rw-r--r--vespa-osgi-testrunner/src/test/java/com/yahoo/vespa/test/samples/UsingTestRuntimeTest.java3
-rw-r--r--vespa-osgi-testrunner/src/test/java/com/yahoo/vespa/testrunner/JunitRunnerTest.java14
24 files changed, 261 insertions, 99 deletions
diff --git a/cloud-tenant-cd/src/main/java/ai/vespa/hosted/cd/cloud/impl/VespaTestRuntime.java b/cloud-tenant-cd/src/main/java/ai/vespa/hosted/cd/cloud/impl/VespaTestRuntime.java
index f4c8974a835..3088b5df74f 100644
--- a/cloud-tenant-cd/src/main/java/ai/vespa/hosted/cd/cloud/impl/VespaTestRuntime.java
+++ b/cloud-tenant-cd/src/main/java/ai/vespa/hosted/cd/cloud/impl/VespaTestRuntime.java
@@ -22,6 +22,7 @@ import java.nio.file.Paths;
* @author mortent
*/
public class VespaTestRuntime implements TestRuntime {
+
private final TestConfig config;
private final Deployment deploymentToTest;
@@ -42,7 +43,8 @@ public class VespaTestRuntime implements TestRuntime {
private VespaTestRuntime(TestConfig config) {
this.config = config;
DefaultEndpointAuthenticator authenticator = new DefaultEndpointAuthenticator(config.system());
- this.deploymentToTest = new HttpDeployment(config.deployments().get(config.zone()), authenticator);
+ this.deploymentToTest = new HttpDeployment(config.platformVersion(), config.applicationVersion(), config.deployedAt(),
+ config.deployments().get(config.zone()), authenticator);
FeedClientBuilder.setEndpointAuthenticator(authenticator);
ai.vespa.feed.client.FeedClientBuilder.setFeedClientBuilderSupplier(FeedClientBuilder::new);
}
@@ -54,6 +56,13 @@ public class VespaTestRuntime implements TestRuntime {
config.zone().region().value());
}
+ @Override
+ public ai.vespa.cloud.ApplicationId application() {
+ return new ai.vespa.cloud.ApplicationId(config.application().tenant().value(),
+ config.application().application().value(),
+ config.application().instance().value());
+ }
+
/** Returns the deployment this is testing. */
@Override
public Deployment deploymentToTest() { return deploymentToTest; }
@@ -93,4 +102,5 @@ public class VespaTestRuntime implements TestRuntime {
System.out.println("TestRuntime: Zone: " + zone.toString());
return controller.testConfig(id, zone);
}
+
}
diff --git a/configserver/src/test/java/com/yahoo/vespa/config/server/deploy/HostedDeployTest.java b/configserver/src/test/java/com/yahoo/vespa/config/server/deploy/HostedDeployTest.java
index 5dfc1bbd3ef..dbc7b5512be 100644
--- a/configserver/src/test/java/com/yahoo/vespa/config/server/deploy/HostedDeployTest.java
+++ b/configserver/src/test/java/com/yahoo/vespa/config/server/deploy/HostedDeployTest.java
@@ -277,6 +277,32 @@ public class HostedDeployTest {
* that are still using features that do not work on version 8.x)
*/
@Test
+ public void testFailingOnOldMajorButNotNewInUpgradeScenario() {
+ int oldMajor = 7;
+ int newMajor = 8;
+ Version wantedVersion = new Version(newMajor, 1, 2);
+ Version oldVersion = new Version(oldMajor, 2, 3);
+ List<Host> hosts = createHosts(9, oldVersion.toFullString(), wantedVersion.toFullString());
+
+ ModelFactory oldFactory = createFailingModelFactory(oldVersion);
+ ModelFactory newFactory = createHostedModelFactory(wantedVersion);
+ List<ModelFactory> modelFactories = List.of(oldFactory, newFactory);
+
+ DeployTester tester = createTester(hosts, modelFactories, prodZone);
+
+ tester.deployApp("src/test/apps/hosted/", wantedVersion.toFullString());
+
+ tester.deployApp("src/test/apps/hosted/", oldVersion.toFullString());
+
+ assertEquals(9, tester.getAllocatedHostsOf(tester.applicationId()).getHosts().size());
+ }
+
+ /**
+ * Tests that we create the minimal set of models and that version 7.x is created
+ * if creating version 8.x fails (to support upgrades to new major version for applications
+ * that are still using features that do not work on version 8.x)
+ */
+ @Test
public void testWantedVersionIsRequiredAlsoWhenThereIsAnOlderMajorThatDoesNotFailModelBuilding() {
int oldMajor = 7;
int newMajor = 8;
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 3105adb2488..813e3454e80 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
@@ -157,7 +157,7 @@ public class InternalStepRunner implements StepRunner {
}
private Optional<RunStatus> deployInitialReal(RunId id, DualLogger logger) {
- Versions versions = controller.jobController().run(id).get().versions();
+ Versions versions = controller.jobController().run(id).versions();
logger.log("Deploying platform version " +
versions.sourcePlatform().orElse(versions.targetPlatform()) +
" and application " +
@@ -166,16 +166,16 @@ public class InternalStepRunner implements StepRunner {
}
private Optional<RunStatus> deployReal(RunId id, DualLogger logger) {
- Versions versions = controller.jobController().run(id).get().versions();
+ Versions versions = controller.jobController().run(id).versions();
logger.log("Deploying platform version " + versions.targetPlatform() +
" and application " + versions.targetRevision() + " ...");
return deployReal(id, false, logger);
}
private Optional<RunStatus> deployReal(RunId id, boolean setTheStage, DualLogger logger) {
- Optional<X509Certificate> testerCertificate = controller.jobController().run(id).get().testerCertificate();
+ Optional<X509Certificate> testerCertificate = controller.jobController().run(id).testerCertificate();
return deploy(() -> controller.applications().deploy(id.job(), setTheStage),
- controller.jobController().run(id).get()
+ controller.jobController().run(id)
.stepInfo(setTheStage ? deployInitialReal : deployReal).get()
.startTime().get(),
logger)
@@ -184,8 +184,8 @@ public class InternalStepRunner implements StepRunner {
if ( ! useTesterCertificate(id) || result != running)
return true;
// If tester cert, ensure real is deployed with the tester cert whose key was successfully deployed.
- return controller.jobController().run(id).get().stepStatus(deployTester).get() == succeeded
- && testerCertificate.equals(controller.jobController().run(id).get().testerCertificate());
+ return controller.jobController().run(id).stepStatus(deployTester).get() == succeeded
+ && testerCertificate.equals(controller.jobController().run(id).testerCertificate());
});
}
@@ -196,7 +196,7 @@ public class InternalStepRunner implements StepRunner {
testerPackage(id),
id.type().zone(),
platform),
- controller.jobController().run(id).get()
+ controller.jobController().run(id)
.stepInfo(deployTester).get()
.startTime().get(),
logger);
@@ -287,10 +287,10 @@ public class InternalStepRunner implements StepRunner {
return Optional.of(installationFailed);
}
- Versions versions = controller.jobController().run(id).get().versions();
+ Versions versions = controller.jobController().run(id).versions();
Version platform = setTheStage ? versions.sourcePlatform().orElse(versions.targetPlatform()) : versions.targetPlatform();
- Run run = controller.jobController().run(id).get();
+ Run run = controller.jobController().run(id);
Optional<ServiceConvergence> services = controller.serviceRegistry().configServer().serviceConvergence(new DeploymentId(id.application(), id.type().zone()),
Optional.of(platform));
if (services.isEmpty()) {
@@ -409,14 +409,14 @@ public class InternalStepRunner implements StepRunner {
}
private Version testerPlatformVersion(RunId id) {
- Version targetPlatform = controller.jobController().run(id).get().versions().targetPlatform();
+ Version targetPlatform = controller.jobController().run(id).versions().targetPlatform();
Version systemVersion = controller.readSystemVersion();
boolean incompatible = controller.applications().versionCompatibility(id.application()).refuse(targetPlatform, systemVersion);
return incompatible || application(id.application()).change().isPinned() ? targetPlatform : systemVersion;
}
private Optional<RunStatus> installTester(RunId id, DualLogger logger) {
- Run run = controller.jobController().run(id).get();
+ Run run = controller.jobController().run(id);
Version platform = testerPlatformVersion(id);
ZoneId zone = id.type().zone();
ApplicationId testerId = id.tester().id();
@@ -608,6 +608,9 @@ public class InternalStepRunner implements StepRunner {
byte[] config = testConfigSerializer.configJson(id.application(),
id.type(),
true,
+ deployment.get().version(),
+ deployment.get().revision(),
+ deployment.get().at(),
endpoints,
controller.applications().reachableContentClustersByZone(deployments));
controller.jobController().cloud().startTests(getTesterDeploymentId(id), suite, config);
@@ -622,7 +625,7 @@ public class InternalStepRunner implements StepRunner {
return Optional.of(error);
}
- Optional<X509Certificate> testerCertificate = controller.jobController().run(id).get().testerCertificate();
+ Optional<X509Certificate> testerCertificate = controller.jobController().run(id).testerCertificate();
if (testerCertificate.isPresent()) {
try {
testerCertificate.get().checkValidity(Date.from(controller.clock().instant()));
@@ -684,7 +687,7 @@ public class InternalStepRunner implements StepRunner {
}
// Hitting a config server which doesn't have this particular app loaded causes a 404.
catch (ConfigServerException e) {
- Instant doom = controller.jobController().run(id).get().stepInfo(copyVespaLogs).get().startTime().get()
+ Instant doom = controller.jobController().run(id).stepInfo(copyVespaLogs).get().startTime().get()
.plus(Duration.ofMinutes(3));
if (e.code() == ConfigServerException.ErrorCode.NOT_FOUND && controller.clock().instant().isBefore(doom)) {
logger.log(INFO, "Found no logs, but will retry");
@@ -710,7 +713,7 @@ public class InternalStepRunner implements StepRunner {
}
catch (RuntimeException e) {
logger.log(WARNING, "Failed deleting application " + id.application(), e);
- Instant startTime = controller.jobController().run(id).get().stepInfo(deactivateReal).get().startTime().get();
+ Instant startTime = controller.jobController().run(id).stepInfo(deactivateReal).get().startTime().get();
return startTime.isBefore(controller.clock().instant().minus(Duration.ofHours(1)))
? Optional.of(error)
: Optional.empty();
@@ -725,7 +728,7 @@ public class InternalStepRunner implements StepRunner {
}
catch (RuntimeException e) {
logger.log(WARNING, "Failed deleting tester of " + id.application(), e);
- Instant startTime = controller.jobController().run(id).get().stepInfo(deactivateTester).get().startTime().get();
+ Instant startTime = controller.jobController().run(id).stepInfo(deactivateTester).get().startTime().get();
return startTime.isBefore(controller.clock().instant().minus(Duration.ofHours(1)))
? Optional.of(error)
: Optional.empty();
@@ -749,7 +752,7 @@ public class InternalStepRunner implements StepRunner {
return Optional.of(error);
}
catch (RuntimeException e) {
- Instant start = controller.jobController().run(id).get().stepInfo(report).get().startTime().get();
+ Instant start = controller.jobController().run(id).stepInfo(report).get().startTime().get();
return (controller.clock().instant().isAfter(start.plusSeconds(180)))
? Optional.empty()
: Optional.of(error);
@@ -871,7 +874,7 @@ public class InternalStepRunner implements StepRunner {
private boolean timedOut(RunId id, Deployment deployment, Duration defaultTimeout) {
// TODO jonmv: This is a workaround for new deployment writes not yet being visible in spite of Curator locking.
// TODO Investigate what's going on here, and remove this workaround.
- Run run = controller.jobController().run(id).get();
+ Run run = controller.jobController().run(id);
if ( ! controller.system().isCd() && run.start().isAfter(deployment.at()))
return false;
@@ -887,7 +890,7 @@ public class InternalStepRunner implements StepRunner {
/** Returns the application package for the tester application, assembled from a generated config, fat-jar and services.xml. */
private ApplicationPackage testerPackage(RunId id) {
- RevisionId revision = controller.jobController().run(id).get().versions().targetRevision();
+ RevisionId revision = controller.jobController().run(id).versions().targetRevision();
DeploymentSpec spec = controller.applications().requireApplication(TenantAndApplicationId.from(id.application())).deploymentSpec();
byte[] testZip = controller.applications().applicationStore().getTester(id.application().tenant(),
id.application().application(), revision);
diff --git a/controller-server/src/main/java/com/yahoo/vespa/hosted/controller/deployment/JobController.java b/controller-server/src/main/java/com/yahoo/vespa/hosted/controller/deployment/JobController.java
index 9331c9942b6..3d4a2f40303 100644
--- a/controller-server/src/main/java/com/yahoo/vespa/hosted/controller/deployment/JobController.java
+++ b/controller-server/src/main/java/com/yahoo/vespa/hosted/controller/deployment/JobController.java
@@ -47,6 +47,7 @@ import java.util.HashSet;
import java.util.List;
import java.util.Map;
import java.util.NavigableMap;
+import java.util.NoSuchElementException;
import java.util.Optional;
import java.util.OptionalLong;
import java.util.Set;
@@ -298,11 +299,12 @@ public class JobController {
return runs.build();
}
- /** Returns the run with the given id, if it exists. */
- public Optional<Run> run(RunId id) {
+ /** Returns the run with the given id, or throws if no such run exists. */
+ public Run run(RunId id) {
return runs(id.application(), id.type()).values().stream()
.filter(run -> run.id().equals(id))
- .findAny();
+ .findAny()
+ .orElseThrow(() -> new NoSuchElementException("no run with id '" + id + "' exists"));
}
/** Returns the last run of the given type, for the given application, if one has been run. */
@@ -412,7 +414,7 @@ public class JobController {
Deque<Mutex> locks = new ArrayDeque<>();
try {
// Ensure no step is still running before we finish the run — report depends transitively on all the other steps.
- Run unlockedRun = run(id).get();
+ Run unlockedRun = run(id);
locks.push(curator.lock(id.application(), id.type(), report));
for (Step step : report.allPrerequisites(unlockedRun.steps().keySet()))
locks.push(curator.lock(id.application(), id.type(), step));
diff --git a/controller-server/src/main/java/com/yahoo/vespa/hosted/controller/deployment/TestConfigSerializer.java b/controller-server/src/main/java/com/yahoo/vespa/hosted/controller/deployment/TestConfigSerializer.java
index 1680e064234..2394f293170 100644
--- a/controller-server/src/main/java/com/yahoo/vespa/hosted/controller/deployment/TestConfigSerializer.java
+++ b/controller-server/src/main/java/com/yahoo/vespa/hosted/controller/deployment/TestConfigSerializer.java
@@ -1,6 +1,7 @@
// Copyright Yahoo. Licensed under the terms of the Apache 2.0 license. See LICENSE in the project root.
package com.yahoo.vespa.hosted.controller.deployment;
+import com.yahoo.component.Version;
import com.yahoo.config.provision.ApplicationId;
import com.yahoo.config.provision.SystemName;
import com.yahoo.config.provision.zone.ZoneId;
@@ -8,10 +9,12 @@ import com.yahoo.slime.Cursor;
import com.yahoo.slime.Slime;
import com.yahoo.slime.SlimeUtils;
import com.yahoo.vespa.hosted.controller.api.integration.deployment.JobType;
+import com.yahoo.vespa.hosted.controller.api.integration.deployment.RevisionId;
import com.yahoo.vespa.hosted.controller.application.Endpoint;
import java.io.IOException;
import java.io.UncheckedIOException;
+import java.time.Instant;
import java.util.List;
import java.util.Map;
@@ -31,6 +34,9 @@ public class TestConfigSerializer {
public Slime configSlime(ApplicationId id,
JobType type,
boolean isCI,
+ Version platform,
+ RevisionId revision,
+ Instant deployedAt,
Map<ZoneId, List<Endpoint>> deployments,
Map<ZoneId, List<String>> clusters) {
Slime slime = new Slime();
@@ -40,6 +46,9 @@ public class TestConfigSerializer {
root.setString("zone", type.zone().value());
root.setString("system", system.value());
root.setBool("isCI", isCI);
+ root.setString("platform", platform.toFullString());
+ root.setLong("revision", revision.number());
+ root.setLong("deployedAt", deployedAt.toEpochMilli());
// TODO jvenstad: remove when clients can be updated
Cursor endpointsObject = root.setObject("endpoints");
@@ -72,10 +81,13 @@ public class TestConfigSerializer {
public byte[] configJson(ApplicationId id,
JobType type,
boolean isCI,
+ Version platform,
+ RevisionId revision,
+ Instant deployedAt,
Map<ZoneId, List<Endpoint>> deployments,
Map<ZoneId, List<String>> clusters) {
try {
- return SlimeUtils.toJsonBytes(configSlime(id, type, isCI, deployments, clusters));
+ return SlimeUtils.toJsonBytes(configSlime(id, type, isCI, platform, revision, deployedAt, deployments, clusters));
}
catch (IOException e) {
throw new UncheckedIOException(e);
diff --git a/controller-server/src/main/java/com/yahoo/vespa/hosted/controller/maintenance/JobRunner.java b/controller-server/src/main/java/com/yahoo/vespa/hosted/controller/maintenance/JobRunner.java
index b4fac8074aa..94ec4129744 100644
--- a/controller-server/src/main/java/com/yahoo/vespa/hosted/controller/maintenance/JobRunner.java
+++ b/controller-server/src/main/java/com/yahoo/vespa/hosted/controller/maintenance/JobRunner.java
@@ -81,7 +81,7 @@ public class JobRunner extends ControllerMaintainer {
&& controller().clock().instant().isAfter(run.sleepUntil().orElse(run.start()).plus(jobTimeout)))
executors.execute(() -> {
jobs.abort(run.id(), "job timeout of " + jobTimeout + " reached");
- advance(jobs.run(run.id()).get());
+ advance(jobs.run(run.id()));
});
else if (run.readySteps().isEmpty())
executors.execute(() -> finish(run.id()));
diff --git a/controller-server/src/main/java/com/yahoo/vespa/hosted/controller/restapi/application/ApplicationApiHandler.java b/controller-server/src/main/java/com/yahoo/vespa/hosted/controller/restapi/application/ApplicationApiHandler.java
index ef7c7063355..63f33540721 100644
--- a/controller-server/src/main/java/com/yahoo/vespa/hosted/controller/restapi/application/ApplicationApiHandler.java
+++ b/controller-server/src/main/java/com/yahoo/vespa/hosted/controller/restapi/application/ApplicationApiHandler.java
@@ -2345,16 +2345,24 @@ public class ApplicationApiHandler extends AuditLoggingRequestHandler {
.flatMap(instance -> instance.productionDeployments().keySet().stream())
.map(zone -> new DeploymentId(prodInstanceId, zone))
.collect(Collectors.toCollection(HashSet::new));
- ZoneId testedZone = type.zone();
+
// If a production job is specified, the production deployment of the orchestrated instance is the relevant one,
// as user instances should not exist in prod.
+ ApplicationId toTest = type.isProduction() ? prodInstanceId : id;
if ( ! type.isProduction())
- deployments.add(new DeploymentId(id, testedZone));
+ deployments.add(new DeploymentId(toTest, type.zone()));
+
+ Deployment deployment = application.require(toTest.instance()).deployments().get(type.zone());
+ if (deployment == null)
+ throw new NotExistsException(toTest + " is not deployed in " + type.zone());
return new SlimeJsonResponse(testConfigSerializer.configSlime(id,
type,
false,
+ deployment.version(),
+ deployment.revision(),
+ deployment.at(),
controller.routing().readTestRunnerEndpointsOf(deployments),
controller.applications().reachableContentClustersByZone(deployments)));
}
diff --git a/controller-server/src/main/java/com/yahoo/vespa/hosted/controller/restapi/application/JobControllerApiHandlerHelper.java b/controller-server/src/main/java/com/yahoo/vespa/hosted/controller/restapi/application/JobControllerApiHandlerHelper.java
index 80425609aa6..8c49df43c30 100644
--- a/controller-server/src/main/java/com/yahoo/vespa/hosted/controller/restapi/application/JobControllerApiHandlerHelper.java
+++ b/controller-server/src/main/java/com/yahoo/vespa/hosted/controller/restapi/application/JobControllerApiHandlerHelper.java
@@ -112,8 +112,7 @@ class JobControllerApiHandlerHelper {
Slime slime = new Slime();
Cursor detailsObject = slime.setObject();
- Run run = jobController.run(runId)
- .orElseThrow(() -> new IllegalStateException("Unknown run '" + runId + "'"));
+ Run run = jobController.run(runId);
detailsObject.setBool("active", ! run.hasEnded());
detailsObject.setString("status", nameOf(run.status()));
try {
diff --git a/controller-server/src/test/java/com/yahoo/vespa/hosted/controller/deployment/DeploymentContext.java b/controller-server/src/test/java/com/yahoo/vespa/hosted/controller/deployment/DeploymentContext.java
index 27951d95689..b3db4a8b845 100644
--- a/controller-server/src/test/java/com/yahoo/vespa/hosted/controller/deployment/DeploymentContext.java
+++ b/controller-server/src/test/java/com/yahoo/vespa/hosted/controller/deployment/DeploymentContext.java
@@ -355,7 +355,7 @@ public class DeploymentContext {
var job = jobId(type);
RunId id = currentRun(job).id();
runner.advance(currentRun(job));
- Run run = jobs.run(id).get();
+ Run run = jobs.run(id);
assertTrue(run.hasFailed());
assertTrue(run.hasEnded());
if (messagePart.isPresent()) {
@@ -441,10 +441,10 @@ public class DeploymentContext {
RunId id = currentRun(job).id();
- assertEquals(unfinished, jobs.run(id).get().stepStatuses().get(Step.endTests));
+ assertEquals(unfinished, jobs.run(id).stepStatuses().get(Step.endTests));
tester.cloud().set(noTests ? Status.NO_TESTS : Status.FAILURE);
runner.advance(currentRun(job));
- assertTrue(jobs.run(id).get().hasEnded());
+ assertTrue(jobs.run(id).hasEnded());
assertTrue(configServer().nodeRepository().list(job.type().zone(), NodeFilter.all().applications(TesterId.of(instanceId).id())).isEmpty());
return this;
@@ -481,7 +481,7 @@ public class DeploymentContext {
assertSame(RunStatus.aborted, run.status());
assertFalse(run.hasEnded());
runner.advance(run);
- assertTrue(jobs.run(run.id()).get().hasEnded());
+ assertTrue(jobs.run(run.id()).hasEnded());
return this;
}
@@ -493,8 +493,8 @@ public class DeploymentContext {
doDeploy(job);
tester.clock().advance(Timeouts.of(tester.controller().system()).noNodesDown().plusSeconds(1));
runner.advance(currentRun(job));
- assertTrue(jobs.run(id).get().hasFailed());
- assertTrue(jobs.run(id).get().hasEnded());
+ assertTrue(jobs.run(id).hasFailed());
+ assertTrue(jobs.run(id).hasEnded());
return this;
}
@@ -507,8 +507,8 @@ public class DeploymentContext {
doUpgrade(job);
tester.clock().advance(Timeouts.of(tester.controller().system()).noNodesDown().plusSeconds(1));
runner.advance(currentRun(job));
- assertTrue(jobs.run(id).get().hasFailed());
- assertTrue(jobs.run(id).get().hasEnded());
+ assertTrue(jobs.run(id).hasFailed());
+ assertTrue(jobs.run(id).hasEnded());
return this;
}
@@ -540,8 +540,8 @@ public class DeploymentContext {
configServer().convergeServices(instanceId, testZone);
configServer().convergeServices(testerId.id(), testZone);
runner.run();
- assertEquals(unfinished, jobs.run(id).get().stepStatuses().get(Step.endTests));
- assertTrue(jobs.run(id).get().steps().get(Step.endTests).startTime().isPresent());
+ assertEquals(unfinished, jobs.run(id).stepStatuses().get(Step.endTests));
+ assertTrue(jobs.run(id).steps().get(Step.endTests).startTime().isPresent());
return id;
}
@@ -571,21 +571,21 @@ public class DeploymentContext {
doInstallTester(job);
if (job.type().equals(stagingTest)) { // Do the initial deployment and installation of the real application.
- assertEquals(unfinished, jobs.run(id).get().stepStatuses().get(Step.installInitialReal));
+ assertEquals(unfinished, jobs.run(id).stepStatuses().get(Step.installInitialReal));
tester.configServer().nodeRepository().doUpgrade(deployment, Optional.empty(), tester.configServer().application(job.application(), zone).get().version().get());
configServer().convergeServices(id.application(), zone);
runner.advance(currentRun(job));
- assertEquals(succeeded, jobs.run(id).get().stepStatuses().get(Step.installInitialReal));
+ assertEquals(succeeded, jobs.run(id).stepStatuses().get(Step.installInitialReal));
// All installation is complete and endpoints are ready, so setup may begin.
- assertEquals(succeeded, jobs.run(id).get().stepStatuses().get(Step.installInitialReal));
- assertEquals(succeeded, jobs.run(id).get().stepStatuses().get(Step.installTester));
- assertEquals(succeeded, jobs.run(id).get().stepStatuses().get(Step.startStagingSetup));
+ assertEquals(succeeded, jobs.run(id).stepStatuses().get(Step.installInitialReal));
+ assertEquals(succeeded, jobs.run(id).stepStatuses().get(Step.installTester));
+ assertEquals(succeeded, jobs.run(id).stepStatuses().get(Step.startStagingSetup));
- assertEquals(unfinished, jobs.run(id).get().stepStatuses().get(Step.endStagingSetup));
+ assertEquals(unfinished, jobs.run(id).stepStatuses().get(Step.endStagingSetup));
tester.cloud().set(Status.SUCCESS);
runner.advance(currentRun(job));
- assertEquals(succeeded, jobs.run(id).get().stepStatuses().get(Step.endStagingSetup));
+ assertEquals(succeeded, jobs.run(id).stepStatuses().get(Step.endStagingSetup));
}
}
@@ -595,7 +595,7 @@ public class DeploymentContext {
ZoneId zone = job.type().zone();
DeploymentId deployment = new DeploymentId(job.application(), zone);
- assertEquals(unfinished, jobs.run(id).get().stepStatuses().get(Step.installReal));
+ assertEquals(unfinished, jobs.run(id).stepStatuses().get(Step.installReal));
configServer().nodeRepository().doUpgrade(deployment, Optional.empty(), tester.configServer().application(job.application(), zone).get().version().get());
runner.advance(currentRun(job));
}
@@ -615,15 +615,15 @@ public class DeploymentContext {
RunId id = currentRun(job).id();
ZoneId zone = job.type().zone();
- assertEquals(unfinished, jobs.run(id).get().stepStatuses().get(Step.installReal));
+ assertEquals(unfinished, jobs.run(id).stepStatuses().get(Step.installReal));
configServer().convergeServices(id.application(), zone);
runner.advance(currentRun(job));
if (job.type().environment().isManuallyDeployed()) {
- assertEquals(succeeded, jobs.run(id).get().stepStatuses().get(Step.installReal));
- assertTrue(jobs.run(id).get().hasEnded());
+ assertEquals(succeeded, jobs.run(id).stepStatuses().get(Step.installReal));
+ assertTrue(jobs.run(id).hasEnded());
return;
}
- assertEquals("Status of " + id, succeeded, jobs.run(id).get().stepStatuses().get(Step.installReal));
+ assertEquals("Status of " + id, succeeded, jobs.run(id).stepStatuses().get(Step.installReal));
}
/** Installs tester and starts tests. */
@@ -631,13 +631,13 @@ public class DeploymentContext {
RunId id = currentRun(job).id();
ZoneId zone = job.type().zone();
- assertEquals(unfinished, jobs.run(id).get().stepStatuses().get(Step.installTester));
+ assertEquals(unfinished, jobs.run(id).stepStatuses().get(Step.installTester));
configServer().nodeRepository().doUpgrade(new DeploymentId(TesterId.of(job.application()).id(), zone), Optional.empty(), tester.configServer().application(id.tester().id(), zone).get().version().get());
runner.advance(currentRun(job));
- assertEquals(unfinished, jobs.run(id).get().stepStatuses().get(Step.installTester));
+ assertEquals(unfinished, jobs.run(id).stepStatuses().get(Step.installTester));
configServer().convergeServices(TesterId.of(id.application()).id(), zone);
runner.advance(currentRun(job));
- assertEquals(succeeded, jobs.run(id).get().stepStatuses().get(Step.installTester));
+ assertEquals(succeeded, jobs.run(id).stepStatuses().get(Step.installTester));
runner.advance(currentRun(job));
}
@@ -648,15 +648,15 @@ public class DeploymentContext {
// All installation is complete and endpoints are ready, so tests may begin.
if (job.type().isDeployment())
- assertEquals(succeeded, jobs.run(id).get().stepStatuses().get(Step.installReal));
- assertEquals(succeeded, jobs.run(id).get().stepStatuses().get(Step.installTester));
- assertEquals(succeeded, jobs.run(id).get().stepStatuses().get(Step.startTests));
+ assertEquals(succeeded, jobs.run(id).stepStatuses().get(Step.installReal));
+ assertEquals(succeeded, jobs.run(id).stepStatuses().get(Step.installTester));
+ assertEquals(succeeded, jobs.run(id).stepStatuses().get(Step.startTests));
- assertEquals(unfinished, jobs.run(id).get().stepStatuses().get(Step.endTests));
+ assertEquals(unfinished, jobs.run(id).stepStatuses().get(Step.endTests));
tester.cloud().set(Status.SUCCESS);
runner.advance(currentRun(job));
- assertTrue(jobs.run(id).get().hasEnded());
- assertFalse(jobs.run(id).get().hasFailed());
+ assertTrue(jobs.run(id).hasEnded());
+ assertFalse(jobs.run(id).hasFailed());
Instance instance = tester.application(TenantAndApplicationId.from(instanceId)).require(id.application().instance());
assertEquals(job.type().isProduction(), instance.deployments().containsKey(zone));
assertTrue(configServer().nodeRepository().list(zone, NodeFilter.all().applications(TesterId.of(instance.id()).id())).isEmpty());
diff --git a/controller-server/src/test/java/com/yahoo/vespa/hosted/controller/deployment/DeploymentTester.java b/controller-server/src/test/java/com/yahoo/vespa/hosted/controller/deployment/DeploymentTester.java
index 4219c52be20..78e7606d7c6 100644
--- a/controller-server/src/test/java/com/yahoo/vespa/hosted/controller/deployment/DeploymentTester.java
+++ b/controller-server/src/test/java/com/yahoo/vespa/hosted/controller/deployment/DeploymentTester.java
@@ -136,8 +136,8 @@ public class DeploymentTester {
triggerJobs();
for (Run run : jobs.active()) {
jobs.abort(run.id(), "DeploymentTester.abortAll");
- runner.advance(jobs.run(run.id()).get());
- assertTrue(jobs.run(run.id()).get().hasEnded());
+ runner.advance(jobs.run(run.id()));
+ assertTrue(jobs.run(run.id()).hasEnded());
}
}
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 ae08d1b3a22..d781b1f1d3f 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
@@ -120,19 +120,19 @@ public class InternalStepRunnerTest {
HostName host = tester.configServer().hostFor(instanceId, zone);
tester.runner().run();
- assertEquals(succeeded, tester.jobs().run(id).get().stepStatuses().get(Step.deployReal));
+ assertEquals(succeeded, tester.jobs().run(id).stepStatuses().get(Step.deployReal));
tester.configServer().convergeServices(app.instanceId(), zone);
- assertEquals(unfinished, tester.jobs().run(id).get().stepStatuses().get(Step.installReal));
+ assertEquals(unfinished, tester.jobs().run(id).stepStatuses().get(Step.installReal));
tester.configServer().nodeRepository().doRestart(app.deploymentIdIn(zone), Optional.of(host));
tester.configServer().nodeRepository().requestReboot(app.deploymentIdIn(zone), Optional.of(host));
tester.runner().run();
- assertEquals(unfinished, tester.jobs().run(id).get().stepStatuses().get(Step.installReal));
+ assertEquals(unfinished, tester.jobs().run(id).stepStatuses().get(Step.installReal));
tester.clock().advance(InternalStepRunner.Timeouts.of(system()).noNodesDown().plus(Duration.ofSeconds(1)));
tester.runner().run();
- assertEquals(installationFailed, tester.jobs().run(id).get().status());
+ assertEquals(installationFailed, tester.jobs().run(id).status());
}
@Test
@@ -251,7 +251,7 @@ public class InternalStepRunnerTest {
@Test
public void noTestsThenErrorIsError() {
RunId id = app.startSystemTestTests();
- Run run = tester.jobs().run(id).get();
+ Run run = tester.jobs().run(id);
run = run.with(noTests, new LockedStep(() -> { }, Step.endTests));
assertFalse(run.hasFailed());
run = run.with(RunStatus.error, new LockedStep(() -> { }, Step.deactivateReal));
@@ -264,8 +264,8 @@ public class InternalStepRunnerTest {
RunId id = app.startSystemTestTests();
tester.cloud().set(Status.NO_TESTS);
tester.runner().run();
- assertEquals(succeeded, tester.jobs().run(id).get().stepStatuses().get(Step.endTests));
- Run run = tester.jobs().run(id).get();
+ assertEquals(succeeded, tester.jobs().run(id).stepStatuses().get(Step.endTests));
+ Run run = tester.jobs().run(id);
assertEquals(noTests, run.status());
}
@@ -274,7 +274,7 @@ public class InternalStepRunnerTest {
RunId id = app.startSystemTestTests();
tester.cloud().set(TesterCloud.Status.NOT_STARTED);
tester.runner().run();
- assertEquals(failed, tester.jobs().run(id).get().stepStatuses().get(Step.endTests));
+ assertEquals(failed, tester.jobs().run(id).stepStatuses().get(Step.endTests));
}
@Test
@@ -288,7 +288,7 @@ public class InternalStepRunnerTest {
assertTestLogEntries(id, Step.endTests,
new LogEntry(lastId + 1, Instant.ofEpochMilli(321), error, "Failure!"),
new LogEntry(lastId + 2, tester.clock().instant(), info, "Tests failed."));
- assertEquals(failed, tester.jobs().run(id).get().stepStatuses().get(Step.endTests));
+ assertEquals(failed, tester.jobs().run(id).stepStatuses().get(Step.endTests));
}
@Test
@@ -299,7 +299,7 @@ public class InternalStepRunnerTest {
long lastId = tester.jobs().details(id).get().lastId().getAsLong();
tester.runner().run();
- assertEquals(failed, tester.jobs().run(id).get().stepStatuses().get(Step.endTests));
+ assertEquals(failed, tester.jobs().run(id).stepStatuses().get(Step.endTests));
assertTestLogEntries(id, Step.endTests,
new LogEntry(lastId + 1, Instant.ofEpochMilli(123), error, "Error!"),
new LogEntry(lastId + 2, tester.clock().instant(), info, "Tester failed running its tests!"));
@@ -309,7 +309,7 @@ public class InternalStepRunnerTest {
public void testsSucceedWhenTheyDoRemotely() {
RunId id = app.startSystemTestTests();
tester.runner().run();
- assertEquals(unfinished, tester.jobs().run(id).get().stepStatuses().get(Step.endTests));
+ assertEquals(unfinished, tester.jobs().run(id).stepStatuses().get(Step.endTests));
var testZone = DeploymentContext.systemTest.zone();
Inspector configObject = SlimeUtils.jsonToSlime(tester.cloud().config()).get();
assertEquals(app.instanceId().serializedForm(), configObject.field("application").asString());
@@ -338,7 +338,7 @@ public class InternalStepRunnerTest {
new LogEntry(lastId + 2, Instant.ofEpochMilli(1234), info, "Steady!"),
new LogEntry(lastId + 3, Instant.ofEpochMilli(12345), info, "Success!"),
new LogEntry(lastId + 4, tester.clock().instant(), info, "Tests completed successfully."));
- assertEquals(succeeded, tester.jobs().run(id).get().stepStatuses().get(Step.endTests));
+ assertEquals(succeeded, tester.jobs().run(id).stepStatuses().get(Step.endTests));
}
@Test
@@ -351,16 +351,16 @@ public class InternalStepRunnerTest {
long lastId1 = tester.jobs().details(id).get().lastId().getAsLong();
Instant instant1 = tester.clock().instant();
tester.runner().run();
- assertEquals(unfinished, tester.jobs().run(id).get().stepStatuses().get(Step.endTests));
- assertEquals(running, tester.jobs().run(id).get().status());
+ assertEquals(unfinished, tester.jobs().run(id).stepStatuses().get(Step.endTests));
+ assertEquals(running, tester.jobs().run(id).status());
tester.cloud().clearLog();
// Test sleeps for a while.
tester.runner().run();
- assertEquals(unfinished, tester.jobs().run(id).get().stepStatuses().get(Step.deployTester));
+ assertEquals(unfinished, tester.jobs().run(id).stepStatuses().get(Step.deployTester));
tester.clock().advance(Duration.ofSeconds(899));
tester.runner().run();
- assertEquals(unfinished, tester.jobs().run(id).get().stepStatuses().get(Step.deployTester));
+ assertEquals(unfinished, tester.jobs().run(id).stepStatuses().get(Step.deployTester));
tester.clock().advance(JobRunner.jobTimeout);
var testZone = DeploymentContext.systemTest.zone();
@@ -369,14 +369,14 @@ public class InternalStepRunnerTest {
tester.configServer().convergeServices(app.instanceId(), testZone);
tester.configServer().convergeServices(app.testerId().id(), testZone);
tester.runner().run();
- assertEquals(unfinished, tester.jobs().run(id).get().stepStatuses().get(Step.endTests));
- assertTrue(tester.jobs().run(id).get().steps().get(Step.endTests).startTime().isPresent());
+ assertEquals(unfinished, tester.jobs().run(id).stepStatuses().get(Step.endTests));
+ assertTrue(tester.jobs().run(id).steps().get(Step.endTests).startTime().isPresent());
tester.cloud().set(TesterCloud.Status.SUCCESS);
tester.cloud().testReport(TestReport.fromJson("{\"bar\":2}"));
long lastId2 = tester.jobs().details(id).get().lastId().getAsLong();
tester.runner().run();
- assertEquals(success, tester.jobs().run(id).get().status());
+ assertEquals(success, tester.jobs().run(id).status());
assertTestLogEntries(id, Step.endTests,
new LogEntry(lastId1 + 1, Instant.ofEpochMilli(123), info, "Not enough data!"),
@@ -394,7 +394,7 @@ public class InternalStepRunnerTest {
tester.jobs().deploy(app.instanceId(), DeploymentContext.devUsEast1, Optional.empty(), applicationPackage());
tester.runner().run();
RunId id = tester.jobs().last(app.instanceId(), DeploymentContext.devUsEast1).get().id();
- assertEquals(unfinished, tester.jobs().run(id).get().stepStatuses().get(Step.installReal));
+ assertEquals(unfinished, tester.jobs().run(id).stepStatuses().get(Step.installReal));
Version version = new Version("7.8.9");
Future<?> concurrentDeployment = Executors.newSingleThreadExecutor().submit(() -> {
@@ -409,7 +409,7 @@ public class InternalStepRunnerTest {
tester.runner().run(); // Job run order determined by JobType enum order per application.
tester.configServer().convergeServices(app.instanceId(), zone);
- assertEquals(unfinished, tester.jobs().run(id).get().stepStatuses().get(Step.installReal));
+ assertEquals(unfinished, tester.jobs().run(id).stepStatuses().get(Step.installReal));
assertEquals(applicationPackage().hash(), tester.configServer().application(app.instanceId(), zone).get().applicationPackage().hash());
assertEquals(otherPackage.hash(), tester.configServer().application(app.instanceId(), DeploymentContext.perfUsEast3.zone()).get().applicationPackage().hash());
@@ -450,8 +450,8 @@ public class InternalStepRunnerTest {
tester.configServer().setLogStream(() -> { throw new ConfigServerException(ConfigServerException.ErrorCode.NOT_FOUND, "404", "context"); });
long lastId = tester.jobs().details(id).get().lastId().getAsLong();
tester.runner().run();
- assertEquals(failed, tester.jobs().run(id).get().stepStatuses().get(Step.endTests));
- assertEquals(unfinished, tester.jobs().run(id).get().stepStatuses().get(Step.copyVespaLogs));
+ assertEquals(failed, tester.jobs().run(id).stepStatuses().get(Step.endTests));
+ assertEquals(unfinished, tester.jobs().run(id).stepStatuses().get(Step.copyVespaLogs));
assertTestLogEntries(id, Step.copyVespaLogs,
new LogEntry(lastId + 2, tester.clock().instant(), info,
"Found no logs, but will retry"));
@@ -459,7 +459,7 @@ public class InternalStepRunnerTest {
// Config servers now provide the log, and we get it.
tester.configServer().setLogStream(() -> vespaLog(tester.clock().instant()));
tester.runner().run();
- assertEquals(failed, tester.jobs().run(id).get().stepStatuses().get(Step.endTests));
+ assertEquals(failed, tester.jobs().run(id).stepStatuses().get(Step.endTests));
assertTestLogEntries(id, Step.copyVespaLogs,
new LogEntry(lastId + 2, tester.clock().instant(), info,
"Found no logs, but will retry"),
@@ -511,21 +511,21 @@ public class InternalStepRunnerTest {
throw new ConfigServerException(ConfigServerException.ErrorCode.PARENT_HOST_NOT_READY, "provisioning", "deploy tester");
});
tester.runner().run();
- assertEquals(unfinished, tester.jobs().run(id).get().stepStatuses().get(Step.deployTester));
- assertEquals(unfinished, tester.jobs().run(id).get().stepStatuses().get(Step.deployReal));
+ assertEquals(unfinished, tester.jobs().run(id).stepStatuses().get(Step.deployTester));
+ assertEquals(unfinished, tester.jobs().run(id).stepStatuses().get(Step.deployReal));
List<X509Certificate> oldTrusted = new ArrayList<>(DeploymentContext.publicApplicationPackage().trustedCertificates());
- X509Certificate oldCert = tester.jobs().run(id).get().testerCertificate().get();
+ X509Certificate oldCert = tester.jobs().run(id).testerCertificate().get();
oldTrusted.add(oldCert);
assertEquals(oldTrusted, tester.configServer().application(app.instanceId(), id.type().zone()).get().applicationPackage().trustedCertificates());
tester.configServer().throwOnNextPrepare(null);
tester.runner().run();
- assertEquals(succeeded, tester.jobs().run(id).get().stepStatuses().get(Step.deployTester));
- assertEquals(succeeded, tester.jobs().run(id).get().stepStatuses().get(Step.deployReal));
+ assertEquals(succeeded, tester.jobs().run(id).stepStatuses().get(Step.deployTester));
+ assertEquals(succeeded, tester.jobs().run(id).stepStatuses().get(Step.deployReal));
List<X509Certificate> newTrusted = new ArrayList<>(DeploymentContext.publicApplicationPackage().trustedCertificates());
- X509Certificate newCert = tester.jobs().run(id).get().testerCertificate().get();
+ X509Certificate newCert = tester.jobs().run(id).testerCertificate().get();
newTrusted.add(newCert);
assertEquals(newTrusted, tester.configServer().application(app.instanceId(), id.type().zone()).get().applicationPackage().trustedCertificates());
assertNotEquals(oldCert, newCert);
@@ -538,12 +538,12 @@ public class InternalStepRunnerTest {
RunId id = app.startSystemTestTests();
List<X509Certificate> trusted = new ArrayList<>(DeploymentContext.publicApplicationPackage().trustedCertificates());
- trusted.add(tester.jobs().run(id).get().testerCertificate().get());
+ trusted.add(tester.jobs().run(id).testerCertificate().get());
assertEquals(trusted, tester.configServer().application(app.instanceId(), id.type().zone()).get().applicationPackage().trustedCertificates());
tester.clock().advance(InternalStepRunner.Timeouts.of(system()).testerCertificate().plus(Duration.ofSeconds(1)));
tester.runner().run();
- assertEquals(RunStatus.error, tester.jobs().run(id).get().status());
+ assertEquals(RunStatus.error, tester.jobs().run(id).status());
}
private void assertTestLogEntries(RunId id, Step step, LogEntry... entries) {
diff --git a/controller-server/src/test/java/com/yahoo/vespa/hosted/controller/deployment/TestConfigSerializerTest.java b/controller-server/src/test/java/com/yahoo/vespa/hosted/controller/deployment/TestConfigSerializerTest.java
index 59ee8cc6eae..67583891765 100644
--- a/controller-server/src/test/java/com/yahoo/vespa/hosted/controller/deployment/TestConfigSerializerTest.java
+++ b/controller-server/src/test/java/com/yahoo/vespa/hosted/controller/deployment/TestConfigSerializerTest.java
@@ -1,12 +1,14 @@
// Copyright Yahoo. Licensed under the terms of the Apache 2.0 license. See LICENSE in the project root.
package com.yahoo.vespa.hosted.controller.deployment;
+import com.yahoo.component.Version;
import com.yahoo.config.provision.ApplicationId;
import com.yahoo.config.provision.ClusterSpec;
import com.yahoo.config.provision.SystemName;
import com.yahoo.config.provision.zone.ZoneId;
import com.yahoo.slime.SlimeUtils;
import com.yahoo.vespa.hosted.controller.api.identifiers.DeploymentId;
+import com.yahoo.vespa.hosted.controller.api.integration.deployment.RevisionId;
import com.yahoo.vespa.hosted.controller.application.Endpoint;
import com.yahoo.vespa.hosted.controller.application.EndpointId;
import org.junit.Test;
@@ -14,6 +16,7 @@ import org.junit.Test;
import java.io.IOException;
import java.nio.file.Files;
import java.nio.file.Paths;
+import java.time.Instant;
import java.util.List;
import java.util.Map;
@@ -31,6 +34,9 @@ public class TestConfigSerializerTest {
byte[] json = new TestConfigSerializer(SystemName.PublicCd).configJson(instanceId,
DeploymentContext.systemTest,
true,
+ Version.fromString("1.2.3"),
+ RevisionId.forProduction(321),
+ Instant.ofEpochMilli(222),
Map.of(zone, List.of(Endpoint.of(ApplicationId.defaultId())
.target(EndpointId.of("ai"), ClusterSpec.Id.from("qrs"),
List.of(new DeploymentId(ApplicationId.defaultId(),
diff --git a/controller-server/src/test/java/com/yahoo/vespa/hosted/controller/restapi/application/responses/test-config-dev.json b/controller-server/src/test/java/com/yahoo/vespa/hosted/controller/restapi/application/responses/test-config-dev.json
index 3a5e6dc5dc3..ac0f2b9f740 100644
--- a/controller-server/src/test/java/com/yahoo/vespa/hosted/controller/restapi/application/responses/test-config-dev.json
+++ b/controller-server/src/test/java/com/yahoo/vespa/hosted/controller/restapi/application/responses/test-config-dev.json
@@ -3,6 +3,9 @@
"zone": "dev.us-east-1",
"system": "main",
"isCI": false,
+ "platform": "6.1.0",
+ "revision": 1,
+ "deployedAt": 1600000000000,
"endpoints": {
"dev.us-east-1": [
"https://my-user.application1.tenant1.us-east-1.dev.vespa.oath.cloud/"
diff --git a/controller-server/src/test/java/com/yahoo/vespa/hosted/controller/restapi/application/responses/test-config.json b/controller-server/src/test/java/com/yahoo/vespa/hosted/controller/restapi/application/responses/test-config.json
index 0a9236655ba..671c34cb2c0 100644
--- a/controller-server/src/test/java/com/yahoo/vespa/hosted/controller/restapi/application/responses/test-config.json
+++ b/controller-server/src/test/java/com/yahoo/vespa/hosted/controller/restapi/application/responses/test-config.json
@@ -3,6 +3,9 @@
"zone": "prod.us-central-1",
"system": "main",
"isCI": false,
+ "platform": "6.1.0",
+ "revision": 1,
+ "deployedAt": 1600000000000,
"endpoints": {
"prod.us-central-1": [
"https://application1.tenant1.us-central-1.vespa.oath.cloud/"
diff --git a/controller-server/src/test/resources/testConfig.json b/controller-server/src/test/resources/testConfig.json
index 5c3d5942001..0ea4b163992 100644
--- a/controller-server/src/test/resources/testConfig.json
+++ b/controller-server/src/test/resources/testConfig.json
@@ -3,6 +3,9 @@
"zone": "test.us-east-1",
"system": "publiccd",
"isCI": true,
+ "platform": "1.2.3",
+ "revision": 321,
+ "deployedAt": 222,
"endpoints": {
"test.us-east-1": [
"https://ai.default.default.global.vespa.oath.cloud/"
diff --git a/hosted-api/src/main/java/ai/vespa/hosted/api/TestConfig.java b/hosted-api/src/main/java/ai/vespa/hosted/api/TestConfig.java
index 937e961c69b..d8bd08773ee 100644
--- a/hosted-api/src/main/java/ai/vespa/hosted/api/TestConfig.java
+++ b/hosted-api/src/main/java/ai/vespa/hosted/api/TestConfig.java
@@ -10,6 +10,7 @@ import com.yahoo.slime.ObjectTraverser;
import com.yahoo.slime.SlimeUtils;
import java.net.URI;
+import java.time.Instant;
import java.util.ArrayList;
import java.util.HashMap;
import java.util.List;
@@ -29,10 +30,14 @@ public class TestConfig {
private final ZoneId zone;
private final SystemName system;
private final boolean isCI;
+ private final String platform;
+ private final long revision;
+ private final Instant deployedAt;
private final Map<ZoneId, Map<String, URI>> deployments;
private final Map<ZoneId, List<String>> contentClusters;
public TestConfig(ApplicationId application, ZoneId zone, SystemName system, boolean isCI,
+ String platform, long revision, Instant deployedAt,
Map<ZoneId, Map<String, URI>> deployments, Map<ZoneId, List<String>> contentClusters) {
if ( ! deployments.containsKey(zone))
throw new IllegalArgumentException("Config must contain a deployment for its zone, but only does for " + deployments.keySet());
@@ -40,6 +45,9 @@ public class TestConfig {
this.zone = requireNonNull(zone);
this.system = requireNonNull(system);
this.isCI = isCI;
+ this.platform = platform;
+ this.revision = revision;
+ this.deployedAt = deployedAt;
this.deployments = deployments.entrySet().stream()
.collect(Collectors.toUnmodifiableMap(entry -> entry.getKey(),
entry -> Map.copyOf(entry.getValue())));
@@ -59,10 +67,17 @@ public class TestConfig {
if (config.field("localEndpoints").valid())
return TestConfig.fromEndpointsOnly(toClusterMap(config.field("localEndpoints")));
+ if (config.field("deployments").valid()) {
+
+ }
+
ApplicationId application = ApplicationId.fromSerializedForm(config.field("application").asString());
ZoneId zone = ZoneId.from(config.field("zone").asString());
SystemName system = SystemName.from(config.field("system").asString());
boolean isCI = config.field("isCI").asBool();
+ String platform = config.field("platform").asString();
+ long revision = config.field("revision").asLong();
+ Instant deployedAt = Instant.ofEpochMilli(config.field("deployedAt").asLong());
Map<ZoneId, Map<String, URI>> deployments = new HashMap<>();
config.field("zoneEndpoints").traverse((ObjectTraverser) (zoneId, clustersObject) -> {
deployments.put(ZoneId.from(zoneId), toClusterMap(clustersObject));
@@ -73,7 +88,7 @@ public class TestConfig {
clustersArray.traverse((ArrayTraverser) (__, cluster) -> clusters.add(cluster.asString()));
contentClusters.put(ZoneId.from(zoneId), clusters);
}));
- return new TestConfig(application, zone, system, isCI, deployments, contentClusters);
+ return new TestConfig(application, zone, system, isCI, platform, revision, deployedAt, deployments, contentClusters);
}
static Map<String, URI> toClusterMap(Inspector clustersObject) {
@@ -91,6 +106,9 @@ public class TestConfig {
ZoneId.defaultId(),
SystemName.defaultSystem(),
false,
+ "",
+ 0,
+ Instant.EPOCH,
Map.of(ZoneId.defaultId(), endpoints),
Map.of());
}
@@ -113,4 +131,10 @@ public class TestConfig {
/** Returns an immutable view of content clusters, per zone, of the application to test. */
public Map<ZoneId, List<String>> contentClusters() { return contentClusters; }
+ public String platformVersion() { return platform; }
+
+ public long applicationVersion() { return revision; }
+
+ public Instant deployedAt() { return deployedAt; }
+
}
diff --git a/hosted-api/src/test/java/ai/vespa/hosted/api/TestConfigTest.java b/hosted-api/src/test/java/ai/vespa/hosted/api/TestConfigTest.java
index 2cbc65c6b23..320bce678c3 100644
--- a/hosted-api/src/test/java/ai/vespa/hosted/api/TestConfigTest.java
+++ b/hosted-api/src/test/java/ai/vespa/hosted/api/TestConfigTest.java
@@ -10,6 +10,7 @@ import java.io.IOException;
import java.net.URI;
import java.nio.file.Files;
import java.nio.file.Paths;
+import java.time.Instant;
import java.util.List;
import java.util.Map;
@@ -32,6 +33,9 @@ public class TestConfigTest {
assertEquals(SystemName.PublicCd,
config.system());
assertTrue(config.isCI());
+ assertEquals("1.2.3", config.platformVersion());
+ assertEquals(321, config.applicationVersion());
+ assertEquals(Instant.ofEpochMilli(1600000000L), config.deployedAt());
assertEquals(Map.of(ZoneId.from("dev", "aws-us-east-1c"),
Map.of("default", URI.create("https://dev.endpoint:443/")),
ZoneId.from("prod", "aws-us-east-1a"),
diff --git a/hosted-api/src/test/resources/test-config.json b/hosted-api/src/test/resources/test-config.json
index 07454efdb66..b1a7e2c2563 100644
--- a/hosted-api/src/test/resources/test-config.json
+++ b/hosted-api/src/test/resources/test-config.json
@@ -3,6 +3,9 @@
"zone": "dev.aws-us-east-1c",
"system": "publiccd",
"isCI": true,
+ "platform": "1.2.3",
+ "revision": 321,
+ "deployedAt": 1600000000,
"zoneEndpoints": {
"dev.aws-us-east-1c": {
"default": "https://dev.endpoint:443/"
diff --git a/tenant-cd-api/abi-spec.json b/tenant-cd-api/abi-spec.json
index 48222a63e28..8eee085de08 100644
--- a/tenant-cd-api/abi-spec.json
+++ b/tenant-cd-api/abi-spec.json
@@ -8,7 +8,10 @@
"abstract"
],
"methods": [
- "public abstract ai.vespa.hosted.cd.Endpoint endpoint(java.lang.String)"
+ "public abstract ai.vespa.hosted.cd.Endpoint endpoint(java.lang.String)",
+ "public abstract java.lang.String platformVersion()",
+ "public abstract long applicationVersion()",
+ "public abstract java.time.Instant deployedAt()"
],
"fields": []
},
@@ -138,7 +141,8 @@
"methods": [
"public static ai.vespa.hosted.cd.TestRuntime get()",
"public abstract ai.vespa.hosted.cd.Deployment deploymentToTest()",
- "public abstract ai.vespa.cloud.Zone zone()"
+ "public abstract ai.vespa.cloud.Zone zone()",
+ "public abstract ai.vespa.cloud.ApplicationId application()"
],
"fields": [
"public static final java.util.logging.Logger logger"
diff --git a/tenant-cd-api/src/main/java/ai/vespa/hosted/cd/Deployment.java b/tenant-cd-api/src/main/java/ai/vespa/hosted/cd/Deployment.java
index 9d42ba138bd..a04f07d5dae 100644
--- a/tenant-cd-api/src/main/java/ai/vespa/hosted/cd/Deployment.java
+++ b/tenant-cd-api/src/main/java/ai/vespa/hosted/cd/Deployment.java
@@ -1,6 +1,8 @@
// Copyright Yahoo. Licensed under the terms of the Apache 2.0 license. See LICENSE in the project root.
package ai.vespa.hosted.cd;
+import java.time.Instant;
+
/**
* A deployment of a Vespa application, which contains endpoints for document retrieval.
*
@@ -11,4 +13,13 @@ public interface Deployment {
/** Returns an Endpoint in the cluster with the given id. */
Endpoint endpoint(String id);
+ /** The Vespa runtime version of the deployment, e.g., 8.16.32. */
+ String platformVersion();
+
+ /** The build number assigned to the application revision of the deployment, e.g., 496. */
+ long applicationVersion();
+
+ /** The time at which the deployment was last updated with a new platform or application version. */
+ Instant deployedAt();
+
}
diff --git a/tenant-cd-api/src/main/java/ai/vespa/hosted/cd/TestRuntime.java b/tenant-cd-api/src/main/java/ai/vespa/hosted/cd/TestRuntime.java
index d031054851c..b1aa2bb62ba 100644
--- a/tenant-cd-api/src/main/java/ai/vespa/hosted/cd/TestRuntime.java
+++ b/tenant-cd-api/src/main/java/ai/vespa/hosted/cd/TestRuntime.java
@@ -1,6 +1,7 @@
// Copyright Yahoo. Licensed under the terms of the Apache 2.0 license. See LICENSE in the project root.
package ai.vespa.hosted.cd;
+import ai.vespa.cloud.ApplicationId;
import ai.vespa.cloud.Zone;
import ai.vespa.hosted.cd.internal.TestRuntimeProvider;
@@ -33,4 +34,6 @@ public interface TestRuntime {
Zone zone();
+ ApplicationId application();
+
}
diff --git a/tenant-cd-commons/src/main/java/ai/vespa/hosted/cd/commons/HttpDeployment.java b/tenant-cd-commons/src/main/java/ai/vespa/hosted/cd/commons/HttpDeployment.java
index 1abdc4d4297..15f6b1f009a 100644
--- a/tenant-cd-commons/src/main/java/ai/vespa/hosted/cd/commons/HttpDeployment.java
+++ b/tenant-cd-commons/src/main/java/ai/vespa/hosted/cd/commons/HttpDeployment.java
@@ -6,6 +6,7 @@ import ai.vespa.hosted.cd.Endpoint;
import ai.vespa.hosted.cd.EndpointAuthenticator;
import java.net.URI;
+import java.time.Instant;
import java.util.Map;
import java.util.NoSuchElementException;
import java.util.stream.Collectors;
@@ -18,9 +19,16 @@ import java.util.stream.Collectors;
public class HttpDeployment implements Deployment {
private final Map<String, Endpoint> endpoints;
+ private final String platform;
+ private final long revision;
+ private final Instant deployedAt;
/** Creates a representation of the given deployment endpoints, using the authenticator for data plane access. */
- public HttpDeployment(Map<String, URI> endpoints, EndpointAuthenticator authenticator) {
+ public HttpDeployment(String platform, long revision, Instant deployedAt,
+ Map<String, URI> endpoints, EndpointAuthenticator authenticator) {
+ this.platform = platform;
+ this.revision = revision;
+ this.deployedAt = deployedAt;
this.endpoints = endpoints.entrySet().stream()
.collect(Collectors.toUnmodifiableMap(entry -> entry.getKey(),
entry -> new HttpEndpoint(entry.getValue(), authenticator)));
@@ -34,4 +42,19 @@ public class HttpDeployment implements Deployment {
return endpoints.get(id);
}
+ @Override
+ public String platformVersion() {
+ return platform;
+ }
+
+ @Override
+ public long applicationVersion() {
+ return revision;
+ }
+
+ @Override
+ public Instant deployedAt() {
+ return deployedAt;
+ }
+
}
diff --git a/vespa-osgi-testrunner/src/test/java/com/yahoo/vespa/test/samples/UsingTestRuntimeTest.java b/vespa-osgi-testrunner/src/test/java/com/yahoo/vespa/test/samples/UsingTestRuntimeTest.java
index acb41bb42be..be60ef554af 100644
--- a/vespa-osgi-testrunner/src/test/java/com/yahoo/vespa/test/samples/UsingTestRuntimeTest.java
+++ b/vespa-osgi-testrunner/src/test/java/com/yahoo/vespa/test/samples/UsingTestRuntimeTest.java
@@ -17,6 +17,9 @@ public class UsingTestRuntimeTest {
assertEquals(Environment.test, runtime.zone().environment());
assertEquals("name", runtime.zone().region());
assertNull(runtime.deploymentToTest().endpoint("dummy"));
+ assertEquals("1.2.3", runtime.deploymentToTest().platformVersion());
+ assertEquals(321, runtime.deploymentToTest().applicationVersion());
+ assertEquals(1000, runtime.deploymentToTest().deployedAt().toEpochMilli());
}
}
diff --git a/vespa-osgi-testrunner/src/test/java/com/yahoo/vespa/testrunner/JunitRunnerTest.java b/vespa-osgi-testrunner/src/test/java/com/yahoo/vespa/testrunner/JunitRunnerTest.java
index 8e330b0228e..51acd4b1fdf 100644
--- a/vespa-osgi-testrunner/src/test/java/com/yahoo/vespa/testrunner/JunitRunnerTest.java
+++ b/vespa-osgi-testrunner/src/test/java/com/yahoo/vespa/testrunner/JunitRunnerTest.java
@@ -1,8 +1,10 @@
package com.yahoo.vespa.testrunner;
+import ai.vespa.cloud.ApplicationId;
import ai.vespa.cloud.Environment;
import ai.vespa.cloud.Zone;
import ai.vespa.hosted.cd.Deployment;
+import ai.vespa.hosted.cd.Endpoint;
import ai.vespa.hosted.cd.TestRuntime;
import com.yahoo.vespa.testrunner.TestReport.Status;
import com.yahoo.vespa.testrunner.TestRunner.Suite;
@@ -169,7 +171,12 @@ class JunitRunnerTest {
@Override
public Deployment deploymentToTest() {
- return __ -> null;
+ return new Deployment() {
+ @Override public Endpoint endpoint(String id) { return null; }
+ @Override public String platformVersion() { return "1.2.3"; }
+ @Override public long applicationVersion() { return 321; }
+ @Override public Instant deployedAt() { return Instant.ofEpochMilli(1000); }
+ };
}
@Override
@@ -177,6 +184,11 @@ class JunitRunnerTest {
return new Zone(Environment.test, "name");
}
+ @Override
+ public ApplicationId application() {
+ return null;
+ }
+
}
}