diff options
author | Ola Aunrønning <olaa@verizonmedia.com> | 2021-03-19 11:15:31 +0100 |
---|---|---|
committer | GitHub <noreply@github.com> | 2021-03-19 11:15:31 +0100 |
commit | 8a073477b45ec34c4a614391d345637c502dc526 (patch) | |
tree | f0df9f4eb81155bc1ca544d1595f968635d9a49c | |
parent | 1a128c911792bd0d19f70f86aa42c10c9401dabb (diff) | |
parent | 7df5396bef81b7cda3c1428182a89072cc2ae70d (diff) |
Merge pull request #17042 from vespa-engine/olaa/noderepo-capacity-function
Consider whether all hosts in change request is replaceable
7 files changed, 53 insertions, 8 deletions
diff --git a/controller-api/src/main/java/com/yahoo/vespa/hosted/controller/api/integration/configserver/NodeRepository.java b/controller-api/src/main/java/com/yahoo/vespa/hosted/controller/api/integration/configserver/NodeRepository.java index 8706afd5db5..c3cb904f545 100644 --- a/controller-api/src/main/java/com/yahoo/vespa/hosted/controller/api/integration/configserver/NodeRepository.java +++ b/controller-api/src/main/java/com/yahoo/vespa/hosted/controller/api/integration/configserver/NodeRepository.java @@ -106,6 +106,9 @@ public interface NodeRepository { void reboot(ZoneId zoneId, String hostName); + /** Checks whether the zone has the spare capacity to remove the given hosts */ + boolean isReplaceable(ZoneId zoneId, List<HostName> hostNames); + private static Node toNode(NodeRepositoryNode node) { var application = Optional.ofNullable(node.getOwner()) .map(owner -> ApplicationId.from(owner.getTenant(), owner.getApplication(), diff --git a/controller-api/src/main/java/com/yahoo/vespa/hosted/controller/api/integration/noderepository/Capacity.java b/controller-api/src/main/java/com/yahoo/vespa/hosted/controller/api/integration/noderepository/Capacity.java new file mode 100644 index 00000000000..b8d60fbd523 --- /dev/null +++ b/controller-api/src/main/java/com/yahoo/vespa/hosted/controller/api/integration/noderepository/Capacity.java @@ -0,0 +1,20 @@ +// Copyright Verizon Media. Licensed under the terms of the Apache 2.0 license. See LICENSE in the project root. +package com.yahoo.vespa.hosted.controller.api.integration.noderepository; + +import com.fasterxml.jackson.annotation.JsonIgnoreProperties; +import com.fasterxml.jackson.annotation.JsonProperty; + +/** + * @author olaa + */ +@JsonIgnoreProperties(ignoreUnknown = true) +public class Capacity { + + @JsonProperty("removalPossible") + public boolean removalPossible; + + public boolean isRemovalPossible() { + return removalPossible; + } + +} diff --git a/controller-api/src/main/java/com/yahoo/vespa/hosted/controller/api/integration/noderepository/ProvisionResource.java b/controller-api/src/main/java/com/yahoo/vespa/hosted/controller/api/integration/noderepository/ProvisionResource.java index d88c7146397..2bfcc20dbd1 100644 --- a/controller-api/src/main/java/com/yahoo/vespa/hosted/controller/api/integration/noderepository/ProvisionResource.java +++ b/controller-api/src/main/java/com/yahoo/vespa/hosted/controller/api/integration/noderepository/ProvisionResource.java @@ -121,5 +121,10 @@ public interface ProvisionResource { @DELETE @Path("/archive/{tenant}") String removeArchiveUri(@PathParam("tenant") TenantName tenant); + + @GET + @Path("/capacity") + Capacity capacity(@QueryParam("json") boolean json, + @QueryParam("hosts") String hostList); } diff --git a/controller-server/src/main/java/com/yahoo/vespa/hosted/controller/maintenance/ChangeManagementAssessor.java b/controller-server/src/main/java/com/yahoo/vespa/hosted/controller/maintenance/ChangeManagementAssessor.java index 461845270cf..00e8c508695 100644 --- a/controller-server/src/main/java/com/yahoo/vespa/hosted/controller/maintenance/ChangeManagementAssessor.java +++ b/controller-server/src/main/java/com/yahoo/vespa/hosted/controller/maintenance/ChangeManagementAssessor.java @@ -1,6 +1,7 @@ // Copyright Verizon Media. Licensed under the terms of the Apache 2.0 license. See LICENSE in the project root. package com.yahoo.vespa.hosted.controller.maintenance; +import com.yahoo.config.provision.HostName; import com.yahoo.config.provision.zone.ZoneId; import com.yahoo.vespa.hosted.controller.Controller; import com.yahoo.vespa.hosted.controller.api.integration.configserver.NodeRepository; @@ -29,15 +30,15 @@ public class ChangeManagementAssessor { public String impact; } - public ChangeManagementAssessor(Controller controller) { - this.nodeRepository = controller.serviceRegistry().configServer().nodeRepository(); + public ChangeManagementAssessor(NodeRepository nodeRepository) { + this.nodeRepository = nodeRepository; } public List<Assessment> assessment(List<String> impactedHostnames, ZoneId zone) { return assessmentInner(impactedHostnames, nodeRepository.listNodes(zone).nodes(), zone); } - static List<Assessment> assessmentInner(List<String> impactedHostnames, List<NodeRepositoryNode> allNodes, ZoneId zone) { + List<Assessment> assessmentInner(List<String> impactedHostnames, List<NodeRepositoryNode> allNodes, ZoneId zone) { // Get all active nodes running on the impacted hosts List<NodeRepositoryNode> containerNodes = allNodes.stream() .filter(nodeRepositoryNode -> nodeRepositoryNode.getState() == NodeState.active) //TODO look at more states? @@ -46,6 +47,13 @@ public class ChangeManagementAssessor { // Group nodes pr cluster Map<String, List<NodeRepositoryNode>> prCluster = containerNodes.stream().collect(Collectors.groupingBy(ChangeManagementAssessor::clusterKey)); + boolean allHostsReplacable = nodeRepository.isReplaceable( + zone, + impactedHostnames.stream() + .map(HostName::from) + .collect(Collectors.toList()) + ); + // Report assessment pr cluster return prCluster.entrySet().stream().map((entry) -> { String key = entry.getKey(); @@ -65,10 +73,11 @@ public class ChangeManagementAssessor { assessment.groupsTotal = totalStats[1]; assessment.groupsImpact = impactedStats[1]; + // TODO check upgrade policy assessment.upgradePolicy = "na"; // TODO do some heuristic on suggestion action - assessment.suggestedAction = "nothing"; + assessment.suggestedAction = allHostsReplacable ? "Retire all hosts" : "nothing"; // TODO do some heuristic on impact assessment.impact = "na"; diff --git a/controller-server/src/main/java/com/yahoo/vespa/hosted/controller/restapi/changemanagement/ChangeManagementApiHandler.java b/controller-server/src/main/java/com/yahoo/vespa/hosted/controller/restapi/changemanagement/ChangeManagementApiHandler.java index 7652ef167ed..b522469f179 100644 --- a/controller-server/src/main/java/com/yahoo/vespa/hosted/controller/restapi/changemanagement/ChangeManagementApiHandler.java +++ b/controller-server/src/main/java/com/yahoo/vespa/hosted/controller/restapi/changemanagement/ChangeManagementApiHandler.java @@ -37,7 +37,7 @@ public class ChangeManagementApiHandler extends AuditLoggingRequestHandler { public ChangeManagementApiHandler(LoggingRequestHandler.Context ctx, Controller controller) { super(ctx, controller.auditLogger()); - this.assessor = new ChangeManagementAssessor(controller); + this.assessor = new ChangeManagementAssessor(controller.serviceRegistry().configServer().nodeRepository()); this.controller = controller; } diff --git a/controller-server/src/test/java/com/yahoo/vespa/hosted/controller/integration/NodeRepositoryMock.java b/controller-server/src/test/java/com/yahoo/vespa/hosted/controller/integration/NodeRepositoryMock.java index a84e7242495..85e82bb3fcd 100644 --- a/controller-server/src/test/java/com/yahoo/vespa/hosted/controller/integration/NodeRepositoryMock.java +++ b/controller-server/src/test/java/com/yahoo/vespa/hosted/controller/integration/NodeRepositoryMock.java @@ -284,6 +284,11 @@ public class NodeRepositoryMock implements NodeRepository { throw new UnsupportedOperationException(); } + @Override + public boolean isReplaceable(ZoneId zoneId, List<HostName> hostNames) { + return false; + } + public Optional<Duration> osUpgradeBudget(ZoneId zone, NodeType type, Version version) { return Optional.ofNullable(osUpgradeBudgets.get(Objects.hash(zone, type, version))); } diff --git a/controller-server/src/test/java/com/yahoo/vespa/hosted/controller/maintenance/ChangeManagementAssessorTest.java b/controller-server/src/test/java/com/yahoo/vespa/hosted/controller/maintenance/ChangeManagementAssessorTest.java index 6761c79bff5..a4fb4669237 100644 --- a/controller-server/src/test/java/com/yahoo/vespa/hosted/controller/maintenance/ChangeManagementAssessorTest.java +++ b/controller-server/src/test/java/com/yahoo/vespa/hosted/controller/maintenance/ChangeManagementAssessorTest.java @@ -7,6 +7,7 @@ import com.yahoo.vespa.hosted.controller.api.integration.noderepository.NodeMemb import com.yahoo.vespa.hosted.controller.api.integration.noderepository.NodeOwner; import com.yahoo.vespa.hosted.controller.api.integration.noderepository.NodeRepositoryNode; import com.yahoo.vespa.hosted.controller.api.integration.noderepository.NodeState; +import com.yahoo.vespa.hosted.controller.integration.NodeRepositoryMock; import org.junit.Assert; import org.junit.Test; @@ -17,6 +18,8 @@ import java.util.List; public class ChangeManagementAssessorTest { + private ChangeManagementAssessor changeManagementAssessor = new ChangeManagementAssessor(new NodeRepositoryMock()); + @Test public void empty_input_variations() { ZoneId zone = ZoneId.from("prod", "eu-trd"); @@ -25,7 +28,7 @@ public class ChangeManagementAssessorTest { // Both zone and hostnames are empty List<ChangeManagementAssessor.Assessment> assessments - = ChangeManagementAssessor.assessmentInner(hostNames, allNodesInZone, zone); + = changeManagementAssessor.assessmentInner(hostNames, allNodesInZone, zone); Assert.assertEquals(0, assessments.size()); } @@ -43,7 +46,7 @@ public class ChangeManagementAssessorTest { // Make Assessment List<ChangeManagementAssessor.Assessment> assessments - = ChangeManagementAssessor.assessmentInner(hostNames, allNodesInZone, zone); + = changeManagementAssessor.assessmentInner(hostNames, allNodesInZone, zone); // Assess the assessment :-o Assert.assertEquals(1, assessments.size()); @@ -81,7 +84,7 @@ public class ChangeManagementAssessorTest { // Make Assessment List<ChangeManagementAssessor.Assessment> assessments - = ChangeManagementAssessor.assessmentInner(hostNames, allNodesInZone, zone); + = changeManagementAssessor.assessmentInner(hostNames, allNodesInZone, zone); // Assess the assessment :-o Assert.assertEquals(1, assessments.size()); //One cluster is impacted |