diff options
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]; } |