aboutsummaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
-rw-r--r--controller-server/src/main/java/com/yahoo/vespa/hosted/controller/deployment/DeploymentStatus.java3
-rw-r--r--controller-server/src/main/java/com/yahoo/vespa/hosted/controller/deployment/InternalStepRunner.java52
-rw-r--r--controller-server/src/main/java/com/yahoo/vespa/hosted/controller/restapi/application/ApplicationApiHandler.java2
-rw-r--r--controller-server/src/main/java/com/yahoo/vespa/hosted/controller/restapi/application/JobControllerApiHandlerHelper.java82
-rw-r--r--controller-server/src/test/java/com/yahoo/vespa/hosted/controller/deployment/ApplicationPackageBuilder.java2
-rw-r--r--controller-server/src/test/java/com/yahoo/vespa/hosted/controller/deployment/InternalStepRunnerTest.java10
-rw-r--r--controller-server/src/test/java/com/yahoo/vespa/hosted/controller/restapi/application/JobControllerApiHandlerHelperTest.java11
-rw-r--r--controller-server/src/test/java/com/yahoo/vespa/hosted/controller/restapi/application/responses/deployment-overview-2.json356
-rw-r--r--controller-server/src/test/java/com/yahoo/vespa/hosted/controller/restapi/application/responses/deployment-overview.json138
-rw-r--r--controller-server/src/test/resources/test_runner_services.xml-cd43
-rw-r--r--flags/src/main/java/com/yahoo/vespa/flags/Flags.java9
-rw-r--r--orchestrator/src/main/java/com/yahoo/vespa/orchestrator/OrchestratorContext.java22
-rw-r--r--orchestrator/src/main/java/com/yahoo/vespa/orchestrator/OrchestratorImpl.java29
-rw-r--r--orchestrator/src/main/java/com/yahoo/vespa/orchestrator/model/ApplicationApi.java9
-rw-r--r--orchestrator/src/main/java/com/yahoo/vespa/orchestrator/model/ApplicationApiImpl.java10
-rw-r--r--orchestrator/src/main/java/com/yahoo/vespa/orchestrator/policy/HostedVespaPolicy.java19
-rw-r--r--orchestrator/src/test/java/com/yahoo/vespa/orchestrator/model/ApplicationApiImplTest.java2
-rw-r--r--orchestrator/src/test/java/com/yahoo/vespa/orchestrator/policy/HostedVespaPolicyTest.java4
-rw-r--r--searchlib/src/tests/tensor/hnsw_index/hnsw_index_test.cpp35
-rw-r--r--searchlib/src/vespa/searchlib/tensor/hnsw_index.cpp23
-rw-r--r--searchlib/src/vespa/searchlib/tensor/hnsw_index_base.cpp11
-rw-r--r--searchlib/src/vespa/searchlib/tensor/hnsw_index_base.h1
-rw-r--r--staging_vespalib/src/vespa/vespalib/util/process_memory_stats.cpp2
23 files changed, 344 insertions, 531 deletions
diff --git a/controller-server/src/main/java/com/yahoo/vespa/hosted/controller/deployment/DeploymentStatus.java b/controller-server/src/main/java/com/yahoo/vespa/hosted/controller/deployment/DeploymentStatus.java
index 35ec6c8d769..3a60c480100 100644
--- a/controller-server/src/main/java/com/yahoo/vespa/hosted/controller/deployment/DeploymentStatus.java
+++ b/controller-server/src/main/java/com/yahoo/vespa/hosted/controller/deployment/DeploymentStatus.java
@@ -52,8 +52,7 @@ import static java.util.stream.Collectors.toUnmodifiableMap;
public class DeploymentStatus {
public static List<JobId> jobsFor(Application application, SystemName system) {
- if ( DeploymentSpec.empty.equals(application.deploymentSpec())
- || application.projectId().isEmpty())
+ if (DeploymentSpec.empty.equals(application.deploymentSpec()))
return List.of();
return application.deploymentSpec().instances().stream()
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 a6ebea7fbdf..61dc249feaa 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
@@ -714,8 +714,7 @@ public class InternalStepRunner implements StepRunner {
ZoneId zone = id.type().zone(controller.system());
boolean useTesterCertificate = controller.system().isPublic() && id.type().environment().isTest();
- byte[] servicesXml = servicesXml(controller.zoneRegistry().accessControlDomain(),
- ! controller.system().isPublic(),
+ byte[] servicesXml = servicesXml(! controller.system().isPublic(),
useTesterCertificate,
testerResourcesFor(zone, spec.requireInstance(id.application().instance())));
byte[] testPackage = controller.applications().applicationStore().getTester(id.application().tenant(), id.application().application(), version);
@@ -766,8 +765,7 @@ public class InternalStepRunner implements StepRunner {
}
/** Returns the generated services.xml content for the tester application. */
- static byte[] servicesXml(AthenzDomain domain, boolean systemUsesAthenz, boolean useTesterCertificate,
- NodeResources resources) {
+ static byte[] servicesXml(boolean systemUsesAthenz, boolean useTesterCertificate, NodeResources resources) {
int jdiscMemoryGb = 2; // 2Gb memory for tester application (excessive?).
int jdiscMemoryPct = (int) Math.ceil(100 * jdiscMemoryGb / resources.memoryGb());
@@ -778,7 +776,6 @@ public class InternalStepRunner implements StepRunner {
"<resources vcpu=\"%.2f\" memory=\"%.2fGb\" disk=\"%.2fGb\" disk-speed=\"%s\" storage-type=\"%s\"/>",
resources.vcpu(), resources.memoryGb(), resources.diskGb(), resources.diskSpeed().name(), resources.storageType().name());
- AthenzDomain idDomain = ("vespa.vespa.cd".equals(domain.value()) ? AthenzDomain.from("vespa.vespa") : domain);
String servicesXml =
"<?xml version='1.0' encoding='UTF-8'?>\n" +
"<services xmlns:deploy='vespa' version='1.0'>\n" +
@@ -797,51 +794,6 @@ public class InternalStepRunner implements StepRunner {
" <binding>http://*/tester/v1/*</binding>\n" +
" </handler>\n" +
"\n" +
- " <http>\n" +
- " <!-- Make sure 4080 is the first port. This will be used by the config server. -->\n" +
- " <server id='default' port='4080'/>\n" +
- " <server id='testertls4443' port='4443'>\n" +
- " <config name=\"jdisc.http.connector\">\n" +
- " <tlsClientAuthEnforcer>\n" +
- " <enable>true</enable>\n" +
- " <pathWhitelist>\n" +
- " <item>/status.html</item>\n" +
- " <item>/state/v1/config</item>\n" +
- " </pathWhitelist>\n" +
- " </tlsClientAuthEnforcer>\n" +
- " </config>\n" +
- " <ssl>\n" +
- " <private-key-file>/var/lib/sia/keys/" + idDomain.value() + ".tenant.key.pem</private-key-file>\n" +
- " <certificate-file>/var/lib/sia/certs/" + idDomain.value() + ".tenant.cert.pem</certificate-file>\n" +
- " <ca-certificates-file>/opt/yahoo/share/ssl/certs/athenz_certificate_bundle.pem</ca-certificates-file>\n" +
- " <client-authentication>want</client-authentication>\n" +
- " </ssl>\n" +
- " </server>\n" +
- " <filtering>\n" +
- (systemUsesAthenz ?
- " <access-control domain='" + domain.value() + "'>\n" + // Set up dummy access control to pass validation :/
- " <exclude>\n" +
- " <binding>http://*/tester/v1/*</binding>\n" +
- " </exclude>\n" +
- " </access-control>\n"
- : "") +
- " <request-chain id=\"testrunner-api\">\n" +
- " <filter id='authz-filter' class='com.yahoo.jdisc.http.filter.security.athenz.AthenzAuthorizationFilter' bundle=\"jdisc-security-filters\">\n" +
- " <config name=\"jdisc.http.filter.security.athenz.athenz-authorization-filter\">\n" +
- " <credentialsToVerify>TOKEN_ONLY</credentialsToVerify>\n" +
- " <roleTokenHeaderName>Yahoo-Role-Auth</roleTokenHeaderName>\n" +
- " </config>\n" +
- " <component id=\"com.yahoo.jdisc.http.filter.security.athenz.StaticRequestResourceMapper\" bundle=\"jdisc-security-filters\">\n" +
- " <config name=\"jdisc.http.filter.security.athenz.static-request-resource-mapper\">\n" +
- " <resourceName>" + domain.value() + ":tester-application</resourceName>\n" +
- " <action>deploy</action>\n" +
- " </config>\n" +
- " </component>\n" +
- " </filter>\n" +
- " </request-chain>\n" +
- " </filtering>\n" +
- " </http>\n" +
- "\n" +
" <nodes count=\"1\" allocated-memory=\"" + jdiscMemoryPct + "%\">\n" +
" " + resourceString + "\n" +
" </nodes>\n" +
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 5bdc3533f65..c06194fcd73 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
@@ -2034,7 +2034,7 @@ public class ApplicationApiHandler extends LoggingRequestHandler {
private HttpResponse submit(String tenant, String application, HttpRequest request) {
Map<String, byte[]> dataParts = parseDataParts(request);
Inspector submitOptions = SlimeUtils.jsonToSlime(dataParts.get(EnvironmentResource.SUBMIT_OPTIONS)).get();
- long projectId = Math.max(1, submitOptions.field("projectId").asLong()); // Absence of this means it's not a prod app :/
+ long projectId = Math.max(1, submitOptions.field("projectId").asLong());
Optional<String> repository = optional("repository", submitOptions);
Optional<String> branch = optional("branch", submitOptions);
Optional<String> commit = optional("commit", submitOptions);
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 339facec231..73cdf28c366 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
@@ -5,7 +5,6 @@ import com.google.common.base.Joiner;
import com.yahoo.component.Version;
import com.yahoo.config.application.api.DeploymentInstanceSpec;
import com.yahoo.config.application.api.DeploymentSpec;
-import com.yahoo.config.application.api.DeploymentSpec.ChangeBlocker;
import com.yahoo.config.provision.ApplicationId;
import com.yahoo.config.provision.SystemName;
import com.yahoo.config.provision.zone.ZoneId;
@@ -42,18 +41,14 @@ import com.yahoo.vespa.hosted.controller.deployment.Versions;
import com.yahoo.vespa.hosted.controller.versions.VespaVersion;
import java.net.URI;
-import java.time.Instant;
-import java.time.format.TextStyle;
import java.util.ArrayDeque;
import java.util.Comparator;
import java.util.Deque;
import java.util.LinkedHashMap;
import java.util.List;
-import java.util.Locale;
import java.util.Map;
import java.util.Optional;
import java.util.stream.Collectors;
-import java.util.stream.Stream;
import static com.yahoo.config.application.api.DeploymentSpec.UpgradePolicy.conservative;
import static com.yahoo.config.application.api.DeploymentSpec.UpgradePolicy.defaultPolicy;
@@ -67,7 +62,6 @@ import static com.yahoo.vespa.hosted.controller.deployment.Step.installReal;
import static com.yahoo.vespa.hosted.controller.versions.VespaVersion.Confidence.broken;
import static com.yahoo.vespa.hosted.controller.versions.VespaVersion.Confidence.high;
import static com.yahoo.vespa.hosted.controller.versions.VespaVersion.Confidence.normal;
-import static java.util.Comparator.naturalOrder;
import static java.util.stream.Collectors.groupingBy;
import static java.util.stream.Collectors.toList;
import static java.util.stream.Collectors.toMap;
@@ -575,42 +569,6 @@ class JobControllerApiHandlerHelper {
stepObject.setBool("declared", stepStatus.isDeclared());
stepObject.setString("instance", stepStatus.instance().value());
- stepStatus.readyAt(change).ifPresent(ready -> stepObject.setLong("readyAt", ready.toEpochMilli()));
- stepStatus.readyAt(change)
- .filter(controller.clock().instant()::isBefore)
- .ifPresent(until -> stepObject.setLong("delayedUntil", until.toEpochMilli()));
- stepStatus.pausedUntil().ifPresent(until -> stepObject.setLong("pausedUntil", until.toEpochMilli()));
- stepStatus.coolingDownUntil(change).ifPresent(until -> stepObject.setLong("coolingDownUntil", until.toEpochMilli()));
- stepStatus.blockedUntil(change).ifPresent(until -> stepObject.setLong("blockedUntil", until.toEpochMilli()));
-
- if (stepStatus.type() == DeploymentStatus.StepType.instance) {
- Cursor deployingObject = stepObject.setObject("deploying");
- if ( ! change.isEmpty()) {
- change.platform().ifPresent(version -> deployingObject.setString("platform", version.toString()));
- change.application().ifPresent(version -> toSlime(deployingObject.setObject("application"), version));
- }
-
- Cursor latestVersionsObject = stepObject.setObject("latestVersions");
- List<ChangeBlocker> blockers = application.deploymentSpec().requireInstance(stepStatus.instance()).changeBlocker();
- latestVersionPreferablyWithNormalConfidenceNAndotNewerThanSystem(controller.versionStatus().versions())
- .ifPresent(latestPlatform -> {
- Cursor latestPlatformObject = latestVersionsObject.setObject("platform");
- latestPlatformObject.setString("platform", latestPlatform.versionNumber().toFullString());
- latestPlatformObject.setLong("at", latestPlatform.committedAt().toEpochMilli());
- latestPlatformObject.setBool("upgrade", application.require(stepStatus.instance()).productionDeployments().values().stream()
- .anyMatch(deployment -> deployment.version().isBefore(latestPlatform.versionNumber())));
- toSlime(latestPlatformObject.setArray("blockers"), blockers.stream().filter(ChangeBlocker::blocksVersions));
- });
- application.latestVersion().ifPresent(latestApplication -> {
- Cursor latestApplicationObject = latestVersionsObject.setObject("application");
- toSlime(latestApplicationObject.setObject("application"), latestApplication);
- latestApplicationObject.setLong("at", latestApplication.buildTime().orElse(Instant.EPOCH).toEpochMilli());
- latestApplicationObject.setBool("upgrade", application.require(stepStatus.instance()).productionDeployments().values().stream()
- .anyMatch(deployment -> deployment.applicationVersion().compareTo(latestApplication) < 0));
- toSlime(latestApplicationObject.setArray("blockers"), blockers.stream().filter(ChangeBlocker::blocksRevisions));
- });
- }
-
stepStatus.job().ifPresent(job -> {
stepObject.setString("jobName", job.type().jobName());
String baseUriForJob = baseUriForDeployments.resolve(baseUriForDeployments.getPath() +
@@ -641,6 +599,13 @@ class JobControllerApiHandlerHelper {
Cursor runObject = toRunArray.addObject();
toSlime(runObject.setObject("versions"), versions);
}
+ stepStatus.readyAt(change).ifPresent(ready -> stepObject.setLong("readyAt", ready.toEpochMilli()));
+ stepStatus.readyAt(change)
+ .filter(controller.clock().instant()::isBefore)
+ .ifPresent(until -> stepObject.setLong("delayedUntil", until.toEpochMilli()));
+ stepStatus.pausedUntil().ifPresent(until -> stepObject.setLong("pausedUntil", until.toEpochMilli()));
+ stepStatus.coolingDownUntil(change).ifPresent(until -> stepObject.setLong("coolingDownUntil", until.toEpochMilli()));
+ stepStatus.blockedUntil(change).ifPresent(until -> stepObject.setLong("blockedUntil", until.toEpochMilli()));
Cursor runsArray = stepObject.setArray("runs");
jobStatus.runs().descendingMap().values().stream().limit(10).forEach(run -> {
@@ -661,11 +626,14 @@ class JobControllerApiHandlerHelper {
});
}
+ // TODO jonmv: Add latest platform and application status.
+
return new SlimeJsonResponse(slime);
}
private static void toSlime(Cursor versionObject, ApplicationVersion version) {
- version.buildNumber().ifPresent(id -> versionObject.setLong("build", id));
+ version.buildNumber().ifPresent(id -> versionObject.setLong("id", id));
+ version.source().ifPresent(source -> versionObject.setString("commit", source.commit()));
version.compileVersion().ifPresent(platform -> versionObject.setString("compileVersion", platform.toFullString()));
version.sourceUrl().ifPresent(url -> versionObject.setString("sourceUrl", url));
version.commit().ifPresent(commit -> versionObject.setString("commit", commit));
@@ -678,33 +646,5 @@ class JobControllerApiHandlerHelper {
versions.sourceApplication().ifPresent(application -> toSlime(versionsObject.setObject("sourceApplication"), application));
}
- private static void toSlime(Cursor blockersArray, Stream<ChangeBlocker> blockers) {
- blockers.forEach(blocker -> {
- Cursor blockerObject = blockersArray.addObject();
- blocker.window().days().stream()
- .map(day -> day.getDisplayName(TextStyle.SHORT, Locale.ENGLISH))
- .forEach(blockerObject.setArray("days")::addString);
- blocker.window().hours()
- .forEach(blockerObject.setArray("hours")::addLong);
- blockerObject.setString("zone", blocker.window().zone().toString());
- });
- }
-
- private static Optional<VespaVersion> latestVersionPreferablyWithNormalConfidenceNAndotNewerThanSystem(List<VespaVersion> versions) {
- int i;
- for (i = versions.size(); i-- > 0; )
- if (versions.get(i).isSystemVersion())
- break;
-
- if (i < 0)
- return Optional.empty();
-
- for (int j = i; j >= 0; j--)
- if (versions.get(j).confidence().equalOrHigherThan(normal))
- return Optional.of(versions.get(j));
-
- return Optional.of(versions.get(i));
- }
-
}
diff --git a/controller-server/src/test/java/com/yahoo/vespa/hosted/controller/deployment/ApplicationPackageBuilder.java b/controller-server/src/test/java/com/yahoo/vespa/hosted/controller/deployment/ApplicationPackageBuilder.java
index ed7ae12168f..9b0706d184f 100644
--- a/controller-server/src/test/java/com/yahoo/vespa/hosted/controller/deployment/ApplicationPackageBuilder.java
+++ b/controller-server/src/test/java/com/yahoo/vespa/hosted/controller/deployment/ApplicationPackageBuilder.java
@@ -201,11 +201,11 @@ public class ApplicationPackageBuilder {
xml.append("'/>\n");
}
xml.append(notifications);
+ xml.append(blockChange);
if (explicitSystemTest)
xml.append(" <test />\n");
if (explicitStagingTest)
xml.append(" <staging />\n");
- xml.append(blockChange);
xml.append(" <");
xml.append(environment.value());
if (globalServiceId != null) {
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 8ecdd63fa8f..db07aff34e5 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
@@ -4,7 +4,6 @@ package com.yahoo.vespa.hosted.controller.deployment;
import com.google.common.collect.ImmutableList;
import com.yahoo.component.Version;
import com.yahoo.config.application.api.DeploymentSpec;
-import com.yahoo.config.provision.AthenzDomain;
import com.yahoo.config.provision.HostName;
import com.yahoo.config.provision.NodeResources;
import com.yahoo.config.provision.SystemName;
@@ -487,10 +486,11 @@ public class InternalStepRunnerTest {
@Test
public void generates_correct_services_xml_test() {
- assertFile("test_runner_services.xml-cd", new String(InternalStepRunner.servicesXml(AthenzDomain.from("vespa.vespa.cd"),
- true,
- false,
- new NodeResources(2, 12, 75, 1, NodeResources.DiskSpeed.fast, NodeResources.StorageType.local))));
+ assertFile("test_runner_services.xml-cd",
+ new String(InternalStepRunner.servicesXml(
+ true,
+ false,
+ new NodeResources(2, 12, 75, 1, NodeResources.DiskSpeed.fast, NodeResources.StorageType.local))));
}
private void assertFile(String resourceName, String actualContent) {
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 1c96f46dd31..186534dd288 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
@@ -5,12 +5,15 @@ import com.yahoo.component.Version;
import com.yahoo.config.provision.zone.ZoneId;
import com.yahoo.container.jdisc.HttpResponse;
import com.yahoo.vespa.hosted.controller.api.application.v4.model.DeployOptions;
+import com.yahoo.vespa.hosted.controller.api.identifiers.DeploymentId;
import com.yahoo.vespa.hosted.controller.api.integration.configserver.ConfigServerException;
import com.yahoo.vespa.hosted.controller.api.integration.deployment.ApplicationVersion;
import com.yahoo.vespa.hosted.controller.api.integration.deployment.JobType;
import com.yahoo.vespa.hosted.controller.application.ApplicationPackage;
import com.yahoo.vespa.hosted.controller.deployment.ApplicationPackageBuilder;
import com.yahoo.vespa.hosted.controller.deployment.DeploymentTester;
+import com.yahoo.vespa.hosted.controller.deployment.InternalStepRunner;
+import com.yahoo.vespa.hosted.controller.deployment.RunStatus;
import org.json.JSONException;
import org.json.JSONObject;
import org.junit.Test;
@@ -23,7 +26,6 @@ import java.nio.file.Path;
import java.nio.file.Paths;
import java.time.Duration;
import java.time.Instant;
-import java.util.Date;
import java.util.Optional;
import static com.yahoo.vespa.hosted.controller.api.integration.configserver.ConfigServerException.ErrorCode.INVALID_APPLICATION_PACKAGE;
@@ -35,10 +37,13 @@ import static com.yahoo.vespa.hosted.controller.api.integration.deployment.JobTy
import static com.yahoo.vespa.hosted.controller.api.integration.deployment.JobType.stagingTest;
import static com.yahoo.vespa.hosted.controller.api.integration.deployment.JobType.systemTest;
import static com.yahoo.vespa.hosted.controller.api.integration.deployment.JobType.testUsCentral1;
+import static com.yahoo.vespa.hosted.controller.api.integration.deployment.TesterCloud.Status.FAILURE;
import static com.yahoo.vespa.hosted.controller.deployment.DeploymentContext.applicationPackage;
import static com.yahoo.vespa.hosted.controller.deployment.RunStatus.deploymentFailed;
+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 org.junit.Assert.assertEquals;
/**
@@ -51,9 +56,6 @@ public class JobControllerApiHandlerHelperTest {
public void testResponses() {
ApplicationPackage applicationPackage = new ApplicationPackageBuilder()
.stagingTest()
- .blockChange(true, true, "mon,tue", "7-13", "UTC")
- .blockChange(false, true, "sun", "0-23", "CET")
- .blockChange(true, false, "fri-sat", "8", "America/Los_Angeles")
.region("us-central-1")
.test("us-central-1")
.parallel("us-west-1", "us-east-3")
@@ -137,6 +139,7 @@ public class JobControllerApiHandlerHelperTest {
userApp.runJob(devAwsUsEast2a, applicationPackage);
assertResponse(JobControllerApiHandlerHelper.runResponse(tester.jobs().runs(userApp.instanceId(), devAwsUsEast2a), URI.create("https://some.url:43/root")), "dev-aws-us-east-2a-runs.json");
assertResponse(JobControllerApiHandlerHelper.jobTypeResponse(tester.controller(), userApp.instanceId(), URI.create("https://some.url:43/root/")), "overview-user-instance.json");
+
assertResponse(JobControllerApiHandlerHelper.overviewResponse(tester.controller(), app.application().id(), URI.create("https://some.url:43/root/")), "deployment-overview-2.json");
}
diff --git a/controller-server/src/test/java/com/yahoo/vespa/hosted/controller/restapi/application/responses/deployment-overview-2.json b/controller-server/src/test/java/com/yahoo/vespa/hosted/controller/restapi/application/responses/deployment-overview-2.json
index de88f914d44..a8be282deaf 100644
--- a/controller-server/src/test/java/com/yahoo/vespa/hosted/controller/restapi/application/responses/deployment-overview-2.json
+++ b/controller-server/src/test/java/com/yahoo/vespa/hosted/controller/restapi/application/responses/deployment-overview-2.json
@@ -6,123 +6,19 @@
"type": "instance",
"dependencies": [],
"declared": true,
- "instance": "default",
- "readyAt": 0,
- "deploying": {
- "application": {
- "build": 3,
- "compileVersion": "6.1.0",
- "sourceUrl": "repository1/tree/commit1",
- "commit": "commit1"
- }
- },
- "latestVersions": {
- "platform": {
- "platform": "7.1.0",
- "at": 0,
- "upgrade": true,
- "blockers": [
- {
- "days": [
- "Mon",
- "Tue"
- ],
- "hours": [
- 7,
- 8,
- 9,
- 10,
- 11,
- 12,
- 13
- ],
- "zone": "UTC"
- },
- {
- "days": [
- "Sun"
- ],
- "hours": [
- 0,
- 1,
- 2,
- 3,
- 4,
- 5,
- 6,
- 7,
- 8,
- 9,
- 10,
- 11,
- 12,
- 13,
- 14,
- 15,
- 16,
- 17,
- 18,
- 19,
- 20,
- 21,
- 22,
- 23
- ],
- "zone": "CET"
- }
- ]
- },
- "application": {
- "application": {
- "build": 3,
- "compileVersion": "6.1.0",
- "sourceUrl": "repository1/tree/commit1",
- "commit": "commit1"
- },
- "at": 1000,
- "upgrade": true,
- "blockers": [
- {
- "days": [
- "Mon",
- "Tue"
- ],
- "hours": [
- 7,
- 8,
- 9,
- 10,
- 11,
- 12,
- 13
- ],
- "zone": "UTC"
- },
- {
- "days": [
- "Fri",
- "Sat"
- ],
- "hours": [
- 8
- ],
- "zone": "America/Los_Angeles"
- }
- ]
- }
- }
+ "instance": "default"
},
{
"type": "test",
"dependencies": [],
"declared": false,
"instance": "default",
- "readyAt": 0,
"jobName": "system-test",
"url": "https://some.url:43/instance/default/job/system-test",
"environment": "test",
"region": "test.us-east-1",
"toRun": [],
+ "readyAt": 0,
"runs": [
{
"id": 3,
@@ -133,17 +29,17 @@
"versions": {
"targetPlatform": "6.1.0",
"targetApplication": {
- "build": 3,
+ "id": 3,
+ "commit": "commit1",
"compileVersion": "6.1.0",
- "sourceUrl": "repository1/tree/commit1",
- "commit": "commit1"
+ "sourceUrl": "repository1/tree/commit1"
},
"sourcePlatform": "6.1.0",
"sourceApplication": {
- "build": 2,
+ "id": 2,
+ "commit": "commit1",
"compileVersion": "6.1.0",
- "sourceUrl": "repository1/tree/commit1",
- "commit": "commit1"
+ "sourceUrl": "repository1/tree/commit1"
}
},
"steps": [
@@ -198,17 +94,17 @@
"versions": {
"targetPlatform": "6.1.0",
"targetApplication": {
- "build": 2,
+ "id": 2,
+ "commit": "commit1",
"compileVersion": "6.1.0",
- "sourceUrl": "repository1/tree/commit1",
- "commit": "commit1"
+ "sourceUrl": "repository1/tree/commit1"
},
"sourcePlatform": "6.1.0",
"sourceApplication": {
- "build": 1,
+ "id": 1,
+ "commit": "commit1",
"compileVersion": "6.1.0",
- "sourceUrl": "repository1/tree/commit1",
- "commit": "commit1"
+ "sourceUrl": "repository1/tree/commit1"
}
},
"steps": [
@@ -263,10 +159,10 @@
"versions": {
"targetPlatform": "6.1.0",
"targetApplication": {
- "build": 1,
+ "id": 1,
+ "commit": "commit1",
"compileVersion": "6.1.0",
- "sourceUrl": "repository1/tree/commit1",
- "commit": "commit1"
+ "sourceUrl": "repository1/tree/commit1"
}
},
"steps": [
@@ -319,9 +215,6 @@
"dependencies": [],
"declared": true,
"instance": "default",
- "readyAt": 4353000,
- "delayedUntil": 4353000,
- "coolingDownUntil": 4353000,
"jobName": "staging-test",
"url": "https://some.url:43/instance/default/job/staging-test",
"environment": "staging",
@@ -331,21 +224,24 @@
"versions": {
"targetPlatform": "6.1.0",
"targetApplication": {
- "build": 3,
+ "id": 3,
+ "commit": "commit1",
"compileVersion": "6.1.0",
- "sourceUrl": "repository1/tree/commit1",
- "commit": "commit1"
+ "sourceUrl": "repository1/tree/commit1"
},
"sourcePlatform": "6.1.0",
"sourceApplication": {
- "build": 1,
+ "id": 1,
+ "commit": "commit1",
"compileVersion": "6.1.0",
- "sourceUrl": "repository1/tree/commit1",
- "commit": "commit1"
+ "sourceUrl": "repository1/tree/commit1"
}
}
}
],
+ "readyAt": 4353000,
+ "delayedUntil": 4353000,
+ "coolingDownUntil": 4353000,
"runs": [
{
"id": 5,
@@ -356,17 +252,17 @@
"versions": {
"targetPlatform": "6.1.0",
"targetApplication": {
- "build": 3,
+ "id": 3,
+ "commit": "commit1",
"compileVersion": "6.1.0",
- "sourceUrl": "repository1/tree/commit1",
- "commit": "commit1"
+ "sourceUrl": "repository1/tree/commit1"
},
"sourcePlatform": "6.1.0",
"sourceApplication": {
- "build": 1,
+ "id": 1,
+ "commit": "commit1",
"compileVersion": "6.1.0",
- "sourceUrl": "repository1/tree/commit1",
- "commit": "commit1"
+ "sourceUrl": "repository1/tree/commit1"
}
},
"steps": [
@@ -437,17 +333,17 @@
"versions": {
"targetPlatform": "6.1.0",
"targetApplication": {
- "build": 3,
+ "id": 3,
+ "commit": "commit1",
"compileVersion": "6.1.0",
- "sourceUrl": "repository1/tree/commit1",
- "commit": "commit1"
+ "sourceUrl": "repository1/tree/commit1"
},
"sourcePlatform": "6.1.0",
"sourceApplication": {
- "build": 1,
+ "id": 1,
+ "commit": "commit1",
"compileVersion": "6.1.0",
- "sourceUrl": "repository1/tree/commit1",
- "commit": "commit1"
+ "sourceUrl": "repository1/tree/commit1"
}
},
"steps": [
@@ -518,17 +414,17 @@
"versions": {
"targetPlatform": "6.1.0",
"targetApplication": {
- "build": 3,
+ "id": 3,
+ "commit": "commit1",
"compileVersion": "6.1.0",
- "sourceUrl": "repository1/tree/commit1",
- "commit": "commit1"
+ "sourceUrl": "repository1/tree/commit1"
},
"sourcePlatform": "6.1.0",
"sourceApplication": {
- "build": 2,
+ "id": 2,
+ "commit": "commit1",
"compileVersion": "6.1.0",
- "sourceUrl": "repository1/tree/commit1",
- "commit": "commit1"
+ "sourceUrl": "repository1/tree/commit1"
}
},
"steps": [
@@ -599,17 +495,17 @@
"versions": {
"targetPlatform": "6.1.0",
"targetApplication": {
- "build": 2,
+ "id": 2,
+ "commit": "commit1",
"compileVersion": "6.1.0",
- "sourceUrl": "repository1/tree/commit1",
- "commit": "commit1"
+ "sourceUrl": "repository1/tree/commit1"
},
"sourcePlatform": "6.1.0",
"sourceApplication": {
- "build": 1,
+ "id": 1,
+ "commit": "commit1",
"compileVersion": "6.1.0",
- "sourceUrl": "repository1/tree/commit1",
- "commit": "commit1"
+ "sourceUrl": "repository1/tree/commit1"
}
},
"steps": [
@@ -680,10 +576,10 @@
"versions": {
"targetPlatform": "6.1.0",
"targetApplication": {
- "build": 1,
+ "id": 1,
+ "commit": "commit1",
"compileVersion": "6.1.0",
- "sourceUrl": "repository1/tree/commit1",
- "commit": "commit1"
+ "sourceUrl": "repository1/tree/commit1"
}
},
"steps": [
@@ -755,19 +651,19 @@
],
"declared": true,
"instance": "default",
- "readyAt": 3603000,
"jobName": "production-us-central-1",
"url": "https://some.url:43/instance/default/job/production-us-central-1",
"environment": "prod",
"region": "prod.us-central-1",
"currentPlatform": "6.1.0",
"currentApplication": {
- "build": 3,
+ "id": 3,
+ "commit": "commit1",
"compileVersion": "6.1.0",
- "sourceUrl": "repository1/tree/commit1",
- "commit": "commit1"
+ "sourceUrl": "repository1/tree/commit1"
},
"toRun": [],
+ "readyAt": 3603000,
"runs": [
{
"id": 3,
@@ -777,17 +673,17 @@
"versions": {
"targetPlatform": "6.1.0",
"targetApplication": {
- "build": 3,
+ "id": 3,
+ "commit": "commit1",
"compileVersion": "6.1.0",
- "sourceUrl": "repository1/tree/commit1",
- "commit": "commit1"
+ "sourceUrl": "repository1/tree/commit1"
},
"sourcePlatform": "6.1.0",
"sourceApplication": {
- "build": 2,
+ "id": 2,
+ "commit": "commit1",
"compileVersion": "6.1.0",
- "sourceUrl": "repository1/tree/commit1",
- "commit": "commit1"
+ "sourceUrl": "repository1/tree/commit1"
}
},
"steps": [
@@ -814,17 +710,17 @@
"versions": {
"targetPlatform": "6.1.0",
"targetApplication": {
- "build": 2,
+ "id": 2,
+ "commit": "commit1",
"compileVersion": "6.1.0",
- "sourceUrl": "repository1/tree/commit1",
- "commit": "commit1"
+ "sourceUrl": "repository1/tree/commit1"
},
"sourcePlatform": "6.1.0",
"sourceApplication": {
- "build": 1,
+ "id": 1,
+ "commit": "commit1",
"compileVersion": "6.1.0",
- "sourceUrl": "repository1/tree/commit1",
- "commit": "commit1"
+ "sourceUrl": "repository1/tree/commit1"
}
},
"steps": [
@@ -851,10 +747,10 @@
"versions": {
"targetPlatform": "6.1.0",
"targetApplication": {
- "build": 1,
+ "id": 1,
+ "commit": "commit1",
"compileVersion": "6.1.0",
- "sourceUrl": "repository1/tree/commit1",
- "commit": "commit1"
+ "sourceUrl": "repository1/tree/commit1"
}
},
"steps": [
@@ -890,17 +786,17 @@
"versions": {
"targetPlatform": "6.1.0",
"targetApplication": {
- "build": 3,
+ "id": 3,
+ "commit": "commit1",
"compileVersion": "6.1.0",
- "sourceUrl": "repository1/tree/commit1",
- "commit": "commit1"
+ "sourceUrl": "repository1/tree/commit1"
},
"sourcePlatform": "6.1.0",
"sourceApplication": {
- "build": 3,
+ "id": 3,
+ "commit": "commit1",
"compileVersion": "6.1.0",
- "sourceUrl": "repository1/tree/commit1",
- "commit": "commit1"
+ "sourceUrl": "repository1/tree/commit1"
}
}
}
@@ -915,17 +811,17 @@
"versions": {
"targetPlatform": "6.1.0",
"targetApplication": {
- "build": 2,
+ "id": 2,
+ "commit": "commit1",
"compileVersion": "6.1.0",
- "sourceUrl": "repository1/tree/commit1",
- "commit": "commit1"
+ "sourceUrl": "repository1/tree/commit1"
},
"sourcePlatform": "6.1.0",
"sourceApplication": {
- "build": 2,
+ "id": 2,
+ "commit": "commit1",
"compileVersion": "6.1.0",
- "sourceUrl": "repository1/tree/commit1",
- "commit": "commit1"
+ "sourceUrl": "repository1/tree/commit1"
}
},
"steps": [
@@ -964,17 +860,17 @@
"versions": {
"targetPlatform": "6.1.0",
"targetApplication": {
- "build": 1,
+ "id": 1,
+ "commit": "commit1",
"compileVersion": "6.1.0",
- "sourceUrl": "repository1/tree/commit1",
- "commit": "commit1"
+ "sourceUrl": "repository1/tree/commit1"
},
"sourcePlatform": "6.1.0",
"sourceApplication": {
- "build": 1,
+ "id": 1,
+ "commit": "commit1",
"compileVersion": "6.1.0",
- "sourceUrl": "repository1/tree/commit1",
- "commit": "commit1"
+ "sourceUrl": "repository1/tree/commit1"
}
},
"steps": [
@@ -1019,27 +915,27 @@
"region": "prod.us-west-1",
"currentPlatform": "6.1.0",
"currentApplication": {
- "build": 2,
+ "id": 2,
+ "commit": "commit1",
"compileVersion": "6.1.0",
- "sourceUrl": "repository1/tree/commit1",
- "commit": "commit1"
+ "sourceUrl": "repository1/tree/commit1"
},
"toRun": [
{
"versions": {
"targetPlatform": "6.1.0",
"targetApplication": {
- "build": 3,
+ "id": 3,
+ "commit": "commit1",
"compileVersion": "6.1.0",
- "sourceUrl": "repository1/tree/commit1",
- "commit": "commit1"
+ "sourceUrl": "repository1/tree/commit1"
},
"sourcePlatform": "6.1.0",
"sourceApplication": {
- "build": 2,
+ "id": 2,
+ "commit": "commit1",
"compileVersion": "6.1.0",
- "sourceUrl": "repository1/tree/commit1",
- "commit": "commit1"
+ "sourceUrl": "repository1/tree/commit1"
}
}
}
@@ -1054,17 +950,17 @@
"versions": {
"targetPlatform": "6.1.0",
"targetApplication": {
- "build": 2,
+ "id": 2,
+ "commit": "commit1",
"compileVersion": "6.1.0",
- "sourceUrl": "repository1/tree/commit1",
- "commit": "commit1"
+ "sourceUrl": "repository1/tree/commit1"
},
"sourcePlatform": "6.1.0",
"sourceApplication": {
- "build": 1,
+ "id": 1,
+ "commit": "commit1",
"compileVersion": "6.1.0",
- "sourceUrl": "repository1/tree/commit1",
- "commit": "commit1"
+ "sourceUrl": "repository1/tree/commit1"
}
},
"steps": [
@@ -1091,10 +987,10 @@
"versions": {
"targetPlatform": "6.1.0",
"targetApplication": {
- "build": 1,
+ "id": 1,
+ "commit": "commit1",
"compileVersion": "6.1.0",
- "sourceUrl": "repository1/tree/commit1",
- "commit": "commit1"
+ "sourceUrl": "repository1/tree/commit1"
}
},
"steps": [
@@ -1127,27 +1023,27 @@
"region": "prod.us-east-3",
"currentPlatform": "6.1.0",
"currentApplication": {
- "build": 1,
+ "id": 1,
+ "commit": "commit1",
"compileVersion": "6.1.0",
- "sourceUrl": "repository1/tree/commit1",
- "commit": "commit1"
+ "sourceUrl": "repository1/tree/commit1"
},
"toRun": [
{
"versions": {
"targetPlatform": "6.1.0",
"targetApplication": {
- "build": 3,
+ "id": 3,
+ "commit": "commit1",
"compileVersion": "6.1.0",
- "sourceUrl": "repository1/tree/commit1",
- "commit": "commit1"
+ "sourceUrl": "repository1/tree/commit1"
},
"sourcePlatform": "6.1.0",
"sourceApplication": {
- "build": 1,
+ "id": 1,
+ "commit": "commit1",
"compileVersion": "6.1.0",
- "sourceUrl": "repository1/tree/commit1",
- "commit": "commit1"
+ "sourceUrl": "repository1/tree/commit1"
}
}
}
@@ -1162,17 +1058,17 @@
"versions": {
"targetPlatform": "6.1.0",
"targetApplication": {
- "build": 2,
+ "id": 2,
+ "commit": "commit1",
"compileVersion": "6.1.0",
- "sourceUrl": "repository1/tree/commit1",
- "commit": "commit1"
+ "sourceUrl": "repository1/tree/commit1"
},
"sourcePlatform": "6.1.0",
"sourceApplication": {
- "build": 1,
+ "id": 1,
+ "commit": "commit1",
"compileVersion": "6.1.0",
- "sourceUrl": "repository1/tree/commit1",
- "commit": "commit1"
+ "sourceUrl": "repository1/tree/commit1"
}
},
"steps": [
@@ -1199,10 +1095,10 @@
"versions": {
"targetPlatform": "6.1.0",
"targetApplication": {
- "build": 1,
+ "id": 1,
+ "commit": "commit1",
"compileVersion": "6.1.0",
- "sourceUrl": "repository1/tree/commit1",
- "commit": "commit1"
+ "sourceUrl": "repository1/tree/commit1"
}
},
"steps": [
diff --git a/controller-server/src/test/java/com/yahoo/vespa/hosted/controller/restapi/application/responses/deployment-overview.json b/controller-server/src/test/java/com/yahoo/vespa/hosted/controller/restapi/application/responses/deployment-overview.json
index e75ebc923bd..027cca5dad2 100644
--- a/controller-server/src/test/java/com/yahoo/vespa/hosted/controller/restapi/application/responses/deployment-overview.json
+++ b/controller-server/src/test/java/com/yahoo/vespa/hosted/controller/restapi/application/responses/deployment-overview.json
@@ -6,47 +6,19 @@
"type": "instance",
"dependencies": [],
"declared": true,
- "instance": "instance1",
- "readyAt": 0,
- "deploying": {
- "application": {
- "build": 4,
- "compileVersion": "6.1.0",
- "sourceUrl": "repository1/tree/commit1",
- "commit": "commit1"
- }
- },
- "latestVersions": {
- "platform": {
- "platform": "6.1.0",
- "at": "(ignore)",
- "upgrade": false,
- "blockers": []
- },
- "application": {
- "application": {
- "build": 4,
- "compileVersion": "6.1.0",
- "sourceUrl": "repository1/tree/commit1",
- "commit": "commit1"
- },
- "at": 1000,
- "upgrade": false,
- "blockers": []
- }
- }
+ "instance": "instance1"
},
{
"type": "test",
"dependencies": [],
"declared": false,
"instance": "instance1",
- "readyAt": 0,
"jobName": "system-test",
"url": "http://localhost:8080/application/v4/tenant/tenant1/application/application1/instance/instance1/job/system-test",
"environment": "test",
"region": "test.us-east-1",
"toRun": [],
+ "readyAt": 0,
"runs": [
{
"id": 2,
@@ -56,10 +28,10 @@
"versions": {
"targetPlatform": "6.1.0",
"targetApplication": {
- "build": 4,
+ "id": 4,
+ "commit": "commit1",
"compileVersion": "6.1.0",
- "sourceUrl": "repository1/tree/commit1",
- "commit": "commit1"
+ "sourceUrl": "repository1/tree/commit1"
}
},
"steps": [
@@ -114,10 +86,10 @@
"versions": {
"targetPlatform": "6.1.0",
"targetApplication": {
- "build": 1,
+ "id": 1,
+ "commit": "commit1",
"compileVersion": "6.1.0",
- "sourceUrl": "repository1/tree/commit1",
- "commit": "commit1"
+ "sourceUrl": "repository1/tree/commit1"
}
},
"steps": [
@@ -170,12 +142,12 @@
"dependencies": [],
"declared": false,
"instance": "instance1",
- "readyAt": 0,
"jobName": "staging-test",
"url": "http://localhost:8080/application/v4/tenant/tenant1/application/application1/instance/instance1/job/staging-test",
"environment": "staging",
"region": "staging.us-east-3",
"toRun": [],
+ "readyAt": 0,
"runs": [
{
"id": 2,
@@ -185,10 +157,10 @@
"versions": {
"targetPlatform": "6.1.0",
"targetApplication": {
- "build": 4,
+ "id": 4,
+ "commit": "commit1",
"compileVersion": "6.1.0",
- "sourceUrl": "repository1/tree/commit1",
- "commit": "commit1"
+ "sourceUrl": "repository1/tree/commit1"
}
},
"steps": [
@@ -259,10 +231,10 @@
"versions": {
"targetPlatform": "6.1.0",
"targetApplication": {
- "build": 1,
+ "id": 1,
+ "commit": "commit1",
"compileVersion": "6.1.0",
- "sourceUrl": "repository1/tree/commit1",
- "commit": "commit1"
+ "sourceUrl": "repository1/tree/commit1"
}
},
"steps": [
@@ -342,10 +314,10 @@
"versions": {
"targetPlatform": "6.1.0",
"targetApplication": {
- "build": 4,
+ "id": 4,
+ "commit": "commit1",
"compileVersion": "6.1.0",
- "sourceUrl": "repository1/tree/commit1",
- "commit": "commit1"
+ "sourceUrl": "repository1/tree/commit1"
}
}
}
@@ -360,10 +332,10 @@
"versions": {
"targetPlatform": "6.1.0",
"targetApplication": {
- "build": 1,
+ "id": 1,
+ "commit": "commit1",
"compileVersion": "6.1.0",
- "sourceUrl": "repository1/tree/commit1",
- "commit": "commit1"
+ "sourceUrl": "repository1/tree/commit1"
}
},
"steps": [
@@ -399,10 +371,10 @@
"versions": {
"targetPlatform": "6.1.0",
"targetApplication": {
- "build": 4,
+ "id": 4,
+ "commit": "commit1",
"compileVersion": "6.1.0",
- "sourceUrl": "repository1/tree/commit1",
- "commit": "commit1"
+ "sourceUrl": "repository1/tree/commit1"
}
}
}
@@ -416,9 +388,9 @@
"versions": {
"targetPlatform": "6.1.0",
"targetApplication": {
- "build": 1,
- "sourceUrl": "repository1/tree/commit1",
- "commit": "commit1"
+ "id": 1,
+ "commit": "commit1",
+ "sourceUrl": "repository1/tree/commit1"
}
},
"steps": [
@@ -454,10 +426,10 @@
"versions": {
"targetPlatform": "6.1.0",
"targetApplication": {
- "build": 4,
+ "id": 4,
+ "commit": "commit1",
"compileVersion": "6.1.0",
- "sourceUrl": "repository1/tree/commit1",
- "commit": "commit1"
+ "sourceUrl": "repository1/tree/commit1"
}
}
}
@@ -471,10 +443,10 @@
"versions": {
"targetPlatform": "6.1.0",
"targetApplication": {
- "build": 1,
+ "id": 1,
+ "commit": "commit1",
"compileVersion": "6.1.0",
- "sourceUrl": "repository1/tree/commit1",
- "commit": "commit1"
+ "sourceUrl": "repository1/tree/commit1"
}
},
"steps": [
@@ -501,39 +473,19 @@
5
],
"declared": true,
- "instance": "instance2",
- "deploying": {},
- "latestVersions": {
- "platform": {
- "platform": "6.1.0",
- "at": "(ignore)",
- "upgrade": false,
- "blockers": []
- },
- "application": {
- "application": {
- "build": 4,
- "compileVersion": "6.1.0",
- "sourceUrl": "repository1/tree/commit1",
- "commit": "commit1"
- },
- "at": 1000,
- "upgrade": false,
- "blockers": []
- }
- }
+ "instance": "instance2"
},
{
"type": "test",
"dependencies": [],
"declared": false,
"instance": "instance2",
- "readyAt": 0,
"jobName": "system-test",
"url": "http://localhost:8080/application/v4/tenant/tenant1/application/application1/instance/instance2/job/system-test",
"environment": "test",
"region": "test.us-east-1",
"toRun": [],
+ "readyAt": 0,
"runs": []
},
{
@@ -541,12 +493,12 @@
"dependencies": [],
"declared": false,
"instance": "instance2",
- "readyAt": 0,
"jobName": "staging-test",
"url": "http://localhost:8080/application/v4/tenant/tenant1/application/application1/instance/instance2/job/staging-test",
"environment": "staging",
"region": "staging.us-east-3",
"toRun": [],
+ "readyAt": 0,
"runs": []
},
{
@@ -565,10 +517,10 @@
"versions": {
"targetPlatform": "6.1.0",
"targetApplication": {
- "build": 4,
+ "id": 4,
+ "commit": "commit1",
"compileVersion": "6.1.0",
- "sourceUrl": "repository1/tree/commit1",
- "commit": "commit1"
+ "sourceUrl": "repository1/tree/commit1"
}
}
}
@@ -591,10 +543,10 @@
"versions": {
"targetPlatform": "6.1.0",
"targetApplication": {
- "build": 4,
+ "id": 4,
+ "commit": "commit1",
"compileVersion": "6.1.0",
- "sourceUrl": "repository1/tree/commit1",
- "commit": "commit1"
+ "sourceUrl": "repository1/tree/commit1"
}
}
}
@@ -617,10 +569,10 @@
"versions": {
"targetPlatform": "6.1.0",
"targetApplication": {
- "build": 4,
+ "id": 4,
+ "commit": "commit1",
"compileVersion": "6.1.0",
- "sourceUrl": "repository1/tree/commit1",
- "commit": "commit1"
+ "sourceUrl": "repository1/tree/commit1"
}
}
}
diff --git a/controller-server/src/test/resources/test_runner_services.xml-cd b/controller-server/src/test/resources/test_runner_services.xml-cd
index 235ca7cb698..125c5004d25 100644
--- a/controller-server/src/test/resources/test_runner_services.xml-cd
+++ b/controller-server/src/test/resources/test_runner_services.xml-cd
@@ -15,49 +15,6 @@
<binding>http://*/tester/v1/*</binding>
</handler>
- <http>
- <!-- Make sure 4080 is the first port. This will be used by the config server. -->
- <server id='default' port='4080'/>
- <server id='testertls4443' port='4443'>
- <config name="jdisc.http.connector">
- <tlsClientAuthEnforcer>
- <enable>true</enable>
- <pathWhitelist>
- <item>/status.html</item>
- <item>/state/v1/config</item>
- </pathWhitelist>
- </tlsClientAuthEnforcer>
- </config>
- <ssl>
- <private-key-file>/var/lib/sia/keys/vespa.vespa.tenant.key.pem</private-key-file>
- <certificate-file>/var/lib/sia/certs/vespa.vespa.tenant.cert.pem</certificate-file>
- <ca-certificates-file>/opt/yahoo/share/ssl/certs/athenz_certificate_bundle.pem</ca-certificates-file>
- <client-authentication>want</client-authentication>
- </ssl>
- </server>
- <filtering>
- <access-control domain='vespa.vespa.cd'>
- <exclude>
- <binding>http://*/tester/v1/*</binding>
- </exclude>
- </access-control>
- <request-chain id="testrunner-api">
- <filter id='authz-filter' class='com.yahoo.jdisc.http.filter.security.athenz.AthenzAuthorizationFilter' bundle="jdisc-security-filters">
- <config name="jdisc.http.filter.security.athenz.athenz-authorization-filter">
- <credentialsToVerify>TOKEN_ONLY</credentialsToVerify>
- <roleTokenHeaderName>Yahoo-Role-Auth</roleTokenHeaderName>
- </config>
- <component id="com.yahoo.jdisc.http.filter.security.athenz.StaticRequestResourceMapper" bundle="jdisc-security-filters">
- <config name="jdisc.http.filter.security.athenz.static-request-resource-mapper">
- <resourceName>vespa.vespa.cd:tester-application</resourceName>
- <action>deploy</action>
- </config>
- </component>
- </filter>
- </request-chain>
- </filtering>
- </http>
-
<nodes count="1" allocated-memory="17%">
<resources vcpu="2.00" memory="12.00Gb" disk="75.00Gb" disk-speed="fast" storage-type="local"/>
</nodes>
diff --git a/flags/src/main/java/com/yahoo/vespa/flags/Flags.java b/flags/src/main/java/com/yahoo/vespa/flags/Flags.java
index b6bfbae8644..5ea160b9bc2 100644
--- a/flags/src/main/java/com/yahoo/vespa/flags/Flags.java
+++ b/flags/src/main/java/com/yahoo/vespa/flags/Flags.java
@@ -122,6 +122,13 @@ public class Flags {
"Takes immediate effect for new batch suspensions.",
HOSTNAME);
+ public static final UnboundBooleanFlag RETIRE_WITH_PERMANENTLY_DOWN = defineFeatureFlag(
+ "retire-with-permanently-down", true,
+ "If enabled, retirement will end with setting the host status to PERMANENTLY_DOWN, " +
+ "instead of ALLOWED_TO_BE_DOWN (old behavior).",
+ "Takes effect on the next run of RetiredExpirer.",
+ HOSTNAME);
+
public static final UnboundBooleanFlag ENABLE_DYNAMIC_PROVISIONING = defineFeatureFlag(
"enable-dynamic-provisioning", false,
"Provision a new docker host when we otherwise can't allocate a docker node",
@@ -194,7 +201,7 @@ public class Flags {
APPLICATION_ID);
public static final UnboundBooleanFlag USE_CONFIG_SERVER_FOR_TESTER_API_CALLS = defineFeatureFlag(
- "use-config-server-for-tester-api-calls", false,
+ "use-config-server-for-tester-api-calls", true,
"Whether controller should send requests to tester API through config server (if false) or tester endpoint (if true)",
"Takes effect immediately",
ZONE_ID);
diff --git a/orchestrator/src/main/java/com/yahoo/vespa/orchestrator/OrchestratorContext.java b/orchestrator/src/main/java/com/yahoo/vespa/orchestrator/OrchestratorContext.java
index 17dfb924973..eb6a4119f8a 100644
--- a/orchestrator/src/main/java/com/yahoo/vespa/orchestrator/OrchestratorContext.java
+++ b/orchestrator/src/main/java/com/yahoo/vespa/orchestrator/OrchestratorContext.java
@@ -30,6 +30,7 @@ public class OrchestratorContext implements AutoCloseable {
private final TimeBudget timeBudget;
private final boolean probe;
private final boolean largeLocks;
+ private final boolean usePermanentlyDownStatus;
// The key set is the set of applications locked by this context tree: Only the
// root context has a non-empty set. The value is an unlock callback to be called
@@ -38,24 +39,32 @@ public class OrchestratorContext implements AutoCloseable {
/** Create an OrchestratorContext for operations on multiple applications. */
public static OrchestratorContext createContextForMultiAppOp(Clock clock, boolean largeLocks) {
- return new OrchestratorContext(null, clock, TimeBudget.fromNow(clock, DEFAULT_TIMEOUT_FOR_BATCH_OP), false, largeLocks);
+ return new OrchestratorContext(null, clock, TimeBudget.fromNow(clock, DEFAULT_TIMEOUT_FOR_BATCH_OP),
+ false, largeLocks, false);
}
/** Create an OrchestratorContext for an operation on a single application. */
public static OrchestratorContext createContextForSingleAppOp(Clock clock) {
- return new OrchestratorContext(null, clock, TimeBudget.fromNow(clock, DEFAULT_TIMEOUT_FOR_SINGLE_OP), false, false);
+ return createContextForSingleAppOp(clock, false);
+ }
+
+ public static OrchestratorContext createContextForSingleAppOp(Clock clock, boolean usePermanentlyDownStatus) {
+ return new OrchestratorContext(null, clock, TimeBudget.fromNow(clock, DEFAULT_TIMEOUT_FOR_SINGLE_OP),
+ false, false, usePermanentlyDownStatus);
}
private OrchestratorContext(OrchestratorContext parentOrNull,
Clock clock,
TimeBudget timeBudget,
boolean probe,
- boolean largeLocks) {
+ boolean largeLocks,
+ boolean usePermanentlyDownStatus) {
this.parent = Optional.ofNullable(parentOrNull);
this.clock = clock;
this.timeBudget = timeBudget;
this.probe = probe;
this.largeLocks = largeLocks;
+ this.usePermanentlyDownStatus = usePermanentlyDownStatus;
}
public Duration getTimeLeft() {
@@ -74,6 +83,9 @@ public class OrchestratorContext implements AutoCloseable {
/** Whether application locks acquired during probing of a batch suspend should be closed after the non-probe is done. */
public boolean largeLocks() { return largeLocks; }
+ /** Whether the PERMANENTLY_DOWN host status should be used (where appropriate). */
+ public boolean usePermanentlyDownStatus() { return usePermanentlyDownStatus; }
+
/**
* Returns true if 1. large locks is enabled, and 2.
* {@link #registerLockAcquisition(ApplicationInstanceReference, Runnable) registerLockAcquisition}
@@ -111,7 +123,7 @@ public class OrchestratorContext implements AutoCloseable {
// Move deadline towards past by a fixed amount to ensure there's time to process exceptions and
// access ZooKeeper before the lock times out.
TimeBudget subTimeBudget = timeBudget.withDeadline(timeBudget.deadline().get().minus(TIMEOUT_OVERHEAD));
- return new OrchestratorContext(this, clock, subTimeBudget, probe, largeLocks);
+ return new OrchestratorContext(this, clock, subTimeBudget, probe, largeLocks, usePermanentlyDownStatus);
}
/** Create an OrchestratorContext for an operation on a single application, but limited to current timeout. */
@@ -124,7 +136,7 @@ public class OrchestratorContext implements AutoCloseable {
}
TimeBudget timeBudget = TimeBudget.from(clock, now, Optional.of(Duration.between(now, deadline)));
- return new OrchestratorContext(this, clock, timeBudget, probe, largeLocks);
+ return new OrchestratorContext(this, clock, timeBudget, probe, largeLocks, usePermanentlyDownStatus);
}
@Override
diff --git a/orchestrator/src/main/java/com/yahoo/vespa/orchestrator/OrchestratorImpl.java b/orchestrator/src/main/java/com/yahoo/vespa/orchestrator/OrchestratorImpl.java
index 244fd4d9b5d..414548f8bdc 100644
--- a/orchestrator/src/main/java/com/yahoo/vespa/orchestrator/OrchestratorImpl.java
+++ b/orchestrator/src/main/java/com/yahoo/vespa/orchestrator/OrchestratorImpl.java
@@ -65,6 +65,7 @@ public class OrchestratorImpl implements Orchestrator {
private final Clock clock;
private final ApplicationApiFactory applicationApiFactory;
private final BooleanFlag enableLargeOrchestratorLocks;
+ private final BooleanFlag retireWithPermanentlyDownFlag;
@Inject
public OrchestratorImpl(ClusterControllerClientFactory clusterControllerClientFactory,
@@ -101,6 +102,7 @@ public class OrchestratorImpl implements Orchestrator {
this.clock = clock;
this.applicationApiFactory = applicationApiFactory;
this.enableLargeOrchestratorLocks = Flags.ENABLE_LARGE_ORCHESTRATOR_LOCKS.bindTo(flagSource);
+ this.retireWithPermanentlyDownFlag = Flags.RETIRE_WITH_PERMANENTLY_DOWN.bindTo(flagSource);
}
@Override
@@ -150,6 +152,12 @@ public class OrchestratorImpl implements Orchestrator {
* monitoring will have had time to catch up. Since we don't want do the delay with the lock held,
* and the host status service's locking functionality does not support something like condition
* variables or Object.wait(), we break out here, releasing the lock before delaying.
+ *
+ * 2020-02-07: We should utilize suspendedSince timestamp on the HostInfo: The above
+ * is equivalent to guaranteeing a minimum time after suspendedSince, before checking
+ * the health with service monitor. This should for all practical purposes remove
+ * the amount of time in this sleep.
+ * Caveat: Cannot be implemented before lingering HostInfo has been fixed (VESPA-17546).
*/
sleep(serviceMonitorConvergenceLatencySeconds, TimeUnit.SECONDS);
@@ -159,15 +167,21 @@ public class OrchestratorImpl implements Orchestrator {
try (MutableStatusRegistry statusRegistry = statusService
.lockApplicationInstance_forCurrentThreadOnly(context, appInstance.reference())) {
HostStatus currentHostState = statusRegistry.getHostInfo(hostName).status();
-
- if (HostStatus.NO_REMARKS == currentHostState) {
+ if (currentHostState == HostStatus.NO_REMARKS) {
return;
}
- ApplicationInstanceStatus appStatus = statusRegistry.getStatus();
- if (appStatus == ApplicationInstanceStatus.NO_REMARKS) {
- policy.releaseSuspensionGrant(context.createSubcontextWithinLock(), appInstance, hostName, statusRegistry);
+ // In 2 cases the resume will appear to succeed (no exception thrown),
+ // but the host status and content cluster states will not be changed accordingly:
+ // 1. When host is permanently down: the host will be removed from the application asap.
+ // 2. The whole application is down: the content cluster states are set to maintenance,
+ // and the host may be taken down manually at any moment.
+ if (currentHostState == HostStatus.PERMANENTLY_DOWN ||
+ statusRegistry.getStatus() == ApplicationInstanceStatus.ALLOWED_TO_BE_DOWN) {
+ return;
}
+
+ policy.releaseSuspensionGrant(context.createSubcontextWithinLock(), appInstance, hostName, statusRegistry);
}
}
@@ -183,7 +197,10 @@ public class OrchestratorImpl implements Orchestrator {
ApplicationInstance appInstance = getApplicationInstance(hostName);
NodeGroup nodeGroup = new NodeGroup(appInstance, hostName);
- OrchestratorContext context = OrchestratorContext.createContextForSingleAppOp(clock);
+ boolean usePermanentlyDownStatus = retireWithPermanentlyDownFlag
+ .with(FetchVector.Dimension.HOSTNAME, hostName.s())
+ .value();
+ OrchestratorContext context = OrchestratorContext.createContextForSingleAppOp(clock, usePermanentlyDownStatus);
try (MutableStatusRegistry statusRegistry = statusService
.lockApplicationInstance_forCurrentThreadOnly(context, appInstance.reference())) {
ApplicationApi applicationApi = applicationApiFactory.create(nodeGroup, statusRegistry,
diff --git a/orchestrator/src/main/java/com/yahoo/vespa/orchestrator/model/ApplicationApi.java b/orchestrator/src/main/java/com/yahoo/vespa/orchestrator/model/ApplicationApi.java
index 2e85713d323..a6353e39610 100644
--- a/orchestrator/src/main/java/com/yahoo/vespa/orchestrator/model/ApplicationApi.java
+++ b/orchestrator/src/main/java/com/yahoo/vespa/orchestrator/model/ApplicationApi.java
@@ -8,6 +8,7 @@ import com.yahoo.vespa.orchestrator.status.ApplicationInstanceStatus;
import com.yahoo.vespa.orchestrator.status.HostStatus;
import java.util.List;
+import java.util.function.Predicate;
/**
* The API a Policy has access to
@@ -29,10 +30,12 @@ public interface ApplicationApi {
ApplicationInstanceStatus getApplicationStatus();
void setHostState(OrchestratorContext context, HostName hostName, HostStatus status);
- List<HostName> getNodesInGroupWithStatus(HostStatus status);
+ List<HostName> getNodesInGroupWith(Predicate<HostStatus> statusPredicate);
+ default List<HostName> getNodesInGroupWithStatus(HostStatus requiredStatus) {
+ return getNodesInGroupWith(status -> status == requiredStatus);
+ }
List<StorageNode> getStorageNodesInGroupInClusterOrder();
List<StorageNode> getUpStorageNodesInGroupInClusterOrder();
- List<StorageNode> getStorageNodesAllowedToBeDownInGroupInReverseClusterOrder();
-
+ List<StorageNode> getSuspendedStorageNodesInGroupInReverseClusterOrder();
}
diff --git a/orchestrator/src/main/java/com/yahoo/vespa/orchestrator/model/ApplicationApiImpl.java b/orchestrator/src/main/java/com/yahoo/vespa/orchestrator/model/ApplicationApiImpl.java
index def5edd0a97..cf6946fa7f8 100644
--- a/orchestrator/src/main/java/com/yahoo/vespa/orchestrator/model/ApplicationApiImpl.java
+++ b/orchestrator/src/main/java/com/yahoo/vespa/orchestrator/model/ApplicationApiImpl.java
@@ -20,6 +20,7 @@ import java.util.HashSet;
import java.util.List;
import java.util.Optional;
import java.util.Set;
+import java.util.function.Predicate;
import java.util.stream.Collectors;
import static com.yahoo.vespa.orchestrator.OrchestratorUtil.getHostsUsedByApplicationInstance;
@@ -62,10 +63,9 @@ public class ApplicationApiImpl implements ApplicationApi {
}
@Override
- public List<StorageNode> getStorageNodesAllowedToBeDownInGroupInReverseClusterOrder() {
+ public List<StorageNode> getSuspendedStorageNodesInGroupInReverseClusterOrder() {
return getStorageNodesInGroupInClusterOrder().stream()
- // PERMANENTLY_DOWN nodes are NOT included.
- .filter(storageNode -> getHostStatus(storageNode.hostName()) == HostStatus.ALLOWED_TO_BE_DOWN)
+ .filter(storageNode -> getHostStatus(storageNode.hostName()).isSuspended())
.sorted(Comparator.reverseOrder())
.collect(Collectors.toList());
}
@@ -104,9 +104,9 @@ public class ApplicationApiImpl implements ApplicationApi {
}
@Override
- public List<HostName> getNodesInGroupWithStatus(HostStatus status) {
+ public List<HostName> getNodesInGroupWith(Predicate<HostStatus> statusPredicate) {
return nodeGroup.getHostNames().stream()
- .filter(hostName -> getHostStatus(hostName) == status)
+ .filter(hostName -> statusPredicate.test(getHostStatus(hostName)))
.collect(Collectors.toList());
}
diff --git a/orchestrator/src/main/java/com/yahoo/vespa/orchestrator/policy/HostedVespaPolicy.java b/orchestrator/src/main/java/com/yahoo/vespa/orchestrator/policy/HostedVespaPolicy.java
index a9b9736ebfb..f6a1e4f91f0 100644
--- a/orchestrator/src/main/java/com/yahoo/vespa/orchestrator/policy/HostedVespaPolicy.java
+++ b/orchestrator/src/main/java/com/yahoo/vespa/orchestrator/policy/HostedVespaPolicy.java
@@ -30,7 +30,9 @@ public class HostedVespaPolicy implements Policy {
private final ClusterControllerClientFactory clusterControllerClientFactory;
private final ApplicationApiFactory applicationApiFactory;
- public HostedVespaPolicy(HostedVespaClusterPolicy clusterPolicy, ClusterControllerClientFactory clusterControllerClientFactory, ApplicationApiFactory applicationApiFactory) {
+ public HostedVespaPolicy(HostedVespaClusterPolicy clusterPolicy,
+ ClusterControllerClientFactory clusterControllerClientFactory,
+ ApplicationApiFactory applicationApiFactory) {
this.clusterPolicy = clusterPolicy;
this.clusterControllerClientFactory = clusterControllerClientFactory;
this.applicationApiFactory = applicationApiFactory;
@@ -60,10 +62,11 @@ public class HostedVespaPolicy implements Policy {
public void releaseSuspensionGrant(OrchestratorContext context, ApplicationApi application)
throws HostStateChangeDeniedException {
// Always defer to Cluster Controller whether it's OK to resume storage node
- for (StorageNode storageNode : application.getStorageNodesAllowedToBeDownInGroupInReverseClusterOrder()) {
+ for (StorageNode storageNode : application.getSuspendedStorageNodesInGroupInReverseClusterOrder()) {
storageNode.setNodeState(context, ClusterControllerNodeState.UP);
}
+ // In particular, we're not modifying the state of PERMANENTLY_DOWN nodes.
for (HostName hostName : application.getNodesInGroupWithStatus(HostStatus.ALLOWED_TO_BE_DOWN)) {
application.setHostState(context, hostName, HostStatus.NO_REMARKS);
}
@@ -92,9 +95,15 @@ public class HostedVespaPolicy implements Policy {
storageNode.setNodeState(context, ClusterControllerNodeState.DOWN);
}
- // Ensure all nodes in the group are marked as allowed to be down
- for (HostName hostName : applicationApi.getNodesInGroupWithStatus(HostStatus.NO_REMARKS)) {
- applicationApi.setHostState(context, hostName, HostStatus.ALLOWED_TO_BE_DOWN);
+ if (context.usePermanentlyDownStatus()) {
+ // Ensure all nodes in the group are marked as permanently down
+ for (HostName hostName : applicationApi.getNodesInGroupWith(status -> status != HostStatus.PERMANENTLY_DOWN)) {
+ applicationApi.setHostState(context, hostName, HostStatus.PERMANENTLY_DOWN);
+ }
+ } else {
+ for (HostName hostName : applicationApi.getNodesInGroupWith(status -> status != HostStatus.ALLOWED_TO_BE_DOWN)) {
+ applicationApi.setHostState(context, hostName, HostStatus.ALLOWED_TO_BE_DOWN);
+ }
}
}
diff --git a/orchestrator/src/test/java/com/yahoo/vespa/orchestrator/model/ApplicationApiImplTest.java b/orchestrator/src/test/java/com/yahoo/vespa/orchestrator/model/ApplicationApiImplTest.java
index d5734a73de0..ee33a92367b 100644
--- a/orchestrator/src/test/java/com/yahoo/vespa/orchestrator/model/ApplicationApiImplTest.java
+++ b/orchestrator/src/test/java/com/yahoo/vespa/orchestrator/model/ApplicationApiImplTest.java
@@ -327,7 +327,7 @@ public class ApplicationApiImplTest {
private void verifyStorageNodesAllowedToBeDown(
ApplicationApi applicationApi, HostName... hostNames) {
List<HostName> actualStorageNodes =
- applicationApi.getStorageNodesAllowedToBeDownInGroupInReverseClusterOrder().stream()
+ applicationApi.getSuspendedStorageNodesInGroupInReverseClusterOrder().stream()
.map(storageNode -> storageNode.hostName())
.collect(Collectors.toList());
assertEquals(Arrays.asList(hostNames), actualStorageNodes);
diff --git a/orchestrator/src/test/java/com/yahoo/vespa/orchestrator/policy/HostedVespaPolicyTest.java b/orchestrator/src/test/java/com/yahoo/vespa/orchestrator/policy/HostedVespaPolicyTest.java
index b27e37ac034..ed6917a3a4e 100644
--- a/orchestrator/src/test/java/com/yahoo/vespa/orchestrator/policy/HostedVespaPolicyTest.java
+++ b/orchestrator/src/test/java/com/yahoo/vespa/orchestrator/policy/HostedVespaPolicyTest.java
@@ -120,7 +120,7 @@ public class HostedVespaPolicyTest {
when(applicationApi.getStorageNodesInGroupInClusterOrder()).thenReturn(upStorageNodes);
List<HostName> noRemarksHostNames = Arrays.asList(hostName1, hostName2, hostName3);
- when(applicationApi.getNodesInGroupWithStatus(HostStatus.NO_REMARKS)).thenReturn(noRemarksHostNames);
+ when(applicationApi.getNodesInGroupWith(any())).thenReturn(noRemarksHostNames);
InOrder order = inOrder(applicationApi, clusterPolicy, storageNode1, storageNode3);
@@ -136,7 +136,7 @@ public class HostedVespaPolicyTest {
order.verify(storageNode1).setNodeState(context, ClusterControllerNodeState.DOWN);
order.verify(storageNode3).setNodeState(context, ClusterControllerNodeState.DOWN);
- order.verify(applicationApi).getNodesInGroupWithStatus(HostStatus.NO_REMARKS);
+ order.verify(applicationApi).getNodesInGroupWith(any());
order.verify(applicationApi).setHostState(context, hostName1, HostStatus.ALLOWED_TO_BE_DOWN);
order.verify(applicationApi).setHostState(context, hostName2, HostStatus.ALLOWED_TO_BE_DOWN);
order.verify(applicationApi).setHostState(context, hostName3, HostStatus.ALLOWED_TO_BE_DOWN);
diff --git a/searchlib/src/tests/tensor/hnsw_index/hnsw_index_test.cpp b/searchlib/src/tests/tensor/hnsw_index/hnsw_index_test.cpp
index 76548a025a0..634569cbc8c 100644
--- a/searchlib/src/tests/tensor/hnsw_index/hnsw_index_test.cpp
+++ b/searchlib/src/tests/tensor/hnsw_index/hnsw_index_test.cpp
@@ -67,6 +67,9 @@ public:
level_generator.level = max_level;
index->add_document(docid);
}
+ void remove_document(uint32_t docid) {
+ index->remove_document(docid);
+ }
void expect_entry_point(uint32_t exp_docid, uint32_t exp_level) {
EXPECT_EQ(exp_docid, index->get_entry_docid());
EXPECT_EQ(exp_level, index->get_entry_level());
@@ -131,6 +134,38 @@ TEST_F(HnswIndexTest, 2d_vectors_inserted_in_level_0_graph_with_simple_select_ne
expect_level_0(7, {2, 3});
}
+TEST_F(HnswIndexTest, 2d_vectors_inserted_and_removed)
+{
+ init(false);
+
+ add_document(1);
+ expect_level_0(1, {});
+ expect_entry_point(1, 0);
+
+ add_document(2);
+ expect_level_0(1, {2});
+ expect_level_0(2, {1});
+ expect_entry_point(1, 0);
+
+ add_document(3);
+ expect_level_0(1, {2, 3});
+ expect_level_0(2, {1, 3});
+ expect_level_0(3, {1, 2});
+ expect_entry_point(1, 0);
+
+ remove_document(2);
+ expect_level_0(1, {3});
+ expect_level_0(3, {1});
+ expect_entry_point(1, 0);
+
+ remove_document(1);
+ expect_level_0(3, {});
+ expect_entry_point(3, 0);
+
+ remove_document(3);
+ expect_entry_point(0, -1);
+}
+
TEST_F(HnswIndexTest, 2d_vectors_inserted_in_hierarchic_graph_with_heuristic_select_neighbors)
{
init(true);
diff --git a/searchlib/src/vespa/searchlib/tensor/hnsw_index.cpp b/searchlib/src/vespa/searchlib/tensor/hnsw_index.cpp
index 4992a26d8b4..345f7f551a6 100644
--- a/searchlib/src/vespa/searchlib/tensor/hnsw_index.cpp
+++ b/searchlib/src/vespa/searchlib/tensor/hnsw_index.cpp
@@ -140,8 +140,27 @@ template <typename FloatType>
void
HnswIndex<FloatType>::remove_document(uint32_t docid)
{
- (void) docid;
- // TODO: implement
+ bool need_new_entrypoint = (docid == _entry_docid);
+ LinkArray empty;
+ LevelArrayRef node_levels = get_level_array(docid);
+ for (int level = node_levels.size(); level-- > 0; ) {
+ LinkArrayRef my_links = get_link_array(docid, level);
+ for (uint32_t neighbor_id : my_links) {
+ if (need_new_entrypoint) {
+ _entry_docid = neighbor_id;
+ _entry_level = level;
+ need_new_entrypoint = false;
+ }
+ remove_link_to(neighbor_id, docid, level);
+ }
+ set_link_array(docid, level, empty);
+ }
+ if (need_new_entrypoint) {
+ _entry_docid = 0;
+ _entry_level = -1;
+ }
+ search::datastore::EntryRef invalid;
+ _node_refs[docid].store_release(invalid);
}
}
diff --git a/searchlib/src/vespa/searchlib/tensor/hnsw_index_base.cpp b/searchlib/src/vespa/searchlib/tensor/hnsw_index_base.cpp
index 7a6493b6fcf..a7b9c1dba79 100644
--- a/searchlib/src/vespa/searchlib/tensor/hnsw_index_base.cpp
+++ b/searchlib/src/vespa/searchlib/tensor/hnsw_index_base.cpp
@@ -145,6 +145,17 @@ HnswIndexBase::connect_new_node(uint32_t docid, const LinkArray& neighbors, uint
}
}
+void
+HnswIndexBase::remove_link_to(uint32_t remove_from, uint32_t remove_id, uint32_t level)
+{
+ LinkArray new_links;
+ auto old_links = get_link_array(remove_from, level);
+ for (uint32_t id : old_links) {
+ if (id != remove_id) new_links.push_back(id);
+ }
+ set_link_array(remove_from, level, new_links);
+}
+
HnswIndexBase::HnswIndexBase(const DocVectorAccess& vectors, RandomLevelGenerator& level_generator, const Config& cfg)
: _vectors(vectors),
_level_generator(level_generator),
diff --git a/searchlib/src/vespa/searchlib/tensor/hnsw_index_base.h b/searchlib/src/vespa/searchlib/tensor/hnsw_index_base.h
index e92ca31e789..9987b61c157 100644
--- a/searchlib/src/vespa/searchlib/tensor/hnsw_index_base.h
+++ b/searchlib/src/vespa/searchlib/tensor/hnsw_index_base.h
@@ -109,6 +109,7 @@ protected:
LinkArray select_neighbors_simple(const HnswCandidateVector& neighbors, uint32_t max_links) const;
LinkArray select_neighbors(const HnswCandidateVector& neighbors, uint32_t max_links) const;
void connect_new_node(uint32_t docid, const LinkArray& neighbors, uint32_t level);
+ void remove_link_to(uint32_t remove_from, uint32_t remove_id, uint32_t level);
public:
HnswIndexBase(const DocVectorAccess& vectors, RandomLevelGenerator& level_generator, const Config& cfg);
diff --git a/staging_vespalib/src/vespa/vespalib/util/process_memory_stats.cpp b/staging_vespalib/src/vespa/vespalib/util/process_memory_stats.cpp
index e2e8e49419f..a758ca1fbbe 100644
--- a/staging_vespalib/src/vespa/vespalib/util/process_memory_stats.cpp
+++ b/staging_vespalib/src/vespa/vespalib/util/process_memory_stats.cpp
@@ -196,7 +196,7 @@ ProcessMemoryStats::create(uint64_t sizeEpsilon)
i, (samples.rbegin()+1)->toString().c_str(), samples.back().toString().c_str());
}
std::sort(samples.begin(), samples.end());
- LOG(warning, "We failed to find 2 consecutive samples that where similar with epsilon of %lu.\nSmallest is '%s',\n median is '%s',\n largest is '%s'",
+ LOG(warning, "We failed to find 2 consecutive samples that where similar with epsilon of %" PRIu64 ".\nSmallest is '%s',\n median is '%s',\n largest is '%s'",
sizeEpsilon, samples.front().toString().c_str(), samples[samples.size()/2].toString().c_str(), samples.back().toString().c_str());
return samples[samples.size()/2];
}