summaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authorOla Aunrønning <olaa@verizonmedia.com>2021-03-12 10:39:40 +0100
committerGitHub <noreply@github.com>2021-03-12 10:39:40 +0100
commit6cd2a39ccb1a62c10dfae5adf9eba40eddf2c2c6 (patch)
tree5dbddf60ad96bc0cb25eed1f533b71645aa7d4d4
parent99253f5769759e7fc379bdd9e135addda01509f0 (diff)
parent1e2ea75d1dc83fab3d70fdc120ebed360833c991 (diff)
Merge pull request #16902 from vespa-engine/smorgrav/assessment_api_handler
Smorgrav/assessment api handler
-rw-r--r--controller-api/src/main/java/com/yahoo/vespa/hosted/controller/api/role/PathGroup.java3
-rw-r--r--controller-server/src/main/java/com/yahoo/vespa/hosted/controller/restapi/changemanagement/ChangeManagementApiHandler.java90
-rw-r--r--controller-server/src/test/java/com/yahoo/vespa/hosted/controller/restapi/ControllerContainerTest.java3
-rw-r--r--controller-server/src/test/java/com/yahoo/vespa/hosted/controller/restapi/changemanagement/ChangeManagementApiHandlerTest.java42
-rw-r--r--controller-server/src/test/java/com/yahoo/vespa/hosted/controller/restapi/changemanagement/responses/initial.json35
5 files changed, 172 insertions, 1 deletions
diff --git a/controller-api/src/main/java/com/yahoo/vespa/hosted/controller/api/role/PathGroup.java b/controller-api/src/main/java/com/yahoo/vespa/hosted/controller/api/role/PathGroup.java
index 391dd59fd0b..72210ec26ed 100644
--- a/controller-api/src/main/java/com/yahoo/vespa/hosted/controller/api/role/PathGroup.java
+++ b/controller-api/src/main/java/com/yahoo/vespa/hosted/controller/api/role/PathGroup.java
@@ -38,7 +38,8 @@ enum PathGroup {
"/routing/v1/",
"/routing/v1/status/environment/{*}",
"/routing/v1/inactive/environment/{*}",
- "/state/v1/{*}"),
+ "/state/v1/{*}",
+ "/changemanagement/v1/{*}"),
/** Paths used for creating and reading user resources. */
user(PathPrefix.api,
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
new file mode 100644
index 00000000000..1dbeaf7c235
--- /dev/null
+++ b/controller-server/src/main/java/com/yahoo/vespa/hosted/controller/restapi/changemanagement/ChangeManagementApiHandler.java
@@ -0,0 +1,90 @@
+package com.yahoo.vespa.hosted.controller.restapi.changemanagement;
+
+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.Cursor;
+import com.yahoo.slime.Slime;
+import com.yahoo.vespa.hosted.controller.Controller;
+import com.yahoo.vespa.hosted.controller.auditlog.AuditLoggingRequestHandler;
+import com.yahoo.yolean.Exceptions;
+
+import java.util.logging.Level;
+
+public class ChangeManagementApiHandler extends AuditLoggingRequestHandler {
+
+ private final Controller controller;
+
+ public ChangeManagementApiHandler(LoggingRequestHandler.Context ctx, Controller controller) {
+ super(ctx, controller.auditLogger());
+ this.controller = controller;
+ }
+
+ @Override
+ public HttpResponse auditAndHandle(HttpRequest request) {
+ try {
+ switch (request.getMethod()) {
+ case POST:
+ return post(request);
+ default:
+ return ErrorResponse.methodNotAllowed("Method '" + request.getMethod() + "' is unsupported");
+ }
+ } catch (IllegalArgumentException e) {
+ return ErrorResponse.badRequest(Exceptions.toMessageString(e));
+ } catch (RuntimeException e) {
+ log.log(Level.WARNING, "Unexpected error handling '" + request.getUri() + "'", e);
+ return ErrorResponse.internalServerError(Exceptions.toMessageString(e));
+ }
+ }
+
+ private HttpResponse post(HttpRequest request) {
+ Path path = new Path(request.getUri());
+ if (path.matches("/changemanagement/v1/assessment")) return new SlimeJsonResponse(assessment());
+ return ErrorResponse.notFoundError("Nothing at " + path);
+ }
+
+ private Slime assessment() {
+ 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");
+
+ // Updated gives clue to if the assessement is old
+ assessment.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
+
+ return slime;
+ }
+} \ No newline at end of file
diff --git a/controller-server/src/test/java/com/yahoo/vespa/hosted/controller/restapi/ControllerContainerTest.java b/controller-server/src/test/java/com/yahoo/vespa/hosted/controller/restapi/ControllerContainerTest.java
index 4b4a8415d69..50123e497dc 100644
--- a/controller-server/src/test/java/com/yahoo/vespa/hosted/controller/restapi/ControllerContainerTest.java
+++ b/controller-server/src/test/java/com/yahoo/vespa/hosted/controller/restapi/ControllerContainerTest.java
@@ -108,6 +108,9 @@ public class ControllerContainerTest {
" <binding>http://*/routing/v1/*</binding>\n" +
" <binding>http://*/api/routing/v1/*</binding>\n" +
" </handler>\n" +
+ " <handler id='com.yahoo.vespa.hosted.controller.restapi.changemanagement.ChangeManagementApiHandler'>\n" +
+ " <binding>http://*/changemanagement/v1/*</binding>\n" +
+ " </handler>\n" +
variablePartXml() +
"</container>";
}
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
new file mode 100644
index 00000000000..ff0b3b83383
--- /dev/null
+++ b/controller-server/src/test/java/com/yahoo/vespa/hosted/controller/restapi/changemanagement/ChangeManagementApiHandlerTest.java
@@ -0,0 +1,42 @@
+// Copyright 2021 Oath Inc. Licensed under the terms of the Apache 2.0 license. See LICENSE in the project root.
+package com.yahoo.vespa.hosted.controller.restapi.changemanagement;
+
+import com.yahoo.application.container.handler.Request;
+import com.yahoo.vespa.athenz.api.AthenzIdentity;
+import com.yahoo.vespa.athenz.api.AthenzUser;
+import com.yahoo.vespa.hosted.controller.restapi.ContainerTester;
+import com.yahoo.vespa.hosted.controller.restapi.ControllerContainerTest;
+import org.intellij.lang.annotations.Language;
+import org.junit.Before;
+import org.junit.Test;
+
+import java.io.File;
+
+public class ChangeManagementApiHandlerTest extends ControllerContainerTest {
+
+ private static final String responses = "src/test/java/com/yahoo/vespa/hosted/controller/restapi/changemanagement/responses/";
+ private static final AthenzIdentity operator = AthenzUser.fromUserId("operatorUser");
+
+ private ContainerTester tester;
+
+ @Before
+ public void before() {
+ tester = new ContainerTester(container, responses);
+ addUserToHostedOperatorRole(operator);
+ }
+
+ @Test
+ public void test_api() {
+ assertFile(new Request("http://localhost:8080/changemanagement/v1/assessment", "{}", Request.Method.POST), "initial.json");
+ }
+
+ private void assertResponse(Request request, @Language("JSON") String body, int statusCode) {
+ addIdentityToRequest(request, operator);
+ tester.assertResponse(request, body, statusCode);
+ }
+
+ private void assertFile(Request request, String filename) {
+ addIdentityToRequest(request, operator);
+ tester.assertResponse(request, new File(filename));
+ }
+}
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
new file mode 100644
index 00000000000..b402ff313dc
--- /dev/null
+++ b/controller-server/src/test/java/com/yahoo/vespa/hosted/controller/restapi/changemanagement/responses/initial.json
@@ -0,0 +1,35 @@
+{
+ "assessment": {
+ "updated": "2021-03-12:12:12:12Z",
+ "clusters": [
+ {
+ "app": "mytenant:myapp:myinstance",
+ "zone": "prod.us-east-3",
+ "cluster": "mycontent",
+ "clusterSize": 19,
+ "clusterImpact": 3,
+ "upgradePolicy": "10%",
+ "utilizationInWindow": 0.5,
+ "suggestedAction": "nothing|bcp",
+ "impact": "low|degraded|outage",
+ "groups": [
+ {
+ "groupId": "23",
+ "groupSize": 4,
+ "groupImpact": 2
+ }
+ ]
+ }
+ ],
+ "hosts": [
+ {
+ "hostname": "myhostname",
+ "resources": "vcpu:memory:disk",
+ "state": "active",
+ "containers": 10,
+ "suggestedAction": "nothing|retire",
+ "impact": "low|degraded|outage"
+ }
+ ]
+ }
+} \ No newline at end of file