summaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authorsmorgrav <smorgrav@verizonmedia.com>2021-03-16 15:11:44 +0100
committersmorgrav <smorgrav@verizonmedia.com>2021-03-16 15:11:44 +0100
commit582cd6a23a51aa08ddfa44523f93b6353d37dc7e (patch)
treebda4c63a4d8174ed8ed7e63109ba199761fd75d7
parent8ca647a2521bc3c11cf81b9a5d7e56e94b03e6f9 (diff)
Implement first assessor functionality
-rw-r--r--controller-server/src/main/java/com/yahoo/vespa/hosted/controller/maintenance/ChangeManagementAssessor.java (renamed from controller-server/src/main/java/com/yahoo/vespa/hosted/controller/maintenance/ChangeManagementAssessment.java)42
-rw-r--r--controller-server/src/main/java/com/yahoo/vespa/hosted/controller/restapi/changemanagement/ChangeManagementApiHandler.java107
-rw-r--r--controller-server/src/test/java/com/yahoo/vespa/hosted/controller/integration/NodeRepositoryMock.java16
-rw-r--r--controller-server/src/test/java/com/yahoo/vespa/hosted/controller/maintenance/ChangeManagementAssessmentTest.java26
-rw-r--r--controller-server/src/test/java/com/yahoo/vespa/hosted/controller/maintenance/ChangeManagementAssessorTest.java124
-rw-r--r--controller-server/src/test/java/com/yahoo/vespa/hosted/controller/restapi/changemanagement/ChangeManagementApiHandlerTest.java48
-rw-r--r--controller-server/src/test/java/com/yahoo/vespa/hosted/controller/restapi/changemanagement/responses/initial.json33
7 files changed, 289 insertions, 107 deletions
diff --git a/controller-server/src/main/java/com/yahoo/vespa/hosted/controller/maintenance/ChangeManagementAssessment.java b/controller-server/src/main/java/com/yahoo/vespa/hosted/controller/maintenance/ChangeManagementAssessor.java
index e44dc58c028..61d003c4aa0 100644
--- a/controller-server/src/main/java/com/yahoo/vespa/hosted/controller/maintenance/ChangeManagementAssessment.java
+++ b/controller-server/src/main/java/com/yahoo/vespa/hosted/controller/maintenance/ChangeManagementAssessor.java
@@ -1,36 +1,34 @@
package com.yahoo.vespa.hosted.controller.maintenance;
-
import com.yahoo.config.provision.zone.ZoneId;
import com.yahoo.vespa.hosted.controller.Controller;
import com.yahoo.vespa.hosted.controller.api.integration.configserver.NodeRepository;
import com.yahoo.vespa.hosted.controller.api.integration.noderepository.NodeRepositoryNode;
import com.yahoo.vespa.hosted.controller.api.integration.noderepository.NodeState;
-import org.jetbrains.annotations.NotNull;
import java.util.Arrays;
import java.util.List;
import java.util.Map;
import java.util.stream.Collectors;
-public class ChangeManagementAssessment {
+public class ChangeManagementAssessor {
private final NodeRepository nodeRepository;
public static class Assessment {
- String app;
- String zone;
- String cluster;
- long clusterImpact;
- long clusterTotal;
- long groupsImpact;
- long groupsTotal;
- String upgradePolicy;
- String suggestedAction;
- String impact;
+ public String app;
+ public String zone;
+ public String cluster;
+ public long clusterImpact;
+ public long clusterSize;
+ public long groupsImpact;
+ public long groupsTotal;
+ public String upgradePolicy;
+ public String suggestedAction;
+ public String impact;
}
- public ChangeManagementAssessment(Controller controller) {
+ public ChangeManagementAssessor(Controller controller) {
this.nodeRepository = controller.serviceRegistry().configServer().nodeRepository();
}
@@ -44,7 +42,7 @@ public class ChangeManagementAssessment {
.filter(node -> impactedHostnames.contains(node.getParentHostname() == null ? "" : node.getParentHostname())).collect(Collectors.toList());
// Group nodes pr cluster
- Map<String, List<NodeRepositoryNode>> prCluster = containerNodes.stream().collect(Collectors.groupingBy(ChangeManagementAssessment::clusterKey));
+ Map<String, List<NodeRepositoryNode>> prCluster = containerNodes.stream().collect(Collectors.groupingBy(ChangeManagementAssessor::clusterKey));
// Report assessment pr cluster
return prCluster.entrySet().stream().map((entry) -> {
@@ -53,20 +51,24 @@ public class ChangeManagementAssessment {
String app = Arrays.stream(key.split(":")).limit(3).collect(Collectors.joining(":"));
String cluster = Arrays.stream(key.split(":")).skip(3).collect(Collectors.joining(":"));
- long[] totalStats = clusterStats(key, containerNodes);
+ long[] totalStats = clusterStats(key, allNodes);
long[] impactedStats = clusterStats(key, nodes);
Assessment assessment = new Assessment();
assessment.app = app;
assessment.zone = zone.value();
assessment.cluster = cluster;
- assessment.clusterTotal = totalStats[0];
+ assessment.clusterSize = totalStats[0];
assessment.clusterImpact = impactedStats[0];
assessment.groupsTotal = totalStats[1];
assessment.groupsImpact = impactedStats[1];
- assessment.upgradePolicy = "na"; //TODO
- assessment.suggestedAction = "nothing"; //TODO
- assessment.impact = "high"; //TODO
+
+ // TODO check upgrade policy
+ assessment.upgradePolicy = "na";
+ // TODO do some heuristic on suggestion action
+ assessment.suggestedAction = "nothing";
+ // TODO do some heuristic on impact
+ assessment.impact = "na";
return assessment;
}).collect(Collectors.toList());
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 1dbeaf7c235..ff45955ee76 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
@@ -1,26 +1,35 @@
package com.yahoo.vespa.hosted.controller.restapi.changemanagement;
+import com.yahoo.config.provision.zone.ZoneId;
import com.yahoo.container.jdisc.HttpRequest;
import com.yahoo.container.jdisc.HttpResponse;
import com.yahoo.container.jdisc.LoggingRequestHandler;
import com.yahoo.restapi.ErrorResponse;
import com.yahoo.restapi.Path;
import com.yahoo.restapi.SlimeJsonResponse;
+import com.yahoo.slime.ArrayTraverser;
import com.yahoo.slime.Cursor;
+import com.yahoo.slime.Inspector;
import com.yahoo.slime.Slime;
+import com.yahoo.slime.SlimeUtils;
import com.yahoo.vespa.hosted.controller.Controller;
import com.yahoo.vespa.hosted.controller.auditlog.AuditLoggingRequestHandler;
+import com.yahoo.vespa.hosted.controller.maintenance.ChangeManagementAssessor;
import com.yahoo.yolean.Exceptions;
+import javax.ws.rs.BadRequestException;
+import java.io.IOException;
+import java.util.ArrayList;
+import java.util.List;
import java.util.logging.Level;
public class ChangeManagementApiHandler extends AuditLoggingRequestHandler {
- private final Controller controller;
+ private final ChangeManagementAssessor assessor;
public ChangeManagementApiHandler(LoggingRequestHandler.Context ctx, Controller controller) {
super(ctx, controller.auditLogger());
- this.controller = controller;
+ assessor = new ChangeManagementAssessor(controller);
}
@Override
@@ -42,48 +51,78 @@ public class ChangeManagementApiHandler extends AuditLoggingRequestHandler {
private HttpResponse post(HttpRequest request) {
Path path = new Path(request.getUri());
- if (path.matches("/changemanagement/v1/assessment")) return new SlimeJsonResponse(assessment());
+ if (path.matches("/changemanagement/v1/assessment")) return new SlimeJsonResponse(doAssessment(request));
return ErrorResponse.notFoundError("Nothing at " + path);
}
- private Slime assessment() {
+ private Inspector inspectorOrThrow(HttpRequest request) {
+ try {
+ return SlimeUtils.jsonToSlime(request.getData().readAllBytes()).get();
+ } catch (IOException e) {
+ throw new BadRequestException("Failed to parse request body");
+ }
+ }
+
+ private static Inspector getInspectorFieldOrThrow(Inspector inspector, String field) {
+ if (!inspector.field(field).valid())
+ throw new BadRequestException("Field " + field + " cannot be null");
+ return inspector.field(field);
+ }
+
+ // The structure here should be
+ //
+ // {
+ // zone: string
+ // hosts: string[]
+ // switches: string[]
+ // switchInSequence: boolean
+ // }
+ //
+ // Only zone and host are supported right now
+ private Slime doAssessment(HttpRequest request) {
+
+ Inspector inspector = inspectorOrThrow(request);
+
+ // For now; mandatory fields
+ String zoneStr = getInspectorFieldOrThrow(inspector, "zone").asString();
+ Inspector hostArray = getInspectorFieldOrThrow(inspector, "hosts");
+
+ // The impacted hostnames
+ List<String> hostNames = new ArrayList<>();
+ if (hostArray.valid()) {
+ hostArray.traverse((ArrayTraverser) (i, host) -> hostNames.add(host.asString()));
+ }
+
+ List<ChangeManagementAssessor.Assessment> assessments = assessor.assessment(hostNames, ZoneId.from(zoneStr));
+
Slime slime = new Slime();
Cursor root = slime.setObject();
// This is the main structure that might be part of something bigger later
- Cursor assessment = root.setObject("assessment");
+ Cursor assessmentCursor = root.setObject("assessment");
- // Updated gives clue to if the assessement is old
- assessment.setString("updated", "2021-03-12:12:12:12Z");
+ // Updated gives clue to if the assessment is old
+ assessmentCursor.setString("updated", "2021-03-12:12:12:12Z");
// Assessment on the cluster level
- Cursor apps = assessment.setArray("clusters");
- Cursor oneCluster = apps.addObject();
- oneCluster.setString("app", "mytenant:myapp:myinstance");
- oneCluster.setString("zone", "prod.us-east-3");
- oneCluster.setString("cluster", "mycontent");
- oneCluster.setLong("clusterSize", 19);
- oneCluster.setLong("clusterImpact", 3);
- oneCluster.setString("upgradePolicy","10%");
- oneCluster.setDouble("utilizationInWindow", 0.5);
- oneCluster.setString("suggestedAction", "nothing|bcp");
- oneCluster.setString("impact", "low|degraded|outage");
-
- Cursor groups = oneCluster.setArray("groups");
- Cursor oneGroup = groups.addObject();
- oneGroup.setString("groupId", "23");
- oneGroup.setLong("groupSize", 4);
- oneGroup.setLong("groupImpact", 2);
-
- // Assessment on the host level
- Cursor hosts = assessment.setArray("hosts");
- Cursor oneHost = hosts.addObject();
- oneHost.setString("hostname", "myhostname");
- oneHost.setString("resources", "vcpu:memory:disk");
- oneHost.setString("state", "active");
- oneHost.setLong("containers", 10);
- oneHost.setString("suggestedAction", "nothing|retire");
- oneHost.setString("impact", "low|degraded|outage"); //For hosts this is mostly decided by request
+ Cursor clustersCursor = assessmentCursor.setArray("clusters");
+
+ assessments.forEach(assessment -> {
+ Cursor oneCluster = clustersCursor.addObject();
+ oneCluster.setString("app", assessment.app);
+ oneCluster.setString("zone", assessment.zone);
+ oneCluster.setString("cluster", assessment.cluster);
+ oneCluster.setLong("clusterSize", assessment.clusterSize);
+ oneCluster.setLong("clusterImpact", assessment.clusterImpact);
+ oneCluster.setLong("groupsTotal", assessment.groupsTotal);
+ oneCluster.setLong("groupsImpact", assessment.groupsImpact);
+ oneCluster.setString("upgradePolicy", assessment.upgradePolicy);
+ oneCluster.setString("suggestedAction", assessment.suggestedAction);
+ oneCluster.setString("impact", assessment.impact);
+ });
+
+ // Assessment on the host level - TODO
+ assessmentCursor.setArray("hosts");
return slime;
}
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 0c558ef3ea8..e2b1e90555d 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
@@ -1,6 +1,7 @@
// Copyright 2018 Yahoo Holdings. Licensed under the terms of the Apache 2.0 license. See LICENSE in the project root.
package com.yahoo.vespa.hosted.controller.integration;
+import com.fasterxml.jackson.annotation.JsonProperty;
import com.fasterxml.jackson.databind.JsonNode;
import com.yahoo.collections.Pair;
import com.yahoo.component.Version;
@@ -15,12 +16,17 @@ import com.yahoo.vespa.hosted.controller.api.integration.configserver.Applicatio
import com.yahoo.vespa.hosted.controller.api.integration.configserver.Node;
import com.yahoo.vespa.hosted.controller.api.integration.configserver.NodeRepository;
import com.yahoo.vespa.hosted.controller.api.integration.configserver.TargetVersions;
+import com.yahoo.vespa.hosted.controller.api.integration.noderepository.NodeEnvironment;
+import com.yahoo.vespa.hosted.controller.api.integration.noderepository.NodeHistory;
import com.yahoo.vespa.hosted.controller.api.integration.noderepository.NodeList;
+import com.yahoo.vespa.hosted.controller.api.integration.noderepository.NodeMembership;
+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 java.net.URI;
import java.time.Duration;
+import java.util.ArrayList;
import java.util.Collection;
import java.util.Collections;
import java.util.HashMap;
@@ -29,6 +35,7 @@ import java.util.Map;
import java.util.NoSuchElementException;
import java.util.Objects;
import java.util.Optional;
+import java.util.Set;
import java.util.function.Function;
import java.util.function.UnaryOperator;
import java.util.stream.Collectors;
@@ -46,6 +53,10 @@ public class NodeRepositoryMock implements NodeRepository {
private final Map<DeploymentId, Pair<Double, Double>> trafficFractions = new HashMap<>();
private final Map<ZoneId, Map<TenantName, URI>> archiveUris = new HashMap<>();
+ // A separate/alternative list of NodeRepositoryNode nodes.
+ // Methods operating with Node and NodeRepositoryNode lives separate lives.
+ private final Map<ZoneId, List<NodeRepositoryNode>> nodeRepoNodes = new HashMap<>();
+
private boolean allowPatching = false;
/** Add or update given nodes in zone */
@@ -77,6 +88,7 @@ public class NodeRepositoryMock implements NodeRepository {
/** Remove all nodes in all zones */
public void clear() {
nodeRepository.clear();
+ nodeRepoNodes.clear();
}
/** Replace nodes in zone with given nodes */
@@ -131,7 +143,7 @@ public class NodeRepositoryMock implements NodeRepository {
@Override
public void addNodes(ZoneId zone, Collection<NodeRepositoryNode> nodes) {
- throw new UnsupportedOperationException();
+ nodeRepoNodes.put(zone, new ArrayList<>(nodes));
}
@Override
@@ -151,7 +163,7 @@ public class NodeRepositoryMock implements NodeRepository {
@Override
public NodeList listNodes(ZoneId zone) {
- throw new UnsupportedOperationException();
+ return new NodeList(nodeRepoNodes.get(zone));
}
@Override
diff --git a/controller-server/src/test/java/com/yahoo/vespa/hosted/controller/maintenance/ChangeManagementAssessmentTest.java b/controller-server/src/test/java/com/yahoo/vespa/hosted/controller/maintenance/ChangeManagementAssessmentTest.java
deleted file mode 100644
index 966ba956991..00000000000
--- a/controller-server/src/test/java/com/yahoo/vespa/hosted/controller/maintenance/ChangeManagementAssessmentTest.java
+++ /dev/null
@@ -1,26 +0,0 @@
-package com.yahoo.vespa.hosted.controller.maintenance;
-
-
-import com.yahoo.config.provision.zone.ZoneId;
-import com.yahoo.vespa.hosted.controller.api.integration.noderepository.NodeRepositoryNode;
-import org.junit.Assert;
-import org.junit.Test;
-
-import java.util.ArrayList;
-import java.util.Arrays;
-import java.util.List;
-
-public class ChangeManagementAssessmentTest{
-
- @Test
- public void empty_input_variations() {
- ZoneId zone = ZoneId.from("prod", "eu-trd");
- List<String> hostNames = new ArrayList<>();
- List<NodeRepositoryNode> allNodesInZone = new ArrayList<>();
-
- // Both zone and hostnames are empty
- List<ChangeManagementAssessment.Assessment> assessments
- = ChangeManagementAssessment.assessmentInner(hostNames, allNodesInZone, zone);
- Assert.assertEquals(0, assessments.size());
- }
-} \ No newline at end of file
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
new file mode 100644
index 00000000000..f3cb996c048
--- /dev/null
+++ b/controller-server/src/test/java/com/yahoo/vespa/hosted/controller/maintenance/ChangeManagementAssessorTest.java
@@ -0,0 +1,124 @@
+package com.yahoo.vespa.hosted.controller.maintenance;
+
+
+import com.yahoo.config.provision.zone.ZoneId;
+import com.yahoo.vespa.hosted.controller.api.integration.noderepository.NodeMembership;
+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 org.junit.Assert;
+import org.junit.Test;
+
+import java.util.ArrayList;
+import java.util.Arrays;
+import java.util.Collections;
+import java.util.List;
+
+public class ChangeManagementAssessorTest {
+
+ @Test
+ public void empty_input_variations() {
+ ZoneId zone = ZoneId.from("prod", "eu-trd");
+ List<String> hostNames = new ArrayList<>();
+ List<NodeRepositoryNode> allNodesInZone = new ArrayList<>();
+
+ // Both zone and hostnames are empty
+ List<ChangeManagementAssessor.Assessment> assessments
+ = ChangeManagementAssessor.assessmentInner(hostNames, allNodesInZone, zone);
+ Assert.assertEquals(0, assessments.size());
+ }
+
+ @Test
+ public void one_host_one_cluster_no_groups() {
+ ZoneId zone = ZoneId.from("prod", "eu-trd");
+ List<String> hostNames = Collections.singletonList("host1");
+ List<NodeRepositoryNode> allNodesInZone = new ArrayList<>();
+ allNodesInZone.add(createNode("node1", "host1", "myapp", "default", 0 ));
+ allNodesInZone.add(createNode("node2", "host1", "myapp", "default", 0 ));
+ allNodesInZone.add(createNode("node3", "host1", "myapp", "default", 0 ));
+
+ // Add an not impacted hosts
+ allNodesInZone.add(createNode("node4", "host2", "myapp", "default", 0 ));
+
+ // Make Assessment
+ List<ChangeManagementAssessor.Assessment> assessments
+ = ChangeManagementAssessor.assessmentInner(hostNames, allNodesInZone, zone);
+
+ // Assess the assessment :-o
+ Assert.assertEquals(1, assessments.size());
+ Assert.assertEquals(3, assessments.get(0).clusterImpact);
+ Assert.assertEquals(4, assessments.get(0).clusterSize);
+ Assert.assertEquals(1, assessments.get(0).groupsImpact);
+ Assert.assertEquals(1, assessments.get(0).groupsTotal);
+ Assert.assertEquals("content:default", assessments.get(0).cluster);
+ Assert.assertEquals("mytenant:myapp:default", assessments.get(0).app);
+ Assert.assertEquals("prod.eu-trd", assessments.get(0).zone);
+ }
+
+ @Test
+ public void one_of_two_groups_in_one_of_two_clusters() {
+ ZoneId zone = ZoneId.from("prod", "eu-trd");
+ List<String> hostNames = Arrays.asList("host1", "host2");
+ List<NodeRepositoryNode> allNodesInZone = new ArrayList<>();
+
+ // Two impacted nodes on host1
+ allNodesInZone.add(createNode("node1", "host1", "myapp", "default", 0 ));
+ allNodesInZone.add(createNode("node2", "host1", "myapp", "default", 0 ));
+
+ // One impacted nodes on host2
+ allNodesInZone.add(createNode("node3", "host2", "myapp", "default", 0 ));
+
+ // Another group on hosts not impacted
+ allNodesInZone.add(createNode("node4", "host3", "myapp", "default", 1 ));
+ allNodesInZone.add(createNode("node5", "host3", "myapp", "default", 1 ));
+ allNodesInZone.add(createNode("node6", "host3", "myapp", "default", 1 ));
+
+ // Another cluster on hosts not impacted - this one also with three different groups (should all be ignored here)
+ allNodesInZone.add(createNode("node4", "host4", "myapp", "myman", 4 ));
+ allNodesInZone.add(createNode("node5", "host4", "myapp", "myman", 5 ));
+ allNodesInZone.add(createNode("node6", "host4", "myapp", "myman", 6 ));
+
+ // Make Assessment
+ List<ChangeManagementAssessor.Assessment> assessments
+ = ChangeManagementAssessor.assessmentInner(hostNames, allNodesInZone, zone);
+
+ // Assess the assessment :-o
+ Assert.assertEquals(1, assessments.size()); //One cluster is impacted
+ Assert.assertEquals(3, assessments.get(0).clusterImpact);
+ Assert.assertEquals(6, assessments.get(0).clusterSize);
+ Assert.assertEquals(1, assessments.get(0).groupsImpact);
+ Assert.assertEquals(2, assessments.get(0).groupsTotal);
+ Assert.assertEquals("content:default", assessments.get(0).cluster);
+ Assert.assertEquals("mytenant:myapp:default", assessments.get(0).app);
+ Assert.assertEquals("prod.eu-trd", assessments.get(0).zone);
+ }
+
+ private NodeOwner createOwner(String tenant, String application, String instance) {
+ NodeOwner owner = new NodeOwner();
+ owner.tenant = tenant;
+ owner.application = application;
+ owner.instance = instance;
+ return owner;
+ }
+
+ private NodeMembership createMembership(String clusterId, int group) {
+ NodeMembership membership = new NodeMembership();
+ membership.group = "" + group;
+ membership.clusterid = clusterId;
+ membership.clustertype = "content";
+ membership.index = 2;
+ membership.retired = false;
+ return membership;
+ }
+
+ private NodeRepositoryNode createNode(String nodename, String hostname, String appName, String clusterId, int group) {
+ NodeRepositoryNode node = new NodeRepositoryNode();
+ node.setHostname(nodename);
+ node.setParentHostname(hostname);
+ node.setState(NodeState.active);
+ node.setOwner(createOwner("mytenant", appName, "default"));
+ node.setMembership(createMembership(clusterId, group));
+
+ return node;
+ }
+} \ No newline at end of file
diff --git a/controller-server/src/test/java/com/yahoo/vespa/hosted/controller/restapi/changemanagement/ChangeManagementApiHandlerTest.java b/controller-server/src/test/java/com/yahoo/vespa/hosted/controller/restapi/changemanagement/ChangeManagementApiHandlerTest.java
index ff0b3b83383..28f2b836365 100644
--- a/controller-server/src/test/java/com/yahoo/vespa/hosted/controller/restapi/changemanagement/ChangeManagementApiHandlerTest.java
+++ b/controller-server/src/test/java/com/yahoo/vespa/hosted/controller/restapi/changemanagement/ChangeManagementApiHandlerTest.java
@@ -2,8 +2,13 @@
package com.yahoo.vespa.hosted.controller.restapi.changemanagement;
import com.yahoo.application.container.handler.Request;
+import com.yahoo.config.provision.zone.ZoneId;
import com.yahoo.vespa.athenz.api.AthenzIdentity;
import com.yahoo.vespa.athenz.api.AthenzUser;
+import com.yahoo.vespa.hosted.controller.api.integration.noderepository.NodeMembership;
+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.restapi.ContainerTester;
import com.yahoo.vespa.hosted.controller.restapi.ControllerContainerTest;
import org.intellij.lang.annotations.Language;
@@ -11,6 +16,8 @@ import org.junit.Before;
import org.junit.Test;
import java.io.File;
+import java.util.ArrayList;
+import java.util.List;
public class ChangeManagementApiHandlerTest extends ControllerContainerTest {
@@ -23,11 +30,12 @@ public class ChangeManagementApiHandlerTest extends ControllerContainerTest {
public void before() {
tester = new ContainerTester(container, responses);
addUserToHostedOperatorRole(operator);
+ tester.serviceRegistry().configServer().nodeRepository().addNodes(ZoneId.from("prod.us-east-3"), createNodes());
}
@Test
public void test_api() {
- assertFile(new Request("http://localhost:8080/changemanagement/v1/assessment", "{}", Request.Method.POST), "initial.json");
+ assertFile(new Request("http://localhost:8080/changemanagement/v1/assessment", "{\"zone\":\"prod.us-east-3\", \"hosts\": [\"host1\"]}", Request.Method.POST), "initial.json");
}
private void assertResponse(Request request, @Language("JSON") String body, int statusCode) {
@@ -39,4 +47,42 @@ public class ChangeManagementApiHandlerTest extends ControllerContainerTest {
addIdentityToRequest(request, operator);
tester.assertResponse(request, new File(filename));
}
+
+ private List<NodeRepositoryNode> createNodes() {
+ List<NodeRepositoryNode> nodes = new ArrayList<>();
+ nodes.add(createNode("node1", "host1", "myapp", "default", 0 ));
+ nodes.add(createNode("node2", "host1", "myapp", "default", 0 ));
+ nodes.add(createNode("node3", "host1", "myapp", "default", 0 ));
+ nodes.add(createNode("node4", "host2", "myapp", "default", 0 ));
+ return nodes;
+ }
+
+ private NodeOwner createOwner(String tenant, String application, String instance) {
+ NodeOwner owner = new NodeOwner();
+ owner.tenant = tenant;
+ owner.application = application;
+ owner.instance = instance;
+ return owner;
+ }
+
+ private NodeMembership createMembership(String clusterId, int group) {
+ NodeMembership membership = new NodeMembership();
+ membership.group = "" + group;
+ membership.clusterid = clusterId;
+ membership.clustertype = "content";
+ membership.index = 2;
+ membership.retired = false;
+ return membership;
+ }
+
+ private NodeRepositoryNode createNode(String nodename, String hostname, String appName, String clusterId, int group) {
+ NodeRepositoryNode node = new NodeRepositoryNode();
+ node.setHostname(nodename);
+ node.setParentHostname(hostname);
+ node.setState(NodeState.active);
+ node.setOwner(createOwner("mytenant", appName, "default"));
+ node.setMembership(createMembership(clusterId, group));
+
+ return node;
+ }
}
diff --git a/controller-server/src/test/java/com/yahoo/vespa/hosted/controller/restapi/changemanagement/responses/initial.json b/controller-server/src/test/java/com/yahoo/vespa/hosted/controller/restapi/changemanagement/responses/initial.json
index b402ff313dc..a9b0dacb968 100644
--- a/controller-server/src/test/java/com/yahoo/vespa/hosted/controller/restapi/changemanagement/responses/initial.json
+++ b/controller-server/src/test/java/com/yahoo/vespa/hosted/controller/restapi/changemanagement/responses/initial.json
@@ -3,33 +3,18 @@
"updated": "2021-03-12:12:12:12Z",
"clusters": [
{
- "app": "mytenant:myapp:myinstance",
+ "app": "mytenant:myapp:default",
"zone": "prod.us-east-3",
- "cluster": "mycontent",
- "clusterSize": 19,
+ "cluster": "content:default",
+ "clusterSize": 4,
"clusterImpact": 3,
- "upgradePolicy": "10%",
- "utilizationInWindow": 0.5,
- "suggestedAction": "nothing|bcp",
- "impact": "low|degraded|outage",
- "groups": [
- {
- "groupId": "23",
- "groupSize": 4,
- "groupImpact": 2
- }
- ]
+ "groupsTotal": 1,
+ "groupsImpact": 1,
+ "upgradePolicy": "na",
+ "suggestedAction": "nothing",
+ "impact": "na"
}
],
- "hosts": [
- {
- "hostname": "myhostname",
- "resources": "vcpu:memory:disk",
- "state": "active",
- "containers": 10,
- "suggestedAction": "nothing|retire",
- "impact": "low|degraded|outage"
- }
- ]
+ "hosts": []
}
} \ No newline at end of file