From a33c2b550a5b151c4b6c2a8a4d9b65153158da8d Mon Sep 17 00:00:00 2001 From: Martin Polden Date: Thu, 22 Aug 2019 11:29:47 +0200 Subject: Support storing status of multiple rotations per application --- .../vespa/hosted/controller/ControllerTester.java | 4 ++- .../DeploymentMetricsMaintainerTest.java | 12 ++++----- .../persistence/ApplicationSerializerTest.java | 30 ++++++++++++++++++---- .../persistence/testdata/complete-application.json | 19 +++++++++++++- .../restapi/ControllerContainerTest.java | 1 + .../restapi/application/ApplicationApiTest.java | 22 ++++++++-------- 6 files changed, 65 insertions(+), 23 deletions(-) (limited to 'controller-server/src/test') diff --git a/controller-server/src/test/java/com/yahoo/vespa/hosted/controller/ControllerTester.java b/controller-server/src/test/java/com/yahoo/vespa/hosted/controller/ControllerTester.java index 7c5442edbde..b79c0dc4ac2 100644 --- a/controller-server/src/test/java/com/yahoo/vespa/hosted/controller/ControllerTester.java +++ b/controller-server/src/test/java/com/yahoo/vespa/hosted/controller/ControllerTester.java @@ -27,6 +27,7 @@ import com.yahoo.vespa.hosted.controller.api.integration.dns.Record; import com.yahoo.vespa.hosted.controller.api.integration.dns.RecordName; import com.yahoo.vespa.hosted.controller.api.integration.organization.Contact; import com.yahoo.vespa.hosted.controller.api.integration.organization.MockContactRetriever; +import com.yahoo.vespa.hosted.controller.api.integration.routing.MemoryGlobalRoutingService; import com.yahoo.vespa.hosted.controller.api.integration.routing.RoutingGenerator; import com.yahoo.vespa.hosted.controller.api.integration.stubs.MockBuildService; import com.yahoo.vespa.hosted.controller.api.integration.stubs.MockMailer; @@ -349,7 +350,8 @@ public final class ControllerTester { new InMemoryFlagSource(), new MockMavenRepository(), new ApplicationCertificateMock(), - new MockMeteringClient()); + new MockMeteringClient(), + new MemoryGlobalRoutingService()); // Calculate initial versions controller.updateVersionStatus(VersionStatus.compute(controller)); return controller; diff --git a/controller-server/src/test/java/com/yahoo/vespa/hosted/controller/maintenance/DeploymentMetricsMaintainerTest.java b/controller-server/src/test/java/com/yahoo/vespa/hosted/controller/maintenance/DeploymentMetricsMaintainerTest.java index d75bb283fe6..ccafab622d0 100644 --- a/controller-server/src/test/java/com/yahoo/vespa/hosted/controller/maintenance/DeploymentMetricsMaintainerTest.java +++ b/controller-server/src/test/java/com/yahoo/vespa/hosted/controller/maintenance/DeploymentMetricsMaintainerTest.java @@ -115,21 +115,21 @@ public class DeploymentMetricsMaintainerTest { tester.controllerTester().metricsService().addRotation(assignedRotation); // No status gathered yet - assertEquals(RotationState.unknown, app.get().rotationStatus(deployment1.get())); - assertEquals(RotationState.unknown, app.get().rotationStatus(deployment2.get())); + assertEquals(RotationState.unknown, app.get().rotationStatus().of(deployment1.get())); + assertEquals(RotationState.unknown, app.get().rotationStatus().of(deployment2.get())); // One rotation out, one in metricsService.setZoneIn(assignedRotation, "proxy.prod.us-west-1.vip.test"); metricsService.setZoneOut(assignedRotation,"proxy.prod.us-east-3.vip.test"); maintainer.maintain(); - assertEquals(RotationState.in, app.get().rotationStatus(deployment1.get())); - assertEquals(RotationState.out, app.get().rotationStatus(deployment2.get())); + assertEquals(RotationState.in, app.get().rotationStatus().of(deployment1.get())); + assertEquals(RotationState.out, app.get().rotationStatus().of(deployment2.get())); // All rotations in metricsService.setZoneIn(assignedRotation,"proxy.prod.us-east-3.vip.test"); maintainer.maintain(); - assertEquals(RotationState.in, app.get().rotationStatus(deployment1.get())); - assertEquals(RotationState.in, app.get().rotationStatus(deployment2.get())); + assertEquals(RotationState.in, app.get().rotationStatus().of(deployment1.get())); + assertEquals(RotationState.in, app.get().rotationStatus().of(deployment2.get())); } private static DeploymentMetricsMaintainer maintainer(Controller controller) { diff --git a/controller-server/src/test/java/com/yahoo/vespa/hosted/controller/persistence/ApplicationSerializerTest.java b/controller-server/src/test/java/com/yahoo/vespa/hosted/controller/persistence/ApplicationSerializerTest.java index 36b13bbcf42..1f39840dc3a 100644 --- a/controller-server/src/test/java/com/yahoo/vespa/hosted/controller/persistence/ApplicationSerializerTest.java +++ b/controller-server/src/test/java/com/yahoo/vespa/hosted/controller/persistence/ApplicationSerializerTest.java @@ -6,7 +6,6 @@ import com.yahoo.config.application.api.DeploymentSpec; import com.yahoo.config.application.api.ValidationOverrides; import com.yahoo.config.provision.ApplicationId; import com.yahoo.config.provision.ClusterSpec; -import com.yahoo.config.provision.HostName; import com.yahoo.config.provision.zone.ZoneId; import com.yahoo.vespa.config.SlimeUtils; import com.yahoo.vespa.hosted.controller.Application; @@ -27,9 +26,12 @@ import com.yahoo.vespa.hosted.controller.application.DeploymentJobs; import com.yahoo.vespa.hosted.controller.application.DeploymentJobs.JobError; import com.yahoo.vespa.hosted.controller.application.DeploymentMetrics; import com.yahoo.vespa.hosted.controller.application.JobStatus; +import com.yahoo.vespa.hosted.controller.rotation.RotationId; import com.yahoo.vespa.hosted.controller.rotation.RotationState; +import com.yahoo.vespa.hosted.controller.rotation.RotationStatus; import org.junit.Test; +import java.nio.charset.StandardCharsets; import java.nio.file.Files; import java.nio.file.Path; import java.nio.file.Paths; @@ -37,6 +39,7 @@ import java.time.Instant; import java.time.temporal.ChronoUnit; import java.util.ArrayList; import java.util.HashMap; +import java.util.LinkedHashMap; import java.util.List; import java.util.Map; import java.util.Optional; @@ -44,12 +47,12 @@ import java.util.OptionalDouble; import java.util.OptionalInt; import java.util.OptionalLong; import java.util.Set; -import java.util.TreeMap; import static com.yahoo.config.provision.SystemName.main; import static com.yahoo.vespa.hosted.controller.ControllerTester.writable; import static java.util.Optional.empty; import static org.junit.Assert.assertEquals; +import static org.junit.Assert.assertTrue; /** * @author bratseth @@ -101,9 +104,10 @@ public class ApplicationSerializerTest { DeploymentJobs deploymentJobs = new DeploymentJobs(projectId, statusList, empty(), true); - Map rotationStatus = new TreeMap<>(); - rotationStatus.put(HostName.from("rot1.fqdn"), RotationState.in); - rotationStatus.put(HostName.from("rot2.fqdn"), RotationState.out); + var rotationStatusMap = new LinkedHashMap(); + rotationStatusMap.put(ZoneId.from("prod", "us-west-1"), RotationState.in); + rotationStatusMap.put(ZoneId.from("prod", "us-east-3"), RotationState.out); + var rotationStatus = new RotationStatus(Map.of(new RotationId("my-rotation"), rotationStatusMap)); Application original = new Application(ApplicationId.from("t1", "a1", "i1"), Instant.now().truncatedTo(ChronoUnit.MILLIS), @@ -249,4 +253,20 @@ public class ApplicationSerializerTest { // ok if no error } + @Test // TODO(mpolden): Remove after september 2019 + public void testLegacyRotationStatus() throws Exception { + var json = Files.readAllBytes(testData.resolve("complete-application.json")); + var application = applicationSerializer.fromSlime(SlimeUtils.jsonToSlime(json)); + var expected = new RotationStatus(Map.of(new RotationId("rotation-foo"), + Map.of(ZoneId.from("prod", "host1.fqdn"), RotationState.out, + ZoneId.from("prod", "host2.fqdn"), RotationState.in))); + assertEquals(expected, application.rotationStatus()); + + // Writes both new and old format + var serializedJson = new String(SlimeUtils.toJsonBytes(applicationSerializer.toSlime(application)), StandardCharsets.UTF_8); + var jsonFragment = "\"rotationStatus2\":[{\"rotationId\":\"rotation-foo\",\"status\":[{\"environment\":\"prod\",\"region\":\"host1.fqdn\",\"state\":\"out\"},{\"environment\":\"prod\",\"region\":\"host2.fqdn\",\"state\":\"in\"}]}]," + + "\"rotationStatus\":[{\"hostname\":\"prod.host1.fqdn\",\"status\":\"out\"},{\"hostname\":\"prod.host2.fqdn\",\"status\":\"in\"}]}"; + assertTrue("Writes both new and old format", serializedJson.contains(jsonFragment)); + } + } diff --git a/controller-server/src/test/java/com/yahoo/vespa/hosted/controller/persistence/testdata/complete-application.json b/controller-server/src/test/java/com/yahoo/vespa/hosted/controller/persistence/testdata/complete-application.json index cb5e34b8dae..c43b666d636 100644 --- a/controller-server/src/test/java/com/yahoo/vespa/hosted/controller/persistence/testdata/complete-application.json +++ b/controller-server/src/test/java/com/yahoo/vespa/hosted/controller/persistence/testdata/complete-application.json @@ -511,5 +511,22 @@ "outstandingChangeField": false, "queryQuality": 100, "writeQuality": 99.99894341115082, - "pemDeployKey": "-----BEGIN PUBLIC KEY-----\n∠( ᐛ 」∠)_\n-----END PUBLIC KEY-----" + "pemDeployKey": "-----BEGIN PUBLIC KEY-----\n∠( ᐛ 」∠)_\n-----END PUBLIC KEY-----", + "assignedRotations": [ + { + "rotationId": "rotation-foo", + "clusterId": "qrs", + "endpointId": "default" + } + ], + "rotationStatus": [ + { + "status": "out", + "hostname": "host1.fqdn" + }, + { + "status": "in", + "hostname": "host2.fqdn" + } + ] } 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 fe31200dc93..f2fbf36bec2 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 @@ -66,6 +66,7 @@ public class ControllerContainerTest { " \n" + " \n" + " \n" + + " \n" + " \n" + " \n" + " \n" + diff --git a/controller-server/src/test/java/com/yahoo/vespa/hosted/controller/restapi/application/ApplicationApiTest.java b/controller-server/src/test/java/com/yahoo/vespa/hosted/controller/restapi/application/ApplicationApiTest.java index 6ce7d7202e8..9bc5c879961 100644 --- a/controller-server/src/test/java/com/yahoo/vespa/hosted/controller/restapi/application/ApplicationApiTest.java +++ b/controller-server/src/test/java/com/yahoo/vespa/hosted/controller/restapi/application/ApplicationApiTest.java @@ -49,7 +49,6 @@ import com.yahoo.vespa.hosted.controller.application.DeploymentJobs; import com.yahoo.vespa.hosted.controller.application.DeploymentMetrics; import com.yahoo.vespa.hosted.controller.application.EndpointId; import com.yahoo.vespa.hosted.controller.application.JobStatus; -import com.yahoo.vespa.hosted.controller.rotation.RotationState; import com.yahoo.vespa.hosted.controller.application.RoutingPolicy; import com.yahoo.vespa.hosted.controller.athenz.ApplicationAction; import com.yahoo.vespa.hosted.controller.athenz.HostedAthenzIdentities; @@ -63,6 +62,8 @@ import com.yahoo.vespa.hosted.controller.integration.MetricsServiceMock; import com.yahoo.vespa.hosted.controller.restapi.ContainerControllerTester; import com.yahoo.vespa.hosted.controller.restapi.ContainerTester; import com.yahoo.vespa.hosted.controller.restapi.ControllerContainerTest; +import com.yahoo.vespa.hosted.controller.rotation.RotationState; +import com.yahoo.vespa.hosted.controller.rotation.RotationStatus; import com.yahoo.vespa.hosted.controller.tenant.AthenzTenant; import com.yahoo.vespa.hosted.controller.versions.VespaVersion; import com.yahoo.yolean.Exceptions; @@ -79,11 +80,11 @@ import java.util.ArrayList; import java.util.Base64; import java.util.Collections; import java.util.HashMap; +import java.util.LinkedHashMap; import java.util.List; import java.util.Map; import java.util.Optional; import java.util.Set; -import java.util.TreeMap; import java.util.function.Supplier; import static com.yahoo.application.container.handler.Request.Method.DELETE; @@ -1677,17 +1678,18 @@ public class ApplicationApiTest extends ControllerContainerTest { applicationList.forEach(application -> { applicationController.lockIfPresent(application.id(), locked -> applicationController.store(locked.withRotationStatus(rotationStatus(application)))); - });} + }); + } - private Map rotationStatus(Application application) { + private RotationStatus rotationStatus(Application application) { return controllerTester.controller().applications().rotationRepository().getRotation(application) - .map(rotation -> controllerTester.controller().metricsService().getRotationStatus(rotation.name())) - .map(rotationStatus -> { - Map result = new TreeMap<>(); - rotationStatus.forEach((hostname, status) -> result.put(hostname, RotationState.in)); - return result; + .map(rotation -> { + var rotationStatus = controllerTester.controller().metricsService().getRotationStatus(rotation.name()); + var statusMap = new LinkedHashMap(); + rotationStatus.forEach((hostname, status) -> statusMap.put(ZoneId.from("prod", hostname.value()), RotationState.in)); + return new RotationStatus(Map.of(rotation.id(), statusMap)); }) - .orElseGet(Collections::emptyMap); + .orElse(RotationStatus.EMPTY); } private void updateContactInformation() { -- cgit v1.2.3