diff options
author | Jon Marius Venstad <venstad@gmail.com> | 2021-01-11 09:13:54 +0100 |
---|---|---|
committer | Jon Marius Venstad <venstad@gmail.com> | 2021-01-11 09:13:54 +0100 |
commit | 65d8b3d6e2a3a95a495e9b3096660e15581d1bed (patch) | |
tree | 7723978d8ec06f6f8237e0da901f88bb289b5487 | |
parent | 00d005ea8544ee5677c2f18d5358cf65afebbf32 (diff) |
Add suspension mojo
11 files changed, 40 insertions, 5 deletions
diff --git a/controller-api/src/main/java/com/yahoo/vespa/hosted/controller/api/integration/configserver/ConfigServer.java b/controller-api/src/main/java/com/yahoo/vespa/hosted/controller/api/integration/configserver/ConfigServer.java index 0c9a415beab..11940b30ac1 100644 --- a/controller-api/src/main/java/com/yahoo/vespa/hosted/controller/api/integration/configserver/ConfigServer.java +++ b/controller-api/src/main/java/com/yahoo/vespa/hosted/controller/api/integration/configserver/ConfigServer.java @@ -144,4 +144,8 @@ public interface ConfigServer { /** Get maximum resources consumed */ QuotaUsage getQuotaUsage(DeploymentId deploymentId); + + /** Sets suspension status — whether application node operations are orchestrated — for the given deployment. */ + void setSuspension(DeploymentId deploymentId, boolean suspend); + } diff --git a/controller-server/src/main/java/com/yahoo/vespa/hosted/controller/ApplicationController.java b/controller-server/src/main/java/com/yahoo/vespa/hosted/controller/ApplicationController.java index 832668bf9f7..e071221dd05 100644 --- a/controller-server/src/main/java/com/yahoo/vespa/hosted/controller/ApplicationController.java +++ b/controller-server/src/main/java/com/yahoo/vespa/hosted/controller/ApplicationController.java @@ -985,4 +985,9 @@ public class ApplicationController { return Map.copyOf(warnings); } + /** Sets suspension status of the given deployment in its zone. */ + public void setSuspension(DeploymentId deploymentId, boolean suspend) { + configServer.setSuspension(deploymentId, suspend); + } + } 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 0dff1600751..67490bf9d8c 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 @@ -292,6 +292,7 @@ public class ApplicationApiHandler extends LoggingRequestHandler { if (path.matches("/application/v4/tenant/{tenant}/application/{application}/instance/{instance}/environment/{environment}/region/{region}/reindex")) return reindex(path.get("tenant"), path.get("application"), path.get("instance"), path.get("environment"), path.get("region"), request); if (path.matches("/application/v4/tenant/{tenant}/application/{application}/instance/{instance}/environment/{environment}/region/{region}/reindexing")) return enableReindexing(path.get("tenant"), path.get("application"), path.get("instance"), path.get("environment"), path.get("region"), request); if (path.matches("/application/v4/tenant/{tenant}/application/{application}/instance/{instance}/environment/{environment}/region/{region}/restart")) return restart(path.get("tenant"), path.get("application"), path.get("instance"), path.get("environment"), path.get("region"), request); + if (path.matches("/application/v4/tenant/{tenant}/application/{application}/instance/{instance}/environment/{environment}/region/{region}/suspend")) return suspend(path.get("tenant"), path.get("application"), path.get("instance"), path.get("environment"), path.get("region"), true); if (path.matches("/application/v4/tenant/{tenant}/application/{application}/environment/{environment}/region/{region}/instance/{instance}")) return deploy(path.get("tenant"), path.get("application"), path.get("instance"), path.get("environment"), path.get("region"), request); if (path.matches("/application/v4/tenant/{tenant}/application/{application}/environment/{environment}/region/{region}/instance/{instance}/deploy")) return deploy(path.get("tenant"), path.get("application"), path.get("instance"), path.get("environment"), path.get("region"), request); // legacy synonym of the above if (path.matches("/application/v4/tenant/{tenant}/application/{application}/environment/{environment}/region/{region}/instance/{instance}/restart")) return restart(path.get("tenant"), path.get("application"), path.get("instance"), path.get("environment"), path.get("region"), request); @@ -319,6 +320,7 @@ public class ApplicationApiHandler extends LoggingRequestHandler { if (path.matches("/application/v4/tenant/{tenant}/application/{application}/instance/{instance}/job/{jobtype}/pause")) return resume(appIdFromPath(path), jobTypeFromPath(path)); if (path.matches("/application/v4/tenant/{tenant}/application/{application}/instance/{instance}/environment/{environment}/region/{region}")) return deactivate(path.get("tenant"), path.get("application"), path.get("instance"), path.get("environment"), path.get("region"), request); if (path.matches("/application/v4/tenant/{tenant}/application/{application}/instance/{instance}/environment/{environment}/region/{region}/reindexing")) return disableReindexing(path.get("tenant"), path.get("application"), path.get("instance"), path.get("environment"), path.get("region"), request); + if (path.matches("/application/v4/tenant/{tenant}/application/{application}/instance/{instance}/environment/{environment}/region/{region}/suspend")) return suspend(path.get("tenant"), path.get("application"), path.get("instance"), path.get("environment"), path.get("region"), false); if (path.matches("/application/v4/tenant/{tenant}/application/{application}/instance/{instance}/environment/{environment}/region/{region}/global-rotation/override")) return setGlobalRotationOverride(path.get("tenant"), path.get("application"), path.get("instance"), path.get("environment"), path.get("region"), true, request); if (path.matches("/application/v4/tenant/{tenant}/application/{application}/environment/{environment}/region/{region}/instance/{instance}")) return deactivate(path.get("tenant"), path.get("application"), path.get("instance"), path.get("environment"), path.get("region"), request); if (path.matches("/application/v4/tenant/{tenant}/application/{application}/environment/{environment}/region/{region}/instance/{instance}/global-rotation/override")) return setGlobalRotationOverride(path.get("tenant"), path.get("application"), path.get("instance"), path.get("environment"), path.get("region"), true, request); @@ -1651,6 +1653,14 @@ public class ApplicationApiHandler extends LoggingRequestHandler { return new MessageResponse("Requested restart of " + deploymentId); } + /** Set suspension status of the given deployment. */ + private HttpResponse suspend(String tenantName, String applicationName, String instanceName, String environment, String region, boolean suspend) { + DeploymentId deploymentId = new DeploymentId(ApplicationId.from(tenantName, applicationName, instanceName), + requireZone(environment, region)); + controller.applications().setSuspension(deploymentId, suspend); + return new MessageResponse((suspend ? "Suspended" : "Resumed") + " orchestration of " + deploymentId); + } + private HttpResponse jobDeploy(ApplicationId id, JobType type, HttpRequest request) { if ( ! type.environment().isManuallyDeployed() && ! isOperator(request)) throw new IllegalArgumentException("Direct deployments are only allowed to manually deployed environments."); diff --git a/controller-server/src/test/java/com/yahoo/vespa/hosted/controller/ControllerTest.java b/controller-server/src/test/java/com/yahoo/vespa/hosted/controller/ControllerTest.java index 569c22d8bf6..8fcbb365804 100644 --- a/controller-server/src/test/java/com/yahoo/vespa/hosted/controller/ControllerTest.java +++ b/controller-server/src/test/java/com/yahoo/vespa/hosted/controller/ControllerTest.java @@ -667,7 +667,7 @@ public class ControllerTest { DeploymentId deployment2 = context.deploymentIdIn(ZoneId.from(Environment.prod, RegionName.from("us-east-3"))); assertFalse(tester.configServer().isSuspended(deployment1)); assertFalse(tester.configServer().isSuspended(deployment2)); - tester.configServer().setSuspended(deployment1, true); + tester.configServer().setSuspension(deployment1, true); assertTrue(tester.configServer().isSuspended(deployment1)); assertFalse(tester.configServer().isSuspended(deployment2)); } diff --git a/controller-server/src/test/java/com/yahoo/vespa/hosted/controller/deployment/DeploymentTriggerTest.java b/controller-server/src/test/java/com/yahoo/vespa/hosted/controller/deployment/DeploymentTriggerTest.java index 9b1eff60831..724ba61da2b 100644 --- a/controller-server/src/test/java/com/yahoo/vespa/hosted/controller/deployment/DeploymentTriggerTest.java +++ b/controller-server/src/test/java/com/yahoo/vespa/hosted/controller/deployment/DeploymentTriggerTest.java @@ -253,7 +253,7 @@ public class DeploymentTriggerTest { var application = tester.newDeploymentContext().submit().deploy(); // The first production zone is suspended: - tester.configServer().setSuspended(application.deploymentIdIn(ZoneId.from("prod", "us-central-1")), true); + tester.configServer().setSuspension(application.deploymentIdIn(ZoneId.from("prod", "us-central-1")), true); // A new change needs to be pushed out, but should not go beyond the suspended zone: application.submit() @@ -265,7 +265,7 @@ public class DeploymentTriggerTest { application.assertNotRunning(productionUsWest1); // The zone is unsuspended so jobs start: - tester.configServer().setSuspended(application.deploymentIdIn(ZoneId.from("prod", "us-central-1")), false); + tester.configServer().setSuspension(application.deploymentIdIn(ZoneId.from("prod", "us-central-1")), false); tester.triggerJobs(); application.runJob(productionUsWest1).runJob(productionUsEast3); assertEquals(Change.empty(), application.instance().change()); diff --git a/controller-server/src/test/java/com/yahoo/vespa/hosted/controller/integration/ConfigServerMock.java b/controller-server/src/test/java/com/yahoo/vespa/hosted/controller/integration/ConfigServerMock.java index ab31b7e21fe..7753570b72d 100644 --- a/controller-server/src/test/java/com/yahoo/vespa/hosted/controller/integration/ConfigServerMock.java +++ b/controller-server/src/test/java/com/yahoo/vespa/hosted/controller/integration/ConfigServerMock.java @@ -244,7 +244,8 @@ public class ConfigServerMock extends AbstractComponent implements ConfigServer return Optional.ofNullable(applications.get(new DeploymentId(id, zone))); } - public void setSuspended(DeploymentId deployment, boolean suspend) { + @Override + public void setSuspension(DeploymentId deployment, boolean suspend) { if (suspend) suspendedApplications.add(deployment); else diff --git a/docproc/src/test/java/com/yahoo/docproc/util/SplitterJoinerTestCase.java b/docproc/src/test/java/com/yahoo/docproc/util/SplitterJoinerTestCase.java index aa55d5b6a41..6c8c485aacb 100644 --- a/docproc/src/test/java/com/yahoo/docproc/util/SplitterJoinerTestCase.java +++ b/docproc/src/test/java/com/yahoo/docproc/util/SplitterJoinerTestCase.java @@ -18,7 +18,7 @@ import static org.junit.Assert.assertEquals; import static org.junit.Assert.assertTrue; /** - * @author <a href="mailto:einarmr@yahoo-inc.com">Einar M R Rosenvinge</a> + * @author Einar M R Rosenvinge */ @SuppressWarnings({"unchecked"}) public class SplitterJoinerTestCase { diff --git a/hosted-api/src/main/java/ai/vespa/hosted/api/ControllerHttpClient.java b/hosted-api/src/main/java/ai/vespa/hosted/api/ControllerHttpClient.java index 3a848b33c76..f17816f224d 100644 --- a/hosted-api/src/main/java/ai/vespa/hosted/api/ControllerHttpClient.java +++ b/hosted-api/src/main/java/ai/vespa/hosted/api/ControllerHttpClient.java @@ -121,6 +121,13 @@ public abstract class ControllerHttpClient { DELETE))); } + /** Sets suspension status of the given application in the given zone. */ + public String suspend(ApplicationId id, ZoneId zone, boolean suspend) { + return toMessage(send(request(HttpRequest.newBuilder(suspendPath(id, zone)) + .timeout(Duration.ofSeconds(10)), + suspend ? POST : DELETE))); + } + /** Returns the default {@link ZoneId} for the given environment, if any. */ public ZoneId defaultZone(Environment environment) { Inspector rootObject = toInspector(send(request(HttpRequest.newBuilder(defaultRegionPath(environment)) @@ -225,6 +232,10 @@ public abstract class ControllerHttpClient { "region", zone.region().value()); } + private URI suspendPath(ApplicationId id, ZoneId zone) { + return concatenated(deploymentPath(id, zone), "suspend"); + } + private URI deploymentJobPath(ApplicationId id, ZoneId zone) { return concatenated(instancePath(id), "deploy", jobNameOf(zone)); diff --git a/orchestrator-restapi/src/main/java/com/yahoo/vespa/orchestrator/restapi/ApplicationSuspensionApi.java b/orchestrator-restapi/src/main/java/com/yahoo/vespa/orchestrator/restapi/ApplicationSuspensionApi.java index 1c597a73d01..e44f6fa0df7 100644 --- a/orchestrator-restapi/src/main/java/com/yahoo/vespa/orchestrator/restapi/ApplicationSuspensionApi.java +++ b/orchestrator-restapi/src/main/java/com/yahoo/vespa/orchestrator/restapi/ApplicationSuspensionApi.java @@ -18,6 +18,7 @@ import java.util.Set; * * @author smorgrav */ +@Path("/orchestrator" + ApplicationSuspensionApi.PATH_PREFIX) public interface ApplicationSuspensionApi { /** * Path prefix for this api. Resources implementing this API should use this with a @Path annotation. diff --git a/orchestrator/src/test/java/com/yahoo/vespa/orchestrator/resources/ApplicationSuspensionResourceTest.java b/orchestrator/src/test/java/com/yahoo/vespa/orchestrator/resources/ApplicationSuspensionResourceTest.java index 4035e29d91a..770cb7f35d2 100644 --- a/orchestrator/src/test/java/com/yahoo/vespa/orchestrator/resources/ApplicationSuspensionResourceTest.java +++ b/orchestrator/src/test/java/com/yahoo/vespa/orchestrator/resources/ApplicationSuspensionResourceTest.java @@ -91,6 +91,7 @@ public class ApplicationSuspensionResourceTest { @Test public void delete_works_on_suspended_and_not_suspended_applications() { // Delete an application that is not suspended + var v = webTarget.path(RESOURCE_1).request(); Response reply = webTarget.path(RESOURCE_1).request().delete(); assertEquals(204, reply.getStatus()); @@ -114,6 +115,7 @@ public class ApplicationSuspensionResourceTest { @Test public void list_applications_returns_the_correct_list_of_suspended_applications() { // Test that initially we have the empty set + var v = webTarget.request(MediaType.APPLICATION_JSON); Response reply = webTarget.request(MediaType.APPLICATION_JSON).get(); assertEquals(200, reply.getStatus()); assertEquals("[]", reply.readEntity(String.class)); diff --git a/orchestrator/src/test/java/com/yahoo/vespa/orchestrator/status/ZkStatusServiceTest.java b/orchestrator/src/test/java/com/yahoo/vespa/orchestrator/status/ZkStatusServiceTest.java index 230290a632a..9a79828bc7b 100644 --- a/orchestrator/src/test/java/com/yahoo/vespa/orchestrator/status/ZkStatusServiceTest.java +++ b/orchestrator/src/test/java/com/yahoo/vespa/orchestrator/status/ZkStatusServiceTest.java @@ -225,6 +225,7 @@ public class ZkStatusServiceTest { }; } + @SuppressWarnings("deprecation") private static void killSession(CuratorFramework curatorFramework, TestingServer testingServer) { try { KillSession.kill(curatorFramework.getZookeeperClient().getZooKeeper(), testingServer.getConnectString()); |