From 6dcddc355a5dc06c715a47214f2a575931a9c2dd Mon Sep 17 00:00:00 2001 From: Jon Marius Venstad Date: Tue, 14 Nov 2017 10:59:37 +0100 Subject: Moved stuff around, and special behaviour for "recursive=true" --- .../yahoo/vespa/hosted/controller/Controller.java | 4 +- .../vespa/hosted/controller/restapi/Path.java | 3 - .../restapi/application/ApplicationApiHandler.java | 157 +++++++++++---------- 3 files changed, 83 insertions(+), 81 deletions(-) (limited to 'controller-server') diff --git a/controller-server/src/main/java/com/yahoo/vespa/hosted/controller/Controller.java b/controller-server/src/main/java/com/yahoo/vespa/hosted/controller/Controller.java index ddf5b989b07..b854ad3f771 100644 --- a/controller-server/src/main/java/com/yahoo/vespa/hosted/controller/Controller.java +++ b/controller-server/src/main/java/com/yahoo/vespa/hosted/controller/Controller.java @@ -156,8 +156,8 @@ public class Controller extends AbstractComponent { public Clock clock() { return clock; } - public URI getElkUri(Environment environment, RegionName region, DeploymentId deploymentId) { - return elkUrl(zoneRegistry.getLogServerUri(environment, region), deploymentId); + public URI getElkUri(DeploymentId deploymentId) { + return elkUrl(zoneRegistry.getLogServerUri(deploymentId.zone().environment(), deploymentId.zone().region()), deploymentId); } public List getConfigServerUris(Environment environment, RegionName region) { diff --git a/controller-server/src/main/java/com/yahoo/vespa/hosted/controller/restapi/Path.java b/controller-server/src/main/java/com/yahoo/vespa/hosted/controller/restapi/Path.java index c8c027d91c9..9853320e482 100644 --- a/controller-server/src/main/java/com/yahoo/vespa/hosted/controller/restapi/Path.java +++ b/controller-server/src/main/java/com/yahoo/vespa/hosted/controller/restapi/Path.java @@ -98,9 +98,6 @@ public class Path { */ public String getRest() { return rest; } - /** Returns this path as a string */ - public String asString() { return pathString; } - @Override public String toString() { return "path '" + Arrays.stream(elements).collect(Collectors.joining("/")) + "'"; 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 50b80e34788..1fd836c9d9a 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 @@ -62,7 +62,6 @@ import com.yahoo.vespa.hosted.controller.application.ClusterCost; import com.yahoo.vespa.hosted.controller.application.ClusterUtilization; import com.yahoo.vespa.hosted.controller.application.Deployment; import com.yahoo.vespa.hosted.controller.application.DeploymentCost; -import com.yahoo.vespa.hosted.controller.application.DeploymentJobs; import com.yahoo.vespa.hosted.controller.application.DeploymentMetrics; import com.yahoo.vespa.hosted.controller.application.JobStatus; import com.yahoo.vespa.hosted.controller.application.SourceRevision; @@ -169,7 +168,7 @@ public class ApplicationApiHandler extends LoggingRequestHandler { if (path.matches("/application/v4/cookiefreshness")) return cookieFreshness(request); if (path.matches("/application/v4/tenant/{tenant}")) return tenant(path.get("tenant"), request); if (path.matches("/application/v4/tenant/{tenant}/application")) return applications(path.get("tenant"), request); - if (path.matches("/application/v4/tenant/{tenant}/application/{application}")) return application(path.get("tenant"), path.get("application"), path, request); + if (path.matches("/application/v4/tenant/{tenant}/application/{application}")) return application(path.get("tenant"), path.get("application"), request); if (path.matches("/application/v4/tenant/{tenant}/application/{application}/environment/{environment}/region/{region}/instance/{instance}")) return deployment(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}/converge")) return waitForConvergence(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}/service")) return services(path.get("tenant"), path.get("application"), path.get("instance"), path.get("environment"), path.get("region"), request); @@ -222,10 +221,19 @@ public class ApplicationApiHandler extends LoggingRequestHandler { response.headers().put("Allow", "GET,PUT,POST,DELETE,OPTIONS"); return response; } - + + private HttpResponse recursiveRoot(HttpRequest request) { + Slime slime = new Slime(); + Cursor tenantArray = slime.setArray(); + for (Tenant tenant : controller.tenants().asList()) + toSlime(tenantArray.addObject(), tenant, request, true); + return new SlimeJsonResponse(slime); + } + private HttpResponse root(HttpRequest request) { - return new ResourceResponse(request, "user", "tenant", "tenant-pipeline", "athensDomain", - "property", "cookiefreshness"); + return request.getBooleanProperty("recursive") + ? recursiveRoot(request) + : new ResourceResponse(request, "user", "tenant", "tenant-pipeline", "athensDomain", "property", "cookiefreshness"); } private HttpResponse authenticatedUser(HttpRequest request) { @@ -310,20 +318,9 @@ public class ApplicationApiHandler extends LoggingRequestHandler { } private HttpResponse tenant(Tenant tenant, HttpRequest request, boolean listApplications) { - Slime tenantSlime = toSlime(tenant, request, listApplications); - tenant.getPropertyId().ifPresent(propertyId -> { - try { - toSlime(tenantSlime.get(), - controller.organization().propertyUri(propertyId), - controller.organization().contactsUri(propertyId), - controller.organization().issueCreationUri(propertyId), - controller.organization().contactsFor(propertyId)); - } - catch (RuntimeException e) { - log.log(Level.WARNING, "Error fetching property info for " + tenant + " with propertyId " + propertyId, e); - } - }); - return new SlimeJsonResponse(tenantSlime); + Slime slime = new Slime(); + toSlime(slime.setObject(), tenant, request, listApplications); + return new SlimeJsonResponse(slime); } private HttpResponse applications(String tenantName, HttpRequest request) { @@ -335,18 +332,21 @@ public class ApplicationApiHandler extends LoggingRequestHandler { return new SlimeJsonResponse(slime); } - private HttpResponse application(String tenantName, String applicationName, Path path, HttpRequest request) { - Slime slime = new Slime(); - Cursor response = slime.setObject(); - - com.yahoo.config.provision.ApplicationId applicationId = com.yahoo.config.provision.ApplicationId.from(tenantName, applicationName, "default"); + private HttpResponse application(String tenantName, String applicationName, HttpRequest request) { + ApplicationId applicationId = ApplicationId.from(tenantName, applicationName, "default"); Application application = controller.applications().get(applicationId) .orElseThrow(() -> new NotExistsException(applicationId + " not found")); - + + Slime slime = new Slime(); + toSlime(slime.setObject(), application, request); + return new SlimeJsonResponse(slime); + } + + private void toSlime(Cursor object, Application application, HttpRequest request) { // Currently deploying change if (application.deploying().isPresent()) { - Cursor deployingObject = response.setObject("deploying"); + Cursor deployingObject = object.setObject("deploying"); if (application.deploying().get() instanceof Change.VersionChange) deployingObject.setString("version", ((Change.VersionChange)application.deploying().get()).version().toString()); else if (((Change.ApplicationChange)application.deploying().get()).revision().isPresent()) @@ -358,7 +358,7 @@ public class ApplicationApiHandler extends LoggingRequestHandler { .deploymentOrder() .sortBy(application.deploymentSpec(), application.deploymentJobs().jobStatus().values()); - Cursor deploymentsArray = response.setArray("deploymentJobs"); + Cursor deploymentsArray = object.setArray("deploymentJobs"); for (JobStatus job : jobStatus) { Cursor jobObject = deploymentsArray.addObject(); jobObject.setString("type", job.type().jobName()); @@ -371,11 +371,11 @@ public class ApplicationApiHandler extends LoggingRequestHandler { } // Compile version. The version that should be used when building an application - response.setString("compileVersion", application.compileVersion(controller).toFullString()); + object.setString("compileVersion", application.compileVersion(controller).toFullString()); // Rotations - Cursor globalRotationsArray = response.setArray("globalRotations"); - Set rotations = controller.getRotationUris(applicationId); + Cursor globalRotationsArray = object.setArray("globalRotations"); + Set rotations = controller.getRotationUris(application.id()); Map rotationHealthStatus = rotations.isEmpty() ? Collections.emptyMap() : controller.getHealthStatus(rotations.iterator().next().getHost()); for (URI rotation : rotations) @@ -385,33 +385,36 @@ public class ApplicationApiHandler extends LoggingRequestHandler { List deployments = controller.applications().deploymentTrigger() .deploymentOrder() .sortBy(application.deploymentSpec().zones(), application.deployments().values()); - Cursor instancesArray = response.setArray("instances"); + Cursor instancesArray = object.setArray("instances"); for (Deployment deployment : deployments) { Cursor deploymentObject = instancesArray.addObject(); + deploymentObject.setString("environment", deployment.zone().environment().value()); deploymentObject.setString("region", deployment.zone().region().value()); deploymentObject.setString("instance", application.id().instance().value()); // pointless if ( ! rotations.isEmpty()) setRotationStatus(deployment, rotationHealthStatus, deploymentObject); - deploymentObject.setString("url", withPath(path.asString() + - "/environment/" + deployment.zone().environment().value() + - "/region/" + deployment.zone().region().value() + - "/instance/" + application.id().instance().value(), - request.getUri()).toString()); + + if (request.getBooleanProperty("recursive")) // List full deployment information when recursive. + toSlime(deploymentObject, new DeploymentId(application.id(), deployment.zone()), deployment, request); + else + deploymentObject.setString("url", withPath(request.getUri().getPath() + + "/environment/" + deployment.zone().environment().value() + + "/region/" + deployment.zone().region().value() + + "/instance/" + application.id().instance().value(), + request.getUri()).toString()); } // Metrics try { - MetricsService.ApplicationMetrics metrics = controller.metricsService().getApplicationMetrics(applicationId); - Cursor metricsObject = response.setObject("metrics"); + MetricsService.ApplicationMetrics metrics = controller.metricsService().getApplicationMetrics(application.id()); + Cursor metricsObject = object.setObject("metrics"); metricsObject.setDouble("queryServiceQuality", metrics.queryServiceQuality()); metricsObject.setDouble("writeServiceQuality", metrics.writeServiceQuality()); } catch (RuntimeException e) { log.log(Level.WARNING, "Failed getting Yamas metrics", Exceptions.toMessageString(e)); } - - return new SlimeJsonResponse(slime); } private HttpResponse deployment(String tenantName, String applicationName, String instanceName, String environment, String region, HttpRequest request) { @@ -426,21 +429,23 @@ public class ApplicationApiHandler extends LoggingRequestHandler { if (deployment == null) throw new NotExistsException(application + " is not deployed in " + deploymentId.zone()); - Optional deploymentEndpoints = controller.applications().getDeploymentEndpoints(deploymentId); - Slime slime = new Slime(); - Cursor response = slime.setObject(); + toSlime(slime.setObject(), deploymentId, deployment, request); + return new SlimeJsonResponse(slime); + } + + private void toSlime(Cursor response, DeploymentId deploymentId, Deployment deployment, HttpRequest request) { + + Optional deploymentEndpoints = controller.applications().getDeploymentEndpoints(deploymentId); Cursor serviceUrlArray = response.setArray("serviceUrls"); if (deploymentEndpoints.isPresent()) { for (URI uri : deploymentEndpoints.get().getContainerEndpoints()) serviceUrlArray.addString(uri.toString()); } - response.setString("nodes", withPath("/zone/v2/" + environment + "/" + region + "/nodes/v2/node/?&recursive=true&application=" + tenantName + "." + applicationName + "." + instanceName, request.getUri()).toString()); + response.setString("nodes", withPath("/zone/v2/" + deploymentId.zone().environment() + "/" + deploymentId.zone().region() + "/nodes/v2/node/?&recursive=true&application=" + deploymentId.applicationId().tenant() + "." + deploymentId.applicationId().application() + "." + deploymentId.applicationId().instance(), request.getUri()).toString()); - Environment env = Environment.from(environment); - RegionName regionName = RegionName.from(region); - URI elkUrl = controller.getElkUri(env, regionName, deploymentId); + URI elkUrl = controller.getElkUri(deploymentId); if (elkUrl != null) response.setString("elkUrl", elkUrl.toString()); @@ -448,10 +453,11 @@ public class ApplicationApiHandler extends LoggingRequestHandler { response.setString("version", deployment.version().toFullString()); response.setString("revision", deployment.revision().id()); response.setLong("deployTimeEpochMs", deployment.at().toEpochMilli()); - Optional deploymentTimeToLive = controller.zoneRegistry().getDeploymentTimeToLive(Environment.from(environment), RegionName.from(region)); + Optional deploymentTimeToLive = controller.zoneRegistry().getDeploymentTimeToLive(deploymentId.zone().environment(), deploymentId.zone().region()); deploymentTimeToLive.ifPresent(duration -> response.setLong("expiryTimeEpochMs", deployment.at().plus(duration).toEpochMilli())); - application.deploymentJobs().projectId().ifPresent(i -> response.setString("screwdriverId", String.valueOf(i))); + controller.applications().get(deploymentId.applicationId()).flatMap(application -> application.deploymentJobs().projectId()) + .ifPresent(i -> response.setString("screwdriverId", String.valueOf(i))); sourceRevisionToSlime(deployment.revision().source(), response); // Cost @@ -467,8 +473,6 @@ public class ApplicationApiHandler extends LoggingRequestHandler { metricsObject.setDouble("documentCount", metrics.documentCount()); metricsObject.setDouble("queryLatencyMillis", metrics.queryLatencyMillis()); metricsObject.setDouble("writeLatencyMillis", metrics.writeLatencyMillis()); - - return new SlimeJsonResponse(slime); } private void toSlime(ApplicationRevision revision, Cursor object) { @@ -575,7 +579,7 @@ public class ApplicationApiHandler extends LoggingRequestHandler { private HttpResponse services(String tenantName, String applicationName, String instanceName, String environment, String region, HttpRequest request) { ApplicationView applicationView = controller.getApplicationView(tenantName, applicationName, instanceName, environment, region); ServiceApiResponse response = new ServiceApiResponse(new Zone(Environment.from(environment), RegionName.from(region)), - new com.yahoo.config.provision.ApplicationId.Builder().tenant(tenantName).applicationName(applicationName).instanceName(instanceName).build(), + new ApplicationId.Builder().tenant(tenantName).applicationName(applicationName).instanceName(instanceName).build(), controller.getConfigServerUris(Environment.from(environment), RegionName.from(region)), request.getUri()); response.setResponse(applicationView); @@ -585,7 +589,7 @@ public class ApplicationApiHandler extends LoggingRequestHandler { private HttpResponse service(String tenantName, String applicationName, String instanceName, String environment, String region, String serviceName, String restPath, HttpRequest request) { Map result = controller.getServiceApiResponse(tenantName, applicationName, instanceName, environment, region, serviceName, restPath); ServiceApiResponse response = new ServiceApiResponse(new Zone(Environment.from(environment), RegionName.from(region)), - new com.yahoo.config.provision.ApplicationId.Builder().tenant(tenantName).applicationName(applicationName).instanceName(instanceName).build(), + new ApplicationId.Builder().tenant(tenantName).applicationName(applicationName).instanceName(instanceName).build(), controller.getConfigServerUris(Environment.from(environment), RegionName.from(region)), request.getUri()); response.setResponse(result, serviceName, restPath); @@ -684,7 +688,7 @@ public class ApplicationApiHandler extends LoggingRequestHandler { authorizer.throwIfUnauthorized(new TenantId(tenantName), request); Application application; try { - application = controller.applications().createApplication(com.yahoo.config.provision.ApplicationId.from(tenantName, applicationName, "default"), authorizer.getNToken(request)); + application = controller.applications().createApplication(ApplicationId.from(tenantName, applicationName, "default"), authorizer.getNToken(request)); } catch (ZmsException e) { // TODO: Push conversion down if (e.getCode() == com.yahoo.jdisc.Response.Status.FORBIDDEN) @@ -811,7 +815,7 @@ public class ApplicationApiHandler extends LoggingRequestHandler { private HttpResponse deleteApplication(String tenantName, String applicationName, HttpRequest request) { authorizer.throwIfUnauthorized(new TenantId(tenantName), request); - com.yahoo.config.provision.ApplicationId id = com.yahoo.config.provision.ApplicationId.from(tenantName, applicationName, "default"); + ApplicationId id = ApplicationId.from(tenantName, applicationName, "default"); Application deleted = controller.applications().deleteApplication(id, authorizer.getNToken(request)); if (deleted == null) return ErrorResponse.notFoundError("Could not delete application '" + id + "': Application not found"); @@ -874,7 +878,7 @@ public class ApplicationApiHandler extends LoggingRequestHandler { return authorizer.getPrincipalIfAny(request).map(Principal::getName); } - private void toSlime(Tenant tenant, Cursor object, HttpRequest request, boolean listApplications) { + private void toSlime(Cursor object, Tenant tenant, HttpRequest request, boolean listApplications) { object.setString("type", tenant.tenantType().name()); tenant.getAthensDomain().ifPresent(a -> object.setString("athensDomain", a.id())); tenant.getProperty().ifPresent(p -> object.setString("property", p.id())); @@ -887,6 +891,22 @@ public class ApplicationApiHandler extends LoggingRequestHandler { toSlime(application, applicationArray.addObject(), request); } } + tenant.getPropertyId().ifPresent(propertyId -> { + try { + object.setString("propertyUrl", controller.organization().propertyUri(propertyId).toString()); + object.setString("contactsUrl", controller.organization().contactsUri(propertyId).toString()); + object.setString("issueCreationUrl", controller.organization().issueCreationUri(propertyId).toString()); + Cursor lists = object.setArray("contacts"); + for (List contactList : controller.organization().contactsFor(propertyId)) { + Cursor list = lists.addArray(); + for (User contact : contactList) + list.addString(contact.displayName()); + } + } + catch (RuntimeException e) { + log.log(Level.WARNING, "Error fetching property info for " + tenant + " with propertyId " + propertyId, e); + } + }); } // A tenant has different content when in a list ... antipattern, but not solvable before application/v5 @@ -989,29 +1009,14 @@ public class ApplicationApiHandler extends LoggingRequestHandler { return Joiner.on("/").join(elements); } - private Slime toSlime(Tenant tenant, HttpRequest request, boolean listApplications) { - Slime slime = new Slime(); - toSlime(tenant, slime.setObject(), request, listApplications); - return slime; - } - - private void toSlime(Cursor root, URI propertyUri, URI contactsUri, URI issueCreationUri, List> contacts) { - root.setString("propertyUrl", propertyUri.toString()); - root.setString("contactsUrl", contactsUri.toString()); - root.setString("issueCreationUrl", issueCreationUri.toString()); - Cursor lists = root.setArray("contacts"); - for (List contactList : contacts) { - Cursor list = lists.addArray(); - for (User contact : contactList) - list.addString(contact.displayName()); - } - } - private void toSlime(Application application, Cursor object, HttpRequest request) { object.setString("application", application.id().application().value()); object.setString("instance", application.id().instance().value()); - object.setString("url", withPath("/application/v4/tenant/" + application.id().tenant().value() + - "/application/" + application.id().application().value(), request.getUri()).toString()); + if (request.getBooleanProperty("recursive")) + toSlime(object, application, request); + else + object.setString("url", withPath("/application/v4/tenant/" + application.id().tenant().value() + + "/application/" + application.id().application().value(), request.getUri()).toString()); } private Slime toSlime(ActivateResult result, long applicationZipSizeBytes) { -- cgit v1.2.3 From 91c8707bb7474c33309676876409ad3d1f5003df Mon Sep 17 00:00:00 2001 From: Jon Marius Venstad Date: Tue, 14 Nov 2017 12:01:08 +0100 Subject: Added tenant name to recursive root response, moved stuff, and test --- .../restapi/application/ApplicationApiHandler.java | 7 +- .../restapi/application/ApplicationApiTest.java | 84 +++--- .../application/responses/recursive-root.json | 297 +++++++++++++++++++++ 3 files changed, 349 insertions(+), 39 deletions(-) create mode 100644 controller-server/src/test/java/com/yahoo/vespa/hosted/controller/restapi/application/responses/recursive-root.json (limited to 'controller-server') 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 1fd836c9d9a..fc145a92b5d 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 @@ -225,8 +225,11 @@ public class ApplicationApiHandler extends LoggingRequestHandler { private HttpResponse recursiveRoot(HttpRequest request) { Slime slime = new Slime(); Cursor tenantArray = slime.setArray(); - for (Tenant tenant : controller.tenants().asList()) - toSlime(tenantArray.addObject(), tenant, request, true); + for (Tenant tenant : controller.tenants().asList()) { + Cursor tenantObject = tenantArray.addObject(); + tenantObject.setString("tenant", tenant.getId().id()); + toSlime(tenantObject, tenant, request, true); + } return new SlimeJsonResponse(slime); } 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 e3443d6c014..44e1c28050b 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 @@ -99,6 +99,38 @@ public class ApplicationApiTest extends ControllerContainerTest { // GET all tenants tester.assertResponse(request("/application/v4/tenant/", "", Request.Method.GET), new File("tenant-list.json")); + + + // Add another Athens domain, so we can try to create more tenants + addTenantAthenzDomain("domain2", "mytenant"); // New domain to test tenant w/property ID + // Add property info for that property id, as well, in the mock organization. + addPropertyData((MockOrganization) controllerTester.controller().organization(), "1234"); + // POST (add) a tenant with property ID + tester.assertResponse(request("/application/v4/tenant/tenant2", + "{\"athensDomain\":\"domain2\", \"property\":\"property2\", \"propertyId\":\"1234\"}", + Request.Method.POST), + new File("tenant-without-applications-with-id.json")); + // PUT (modify) a tenant with property ID + tester.assertResponse(request("/application/v4/tenant/tenant2", + "{\"athensDomain\":\"domain2\", \"property\":\"property2\", \"propertyId\":\"1234\"}", + Request.Method.PUT), + new File("tenant-without-applications-with-id.json")); + // GET a tenant with property ID + tester.assertResponse(request("/application/v4/tenant/tenant2", "", Request.Method.GET), + new File("tenant-without-applications-with-id.json")); + + // Test legacy OpsDB tenants + // POST (add) an OpsDB tenant with property ID + tester.assertResponse(request("/application/v4/tenant/tenant3", + "{\"userGroup\":\"group1\",\"property\":\"property1\",\"propertyId\":\"1234\"}", + Request.Method.POST), + new File("opsdb-tenant-with-id-without-applications.json")); + // PUT (modify) the OpsDB tenant to set another property + tester.assertResponse(request("/application/v4/tenant/tenant3", + "{\"userGroup\":\"group1\",\"property\":\"property2\",\"propertyId\":\"4321\"}", + Request.Method.PUT), + new File("opsdb-tenant-with-new-id-without-applications.json")); + // POST (create) an application tester.assertResponse(request("/application/v4/tenant/tenant1/application/application1", "", @@ -183,6 +215,14 @@ public class ApplicationApiTest extends ControllerContainerTest { setDeploymentMaintainedInfo(controllerTester); tester.assertResponse(request("/application/v4/tenant/tenant1/application/application1/environment/prod/region/corp-us-east-1/instance/default", "", Request.Method.GET), new File("deployment.json")); + + // GET at root, with "&recursive=true", returns info about all tenants, their applications and their deployments + tester.assertResponse(request("/application/v4/", + "", + Request.Method.GET, + "domain1", "mytenant&recursive=true"), + new File("recursive-root.json")); + // POST a 'restart application' command tester.assertResponse(request("/application/v4/tenant/tenant1/application/application1/environment/prod/region/corp-us-east-1/instance/default/restart", "", @@ -241,36 +281,6 @@ public class ApplicationApiTest extends ControllerContainerTest { tester.assertResponse(request("/application/v4/", "", Request.Method.OPTIONS), ""); - // Add another Athens domain, so we can try to create more tenants - addTenantAthenzDomain("domain2", "mytenant"); // New domain to test tenant w/property ID - // Add property info for that property id, as well, in the mock organization. - addPropertyData((MockOrganization) controllerTester.controller().organization(), "1234"); - // POST (add) a tenant with property ID - tester.assertResponse(request("/application/v4/tenant/tenant2", - "{\"athensDomain\":\"domain2\", \"property\":\"property2\", \"propertyId\":\"1234\"}", - Request.Method.POST), - new File("tenant-without-applications-with-id.json")); - // PUT (modify) a tenant with property ID - tester.assertResponse(request("/application/v4/tenant/tenant2", - "{\"athensDomain\":\"domain2\", \"property\":\"property2\", \"propertyId\":\"1234\"}", - Request.Method.PUT), - new File("tenant-without-applications-with-id.json")); - // GET a tenant with property ID - tester.assertResponse(request("/application/v4/tenant/tenant2", "", Request.Method.GET), - new File("tenant-without-applications-with-id.json")); - - // Test legacy OpsDB tenants - // POST (add) an OpsDB tenant with property ID - tester.assertResponse(request("/application/v4/tenant/tenant3", - "{\"userGroup\":\"group1\",\"property\":\"property1\",\"propertyId\":\"1234\"}", - Request.Method.POST), - new File("opsdb-tenant-with-id-without-applications.json")); - // PUT (modify) the OpsDB tenant to set another property - tester.assertResponse(request("/application/v4/tenant/tenant3", - "{\"userGroup\":\"group1\",\"property\":\"property2\",\"propertyId\":\"4321\"}", - Request.Method.PUT), - new File("opsdb-tenant-with-new-id-without-applications.json")); - // GET global rotation status tester.assertResponse(request("/application/v4/tenant/tenant1/application/application1/environment/prod/region/us-west-1/instance/default/global-rotation", "", Request.Method.GET), new File("global-rotation.json")); @@ -295,13 +305,6 @@ public class ApplicationApiTest extends ControllerContainerTest { controllerTester.controller().deconstruct(); } - private void addPropertyData(MockOrganization organization, String propertyIdValue) { - PropertyId propertyId = new PropertyId(propertyIdValue); - organization.addProperty(propertyId); - organization.setContactsFor(propertyId, Arrays.asList(Collections.singletonList(User.from("alice")), - Collections.singletonList(User.from("bob")))); - } - @Test public void testDeployDirectly() throws Exception { // Setup @@ -789,4 +792,11 @@ public class ApplicationApiTest extends ControllerContainerTest { } } + private void addPropertyData(MockOrganization organization, String propertyIdValue) { + PropertyId propertyId = new PropertyId(propertyIdValue); + organization.addProperty(propertyId); + organization.setContactsFor(propertyId, Arrays.asList(Collections.singletonList(User.from("alice")), + Collections.singletonList(User.from("bob")))); + } + } diff --git a/controller-server/src/test/java/com/yahoo/vespa/hosted/controller/restapi/application/responses/recursive-root.json b/controller-server/src/test/java/com/yahoo/vespa/hosted/controller/restapi/application/responses/recursive-root.json new file mode 100644 index 00000000000..71af7d4be44 --- /dev/null +++ b/controller-server/src/test/java/com/yahoo/vespa/hosted/controller/restapi/application/responses/recursive-root.json @@ -0,0 +1,297 @@ +[ + { + "tenant": "tenant2", + "type": "ATHENS", + "athensDomain": "domain2", + "property": "property2", + "propertyId": "1234", + "applications": [], + "propertyUrl": "www.properties.tld/1234", + "contactsUrl": "www.contacts.tld/1234", + "issueCreationUrl": "www.issues.tld/1234", + "contacts": [ + [ + "alice" + ], + [ + "bob" + ] + ] + }, + { + "tenant": "tenant3", + "type": "OPSDB", + "property": "property2", + "propertyId": "4321", + "userGroup": "group1", + "applications": [], + "propertyUrl": "www.properties.tld/4321", + "contactsUrl": "www.contacts.tld/4321", + "issueCreationUrl": "www.issues.tld/4321", + "contacts": [] + }, + { + "tenant": "tenant1", + "type": "ATHENS", + "athensDomain": "domain1", + "property": "property1", + "applications": [ + { + "application": "application1", + "instance": "default", + "deploying": { + "version": "6.1" + }, + "deploymentJobs": [ + { + "type": "system-test", + "success": true, + "lastTriggered": { + "id": -1, + "version": "6.1.0", + "revision": { + "hash": "(ignore)", + "source": { + "gitRepository": "repository1", + "gitBranch": "master", + "gitCommit": "commit1" + } + }, + "reason": "", + "at": "(ignore)" + }, + "lastCompleted": { + "id": 42, + "version": "6.1.0", + "revision": { + "hash": "(ignore)", + "source": { + "gitRepository": "repository1", + "gitBranch": "master", + "gitCommit": "commit1" + } + }, + "reason": "", + "at": "(ignore)" + }, + "lastSuccess": { + "id": 42, + "version": "6.1.0", + "revision": { + "hash": "(ignore)", + "source": { + "gitRepository": "repository1", + "gitBranch": "master", + "gitCommit": "commit1" + } + }, + "reason": "", + "at": "(ignore)" + } + }, + { + "type": "staging-test", + "success": true, + "lastTriggered": { + "id": -1, + "version": "6.1.0", + "revision": { + "hash": "(ignore)", + "source": { + "gitRepository": "repository1", + "gitBranch": "master", + "gitCommit": "commit1" + } + }, + "reason": "system-test completed", + "at": "(ignore)" + }, + "lastCompleted": { + "id": 42, + "version": "6.1.0", + "revision": { + "hash": "(ignore)", + "source": { + "gitRepository": "repository1", + "gitBranch": "master", + "gitCommit": "commit1" + } + }, + "reason": "system-test completed", + "at": "(ignore)" + }, + "lastSuccess": { + "id": 42, + "version": "6.1.0", + "revision": { + "hash": "(ignore)", + "source": { + "gitRepository": "repository1", + "gitBranch": "master", + "gitCommit": "commit1" + } + }, + "reason": "system-test completed", + "at": "(ignore)" + } + }, + { + "type": "production-corp-us-east-1", + "success": false, + "lastTriggered": { + "id": -1, + "version": "6.1.0", + "revision": { + "hash": "(ignore)", + "source": { + "gitRepository": "repository1", + "gitBranch": "master", + "gitCommit": "commit1" + } + }, + "reason": "Immediate retry on failure", + "at": "(ignore)" + }, + "lastCompleted": { + "id": 42, + "version": "6.1.0", + "revision": { + "hash": "(ignore)", + "source": { + "gitRepository": "repository1", + "gitBranch": "master", + "gitCommit": "commit1" + } + }, + "reason": "staging-test completed", + "at": "(ignore)" + }, + "firstFailing": { + "id": 42, + "version": "6.1.0", + "revision": { + "hash": "(ignore)", + "source": { + "gitRepository": "repository1", + "gitBranch": "master", + "gitCommit": "commit1" + } + }, + "reason": "staging-test completed", + "at": "(ignore)" + } + } + ], + "compileVersion": "6.1.0", + "globalRotations": [ + "http://fake-global-rotation-tenant1.application1" + ], + "instances": [ + { + "environment": "dev", + "region": "us-west-1", + "instance": "default", + "serviceUrls": [ + "http://old-endpoint.vespa.yahooapis.com:4080", + "http://qrs-endpoint.vespa.yahooapis.com:4080", + "http://feeding-endpoint.vespa.yahooapis.com:4080", + "http://global-endpoint.vespa.yahooapis.com:4080", + "http://alias-endpoint.vespa.yahooapis.com:4080" + ], + "nodes": "http://localhost:8080/zone/v2/dev/us-west-1/nodes/v2/node/%3F&recursive=true&application=tenant1.application1.default", + "yamasUrl": "http://monitoring-system.test/?environment=dev®ion=us-west-1&application=tenant1.application1", + "version": "6.1.0", + "revision": "(ignore)", + "deployTimeEpochMs": "(ignore)", + "screwdriverId": "123", + "cost": { + "tco": 0, + "waste": 0, + "utilization": 0.0, + "cluster": {} + }, + "metrics": { + "queriesPerSecond": 0.0, + "writesPerSecond": 0.0, + "documentCount": 0.0, + "queryLatencyMillis": 0.0, + "writeLatencyMillis": 0.0 + } + }, + { + "environment": "prod", + "region": "corp-us-east-1", + "instance": "default", + "bcpStatus": { + "rotationStatus": "UNKNOWN" + }, + "serviceUrls": [ + "http://old-endpoint.vespa.yahooapis.com:4080", + "http://qrs-endpoint.vespa.yahooapis.com:4080", + "http://feeding-endpoint.vespa.yahooapis.com:4080", + "http://global-endpoint.vespa.yahooapis.com:4080", + "http://alias-endpoint.vespa.yahooapis.com:4080" + ], + "nodes": "http://localhost:8080/zone/v2/prod/corp-us-east-1/nodes/v2/node/%3F&recursive=true&application=tenant1.application1.default", + "elkUrl": "http://log.prod.corp-us-east-1.test/#/discover?_g=()&_a=(columns:!(_source),index:'logstash-*',interval:auto,query:(query_string:(analyze_wildcard:!t,query:'HV-tenant:%22tenant1%22%20AND%20HV-application:%22application1%22%20AND%20HV-region:%22corp-us-east-1%22%20AND%20HV-instance:%22default%22%20AND%20HV-environment:%22prod%22')),sort:!('@timestamp',desc))", + "yamasUrl": "http://monitoring-system.test/?environment=prod®ion=corp-us-east-1&application=tenant1.application1", + "version": "6.1.0", + "revision": "(ignore)", + "deployTimeEpochMs": "(ignore)", + "screwdriverId": "123", + "gitRepository": "repository1", + "gitBranch": "master", + "gitCommit": "commit1", + "cost": { + "tco": 74, + "waste": 0, + "utilization": 2.999999999999999, + "cluster": { + "cluster1": { + "count": 2, + "resource": "cpu", + "utilization": 2.999999999999999, + "tco": 74, + "waste": 0, + "flavor": "flavor1", + "flavorCost": 37.0, + "flavorCpu": 2.0, + "flavorMem": 4.0, + "flavorDisk": 50.0, + "type": "content", + "util": { + "cpu": 2.999999999999999, + "mem": 0.4285714285714286, + "disk": 0.5714285714285715, + "diskBusy": 1.0 + }, + "usage": { + "cpu": 0.6, + "mem": 0.3, + "disk": 0.4, + "diskBusy": 0.3 + }, + "hostnames": [ + "host1", + "host2" + ] + } + } + }, + "metrics": { + "queriesPerSecond": 1.0, + "writesPerSecond": 2.0, + "documentCount": 3.0, + "queryLatencyMillis": 4.0, + "writeLatencyMillis": 5.0 + } + } + ], + "metrics": { + "queryServiceQuality": 0.5, + "writeServiceQuality": 0.7 + } + } + ] + } +] -- cgit v1.2.3 From 4bbc0c91453596ba7e7d91d6dce5b0923a956964 Mon Sep 17 00:00:00 2001 From: Jon Marius Venstad Date: Tue, 14 Nov 2017 12:40:32 +0100 Subject: Test recursive responses at tenant and application level as well --- .../restapi/application/ApplicationApiTest.java | 13 + .../responses/recursive-application.json | 254 ++++++++++++++++++++ .../application/responses/recursive-tenant.json | 263 +++++++++++++++++++++ 3 files changed, 530 insertions(+) create mode 100644 controller-server/src/test/java/com/yahoo/vespa/hosted/controller/restapi/application/responses/recursive-application.json create mode 100644 controller-server/src/test/java/com/yahoo/vespa/hosted/controller/restapi/application/responses/recursive-tenant.json (limited to 'controller-server') 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 44e1c28050b..365f73ef2cd 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 @@ -222,6 +222,19 @@ public class ApplicationApiTest extends ControllerContainerTest { Request.Method.GET, "domain1", "mytenant&recursive=true"), new File("recursive-root.json")); + // GET at a tenant, with "&recursive=true", returns full info about their applications and their deployments + tester.assertResponse(request("/application/v4/tenant/tenant1/", + "", + Request.Method.GET, + "domain1", "mytenant&recursive=true"), + new File("recursive-tenant.json")); + // GET at an application, with "&recursive=true", returns full info about its deployments + tester.assertResponse(request("/application/v4/tenant/tenant1/application/application1/", + "", + Request.Method.GET, + "domain1", "mytenant&recursive=true"), + new File("recursive-application.json")); + // POST a 'restart application' command tester.assertResponse(request("/application/v4/tenant/tenant1/application/application1/environment/prod/region/corp-us-east-1/instance/default/restart", diff --git a/controller-server/src/test/java/com/yahoo/vespa/hosted/controller/restapi/application/responses/recursive-application.json b/controller-server/src/test/java/com/yahoo/vespa/hosted/controller/restapi/application/responses/recursive-application.json new file mode 100644 index 00000000000..ee0b7bfa906 --- /dev/null +++ b/controller-server/src/test/java/com/yahoo/vespa/hosted/controller/restapi/application/responses/recursive-application.json @@ -0,0 +1,254 @@ +{ + "deploying": { + "version": "6.1" + }, + "deploymentJobs": [ + { + "type": "system-test", + "success": true, + "lastTriggered": { + "id": -1, + "version": "6.1.0", + "revision": { + "hash": "(ignore)", + "source": { + "gitRepository": "repository1", + "gitBranch": "master", + "gitCommit": "commit1" + } + }, + "reason": "", + "at": "(ignore)" + }, + "lastCompleted": { + "id": 42, + "version": "6.1.0", + "revision": { + "hash": "(ignore)", + "source": { + "gitRepository": "repository1", + "gitBranch": "master", + "gitCommit": "commit1" + } + }, + "reason": "", + "at": "(ignore)" + }, + "lastSuccess": { + "id": 42, + "version": "6.1.0", + "revision": { + "hash": "(ignore)", + "source": { + "gitRepository": "repository1", + "gitBranch": "master", + "gitCommit": "commit1" + } + }, + "reason": "", + "at": "(ignore)" + } + }, + { + "type": "staging-test", + "success": true, + "lastTriggered": { + "id": -1, + "version": "6.1.0", + "revision": { + "hash": "(ignore)", + "source": { + "gitRepository": "repository1", + "gitBranch": "master", + "gitCommit": "commit1" + } + }, + "reason": "system-test completed", + "at": "(ignore)" + }, + "lastCompleted": { + "id": 42, + "version": "6.1.0", + "revision": { + "hash": "(ignore)", + "source": { + "gitRepository": "repository1", + "gitBranch": "master", + "gitCommit": "commit1" + } + }, + "reason": "system-test completed", + "at": "(ignore)" + }, + "lastSuccess": { + "id": 42, + "version": "6.1.0", + "revision": { + "hash": "(ignore)", + "source": { + "gitRepository": "repository1", + "gitBranch": "master", + "gitCommit": "commit1" + } + }, + "reason": "system-test completed", + "at": "(ignore)" + } + }, + { + "type": "production-corp-us-east-1", + "success": false, + "lastTriggered": { + "id": -1, + "version": "6.1.0", + "revision": { + "hash": "(ignore)", + "source": { + "gitRepository": "repository1", + "gitBranch": "master", + "gitCommit": "commit1" + } + }, + "reason": "Immediate retry on failure", + "at": "(ignore)" + }, + "lastCompleted": { + "id": 42, + "version": "6.1.0", + "revision": { + "hash": "(ignore)", + "source": { + "gitRepository": "repository1", + "gitBranch": "master", + "gitCommit": "commit1" + } + }, + "reason": "staging-test completed", + "at": "(ignore)" + }, + "firstFailing": { + "id": 42, + "version": "6.1.0", + "revision": { + "hash": "(ignore)", + "source": { + "gitRepository": "repository1", + "gitBranch": "master", + "gitCommit": "commit1" + } + }, + "reason": "staging-test completed", + "at": "(ignore)" + } + } + ], + "compileVersion": "6.1.0", + "globalRotations": [ + "http://fake-global-rotation-tenant1.application1" + ], + "instances": [ + { + "environment": "dev", + "region": "us-west-1", + "instance": "default", + "serviceUrls": [ + "http://old-endpoint.vespa.yahooapis.com:4080", + "http://qrs-endpoint.vespa.yahooapis.com:4080", + "http://feeding-endpoint.vespa.yahooapis.com:4080", + "http://global-endpoint.vespa.yahooapis.com:4080", + "http://alias-endpoint.vespa.yahooapis.com:4080" + ], + "nodes": "http://localhost:8080/zone/v2/dev/us-west-1/nodes/v2/node/%3F&recursive=true&application=tenant1.application1.default", + "yamasUrl": "http://monitoring-system.test/?environment=dev®ion=us-west-1&application=tenant1.application1", + "version": "6.1.0", + "revision": "(ignore)", + "deployTimeEpochMs": "(ignore)", + "screwdriverId": "123", + "cost": { + "tco": 0, + "waste": 0, + "utilization": 0.0, + "cluster": {} + }, + "metrics": { + "queriesPerSecond": 0.0, + "writesPerSecond": 0.0, + "documentCount": 0.0, + "queryLatencyMillis": 0.0, + "writeLatencyMillis": 0.0 + } + }, + { + "environment": "prod", + "region": "corp-us-east-1", + "instance": "default", + "bcpStatus": { + "rotationStatus": "UNKNOWN" + }, + "serviceUrls": [ + "http://old-endpoint.vespa.yahooapis.com:4080", + "http://qrs-endpoint.vespa.yahooapis.com:4080", + "http://feeding-endpoint.vespa.yahooapis.com:4080", + "http://global-endpoint.vespa.yahooapis.com:4080", + "http://alias-endpoint.vespa.yahooapis.com:4080" + ], + "nodes": "http://localhost:8080/zone/v2/prod/corp-us-east-1/nodes/v2/node/%3F&recursive=true&application=tenant1.application1.default", + "elkUrl": "http://log.prod.corp-us-east-1.test/#/discover?_g=()&_a=(columns:!(_source),index:'logstash-*',interval:auto,query:(query_string:(analyze_wildcard:!t,query:'HV-tenant:%22tenant1%22%20AND%20HV-application:%22application1%22%20AND%20HV-region:%22corp-us-east-1%22%20AND%20HV-instance:%22default%22%20AND%20HV-environment:%22prod%22')),sort:!('@timestamp',desc))", + "yamasUrl": "http://monitoring-system.test/?environment=prod®ion=corp-us-east-1&application=tenant1.application1", + "version": "6.1.0", + "revision": "(ignore)", + "deployTimeEpochMs": "(ignore)", + "screwdriverId": "123", + "gitRepository": "repository1", + "gitBranch": "master", + "gitCommit": "commit1", + "cost": { + "tco": 74, + "waste": 0, + "utilization": 2.999999999999999, + "cluster": { + "cluster1": { + "count": 2, + "resource": "cpu", + "utilization": 2.999999999999999, + "tco": 74, + "waste": 0, + "flavor": "flavor1", + "flavorCost": 37.0, + "flavorCpu": 2.0, + "flavorMem": 4.0, + "flavorDisk": 50.0, + "type": "content", + "util": { + "cpu": 2.999999999999999, + "mem": 0.4285714285714286, + "disk": 0.5714285714285715, + "diskBusy": 1.0 + }, + "usage": { + "cpu": 0.6, + "mem": 0.3, + "disk": 0.4, + "diskBusy": 0.3 + }, + "hostnames": [ + "host1", + "host2" + ] + } + } + }, + "metrics": { + "queriesPerSecond": 1.0, + "writesPerSecond": 2.0, + "documentCount": 3.0, + "queryLatencyMillis": 4.0, + "writeLatencyMillis": 5.0 + } + } + ], + "metrics": { + "queryServiceQuality": 0.5, + "writeServiceQuality": 0.7 + } +} diff --git a/controller-server/src/test/java/com/yahoo/vespa/hosted/controller/restapi/application/responses/recursive-tenant.json b/controller-server/src/test/java/com/yahoo/vespa/hosted/controller/restapi/application/responses/recursive-tenant.json new file mode 100644 index 00000000000..e05b05ed1a7 --- /dev/null +++ b/controller-server/src/test/java/com/yahoo/vespa/hosted/controller/restapi/application/responses/recursive-tenant.json @@ -0,0 +1,263 @@ +{ + "type": "ATHENS", + "athensDomain": "domain1", + "property": "property1", + "applications": [ + { + "application": "application1", + "instance": "default", + "deploying": { + "version": "6.1" + }, + "deploymentJobs": [ + { + "type": "system-test", + "success": true, + "lastTriggered": { + "id": -1, + "version": "6.1.0", + "revision": { + "hash": "(ignore)", + "source": { + "gitRepository": "repository1", + "gitBranch": "master", + "gitCommit": "commit1" + } + }, + "reason": "", + "at": "(ignore)" + }, + "lastCompleted": { + "id": 42, + "version": "6.1.0", + "revision": { + "hash": "(ignore)", + "source": { + "gitRepository": "repository1", + "gitBranch": "master", + "gitCommit": "commit1" + } + }, + "reason": "", + "at": "(ignore)" + }, + "lastSuccess": { + "id": 42, + "version": "6.1.0", + "revision": { + "hash": "(ignore)", + "source": { + "gitRepository": "repository1", + "gitBranch": "master", + "gitCommit": "commit1" + } + }, + "reason": "", + "at": "(ignore)" + } + }, + { + "type": "staging-test", + "success": true, + "lastTriggered": { + "id": -1, + "version": "6.1.0", + "revision": { + "hash": "(ignore)", + "source": { + "gitRepository": "repository1", + "gitBranch": "master", + "gitCommit": "commit1" + } + }, + "reason": "system-test completed", + "at": "(ignore)" + }, + "lastCompleted": { + "id": 42, + "version": "6.1.0", + "revision": { + "hash": "(ignore)", + "source": { + "gitRepository": "repository1", + "gitBranch": "master", + "gitCommit": "commit1" + } + }, + "reason": "system-test completed", + "at": "(ignore)" + }, + "lastSuccess": { + "id": 42, + "version": "6.1.0", + "revision": { + "hash": "(ignore)", + "source": { + "gitRepository": "repository1", + "gitBranch": "master", + "gitCommit": "commit1" + } + }, + "reason": "system-test completed", + "at": "(ignore)" + } + }, + { + "type": "production-corp-us-east-1", + "success": false, + "lastTriggered": { + "id": -1, + "version": "6.1.0", + "revision": { + "hash": "(ignore)", + "source": { + "gitRepository": "repository1", + "gitBranch": "master", + "gitCommit": "commit1" + } + }, + "reason": "Immediate retry on failure", + "at": "(ignore)" + }, + "lastCompleted": { + "id": 42, + "version": "6.1.0", + "revision": { + "hash": "(ignore)", + "source": { + "gitRepository": "repository1", + "gitBranch": "master", + "gitCommit": "commit1" + } + }, + "reason": "staging-test completed", + "at": "(ignore)" + }, + "firstFailing": { + "id": 42, + "version": "6.1.0", + "revision": { + "hash": "(ignore)", + "source": { + "gitRepository": "repository1", + "gitBranch": "master", + "gitCommit": "commit1" + } + }, + "reason": "staging-test completed", + "at": "(ignore)" + } + } + ], + "compileVersion": "6.1.0", + "globalRotations": [ + "http://fake-global-rotation-tenant1.application1" + ], + "instances": [ + { + "environment": "dev", + "region": "us-west-1", + "instance": "default", + "serviceUrls": [ + "http://old-endpoint.vespa.yahooapis.com:4080", + "http://qrs-endpoint.vespa.yahooapis.com:4080", + "http://feeding-endpoint.vespa.yahooapis.com:4080", + "http://global-endpoint.vespa.yahooapis.com:4080", + "http://alias-endpoint.vespa.yahooapis.com:4080" + ], + "nodes": "http://localhost:8080/zone/v2/dev/us-west-1/nodes/v2/node/%3F&recursive=true&application=tenant1.application1.default", + "yamasUrl": "http://monitoring-system.test/?environment=dev®ion=us-west-1&application=tenant1.application1", + "version": "6.1.0", + "revision": "(ignore)", + "deployTimeEpochMs": "(ignore)", + "screwdriverId": "123", + "cost": { + "tco": 0, + "waste": 0, + "utilization": 0.0, + "cluster": {} + }, + "metrics": { + "queriesPerSecond": 0.0, + "writesPerSecond": 0.0, + "documentCount": 0.0, + "queryLatencyMillis": 0.0, + "writeLatencyMillis": 0.0 + } + }, + { + "environment": "prod", + "region": "corp-us-east-1", + "instance": "default", + "bcpStatus": { + "rotationStatus": "UNKNOWN" + }, + "serviceUrls": [ + "http://old-endpoint.vespa.yahooapis.com:4080", + "http://qrs-endpoint.vespa.yahooapis.com:4080", + "http://feeding-endpoint.vespa.yahooapis.com:4080", + "http://global-endpoint.vespa.yahooapis.com:4080", + "http://alias-endpoint.vespa.yahooapis.com:4080" + ], + "nodes": "http://localhost:8080/zone/v2/prod/corp-us-east-1/nodes/v2/node/%3F&recursive=true&application=tenant1.application1.default", + "elkUrl": "http://log.prod.corp-us-east-1.test/#/discover?_g=()&_a=(columns:!(_source),index:'logstash-*',interval:auto,query:(query_string:(analyze_wildcard:!t,query:'HV-tenant:%22tenant1%22%20AND%20HV-application:%22application1%22%20AND%20HV-region:%22corp-us-east-1%22%20AND%20HV-instance:%22default%22%20AND%20HV-environment:%22prod%22')),sort:!('@timestamp',desc))", + "yamasUrl": "http://monitoring-system.test/?environment=prod®ion=corp-us-east-1&application=tenant1.application1", + "version": "6.1.0", + "revision": "(ignore)", + "deployTimeEpochMs": "(ignore)", + "screwdriverId": "123", + "gitRepository": "repository1", + "gitBranch": "master", + "gitCommit": "commit1", + "cost": { + "tco": 74, + "waste": 0, + "utilization": 2.999999999999999, + "cluster": { + "cluster1": { + "count": 2, + "resource": "cpu", + "utilization": 2.999999999999999, + "tco": 74, + "waste": 0, + "flavor": "flavor1", + "flavorCost": 37.0, + "flavorCpu": 2.0, + "flavorMem": 4.0, + "flavorDisk": 50.0, + "type": "content", + "util": { + "cpu": 2.999999999999999, + "mem": 0.4285714285714286, + "disk": 0.5714285714285715, + "diskBusy": 1.0 + }, + "usage": { + "cpu": 0.6, + "mem": 0.3, + "disk": 0.4, + "diskBusy": 0.3 + }, + "hostnames": [ + "host1", + "host2" + ] + } + } + }, + "metrics": { + "queriesPerSecond": 1.0, + "writesPerSecond": 2.0, + "documentCount": 3.0, + "queryLatencyMillis": 4.0, + "writeLatencyMillis": 5.0 + } + } + ], + "metrics": { + "queryServiceQuality": 0.5, + "writeServiceQuality": 0.7 + } + } + ] +} -- cgit v1.2.3 From 5c2ab1c3bc6ac66d056264ec1765cfa75728282c Mon Sep 17 00:00:00 2001 From: Jon Marius Venstad Date: Tue, 14 Nov 2017 14:23:43 +0100 Subject: Use @include and list self-info in tenant and application blobs --- .../restapi/application/ApplicationApiHandler.java | 25 +- .../restapi/application/ApplicationApiTest.java | 4 +- ...cation-without-change-multiple-deployments.json | 1 + .../restapi/application/responses/application.json | 2 + .../application/responses/application1.json | 159 +++++++++++++ .../application/responses/dev-us-west-1.json | 31 +++ .../opsdb-tenant-with-id-without-applications.json | 1 + ...db-tenant-with-new-id-without-applications.json | 1 + .../application/responses/prod-corp-us-east-1.json | 68 ++++++ .../responses/recursive-application.json | 254 -------------------- .../application/responses/recursive-root.json | 265 +-------------------- .../application/responses/recursive-tenant.json | 263 -------------------- .../responses/tenant-with-application.json | 1 + .../tenant-without-applications-with-id.json | 1 + .../responses/tenant-without-applications.json | 1 + .../restapi/application/responses/tenant1.json | 9 + 16 files changed, 291 insertions(+), 795 deletions(-) create mode 100644 controller-server/src/test/java/com/yahoo/vespa/hosted/controller/restapi/application/responses/application1.json create mode 100644 controller-server/src/test/java/com/yahoo/vespa/hosted/controller/restapi/application/responses/dev-us-west-1.json create mode 100644 controller-server/src/test/java/com/yahoo/vespa/hosted/controller/restapi/application/responses/prod-corp-us-east-1.json delete mode 100644 controller-server/src/test/java/com/yahoo/vespa/hosted/controller/restapi/application/responses/recursive-application.json delete mode 100644 controller-server/src/test/java/com/yahoo/vespa/hosted/controller/restapi/application/responses/recursive-tenant.json create mode 100644 controller-server/src/test/java/com/yahoo/vespa/hosted/controller/restapi/application/responses/tenant1.json (limited to 'controller-server') 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 fc145a92b5d..1bb116809f7 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 @@ -225,11 +225,8 @@ public class ApplicationApiHandler extends LoggingRequestHandler { private HttpResponse recursiveRoot(HttpRequest request) { Slime slime = new Slime(); Cursor tenantArray = slime.setArray(); - for (Tenant tenant : controller.tenants().asList()) { - Cursor tenantObject = tenantArray.addObject(); - tenantObject.setString("tenant", tenant.getId().id()); - toSlime(tenantObject, tenant, request, true); - } + for (Tenant tenant : controller.tenants().asList()) + toSlime(tenantArray.addObject(), tenant, request, true); return new SlimeJsonResponse(slime); } @@ -347,6 +344,8 @@ public class ApplicationApiHandler extends LoggingRequestHandler { } private void toSlime(Cursor object, Application application, HttpRequest request) { + object.setString("application", application.id().application().value()); + object.setString("instance", application.id().instance().value()); // Currently deploying change if (application.deploying().isPresent()) { Cursor deployingObject = object.setObject("deploying"); @@ -882,6 +881,7 @@ public class ApplicationApiHandler extends LoggingRequestHandler { } private void toSlime(Cursor object, Tenant tenant, HttpRequest request, boolean listApplications) { + object.setString("tenant", tenant.getId().id()); object.setString("type", tenant.tenantType().name()); tenant.getAthensDomain().ifPresent(a -> object.setString("athensDomain", a.id())); tenant.getProperty().ifPresent(p -> object.setString("property", p.id())); @@ -890,8 +890,12 @@ public class ApplicationApiHandler extends LoggingRequestHandler { Cursor applicationArray = object.setArray("applications"); if (listApplications) { // This cludge is needed because we call this after deleting the tenant. As this call makes another tenant lookup it will fail. TODO is to support lookup on tenant for (Application application : controller.applications().asList(TenantName.from(tenant.getId().id()))) { - if (application.id().instance().isDefault()) // TODO: Skip non-default applications until supported properly - toSlime(application, applicationArray.addObject(), request); + if (application.id().instance().isDefault()) {// TODO: Skip non-default applications until supported properly + if (request.getBooleanProperty("recursive")) + toSlime(applicationArray.addObject(), application, request); + else + toSlime(application, applicationArray.addObject(), request); + } } } tenant.getPropertyId().ifPresent(propertyId -> { @@ -1015,11 +1019,8 @@ public class ApplicationApiHandler extends LoggingRequestHandler { private void toSlime(Application application, Cursor object, HttpRequest request) { object.setString("application", application.id().application().value()); object.setString("instance", application.id().instance().value()); - if (request.getBooleanProperty("recursive")) - toSlime(object, application, request); - else - object.setString("url", withPath("/application/v4/tenant/" + application.id().tenant().value() + - "/application/" + application.id().application().value(), request.getUri()).toString()); + object.setString("url", withPath("/application/v4/tenant/" + application.id().tenant().value() + + "/application/" + application.id().application().value(), request.getUri()).toString()); } private Slime toSlime(ActivateResult result, long applicationZipSizeBytes) { 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 365f73ef2cd..ae3738dfd71 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 @@ -227,13 +227,13 @@ public class ApplicationApiTest extends ControllerContainerTest { "", Request.Method.GET, "domain1", "mytenant&recursive=true"), - new File("recursive-tenant.json")); + new File("tenant1.json")); // GET at an application, with "&recursive=true", returns full info about its deployments tester.assertResponse(request("/application/v4/tenant/tenant1/application/application1/", "", Request.Method.GET, "domain1", "mytenant&recursive=true"), - new File("recursive-application.json")); + new File("application1.json")); // POST a 'restart application' command diff --git a/controller-server/src/test/java/com/yahoo/vespa/hosted/controller/restapi/application/responses/application-without-change-multiple-deployments.json b/controller-server/src/test/java/com/yahoo/vespa/hosted/controller/restapi/application/responses/application-without-change-multiple-deployments.json index a1bcc3eeb67..a4ce68f93fe 100644 --- a/controller-server/src/test/java/com/yahoo/vespa/hosted/controller/restapi/application/responses/application-without-change-multiple-deployments.json +++ b/controller-server/src/test/java/com/yahoo/vespa/hosted/controller/restapi/application/responses/application-without-change-multiple-deployments.json @@ -1,4 +1,5 @@ { + "application": "application1", "deploymentJobs": [ { "type": "component", diff --git a/controller-server/src/test/java/com/yahoo/vespa/hosted/controller/restapi/application/responses/application.json b/controller-server/src/test/java/com/yahoo/vespa/hosted/controller/restapi/application/responses/application.json index f399d6c9188..fdd3dcc4d5c 100644 --- a/controller-server/src/test/java/com/yahoo/vespa/hosted/controller/restapi/application/responses/application.json +++ b/controller-server/src/test/java/com/yahoo/vespa/hosted/controller/restapi/application/responses/application.json @@ -1,4 +1,6 @@ { + "application": "application1", + "instance": "default", "deploying": { "version": "(ignore)" }, diff --git a/controller-server/src/test/java/com/yahoo/vespa/hosted/controller/restapi/application/responses/application1.json b/controller-server/src/test/java/com/yahoo/vespa/hosted/controller/restapi/application/responses/application1.json new file mode 100644 index 00000000000..3ebb870d75b --- /dev/null +++ b/controller-server/src/test/java/com/yahoo/vespa/hosted/controller/restapi/application/responses/application1.json @@ -0,0 +1,159 @@ +{ + "application": "application1", + "instance": "default", + "deploying": { + "version": "6.1" + }, + "deploymentJobs": [ + { + "type": "system-test", + "success": true, + "lastTriggered": { + "id": -1, + "version": "6.1.0", + "revision": { + "hash": "(ignore)", + "source": { + "gitRepository": "repository1", + "gitBranch": "master", + "gitCommit": "commit1" + } + }, + "reason": "", + "at": "(ignore)" + }, + "lastCompleted": { + "id": 42, + "version": "6.1.0", + "revision": { + "hash": "(ignore)", + "source": { + "gitRepository": "repository1", + "gitBranch": "master", + "gitCommit": "commit1" + } + }, + "reason": "", + "at": "(ignore)" + }, + "lastSuccess": { + "id": 42, + "version": "6.1.0", + "revision": { + "hash": "(ignore)", + "source": { + "gitRepository": "repository1", + "gitBranch": "master", + "gitCommit": "commit1" + } + }, + "reason": "", + "at": "(ignore)" + } + }, + { + "type": "staging-test", + "success": true, + "lastTriggered": { + "id": -1, + "version": "6.1.0", + "revision": { + "hash": "(ignore)", + "source": { + "gitRepository": "repository1", + "gitBranch": "master", + "gitCommit": "commit1" + } + }, + "reason": "system-test completed", + "at": "(ignore)" + }, + "lastCompleted": { + "id": 42, + "version": "6.1.0", + "revision": { + "hash": "(ignore)", + "source": { + "gitRepository": "repository1", + "gitBranch": "master", + "gitCommit": "commit1" + } + }, + "reason": "system-test completed", + "at": "(ignore)" + }, + "lastSuccess": { + "id": 42, + "version": "6.1.0", + "revision": { + "hash": "(ignore)", + "source": { + "gitRepository": "repository1", + "gitBranch": "master", + "gitCommit": "commit1" + } + }, + "reason": "system-test completed", + "at": "(ignore)" + } + }, + { + "type": "production-corp-us-east-1", + "success": false, + "lastTriggered": { + "id": -1, + "version": "6.1.0", + "revision": { + "hash": "(ignore)", + "source": { + "gitRepository": "repository1", + "gitBranch": "master", + "gitCommit": "commit1" + } + }, + "reason": "Immediate retry on failure", + "at": "(ignore)" + }, + "lastCompleted": { + "id": 42, + "version": "6.1.0", + "revision": { + "hash": "(ignore)", + "source": { + "gitRepository": "repository1", + "gitBranch": "master", + "gitCommit": "commit1" + } + }, + "reason": "staging-test completed", + "at": "(ignore)" + }, + "firstFailing": { + "id": 42, + "version": "6.1.0", + "revision": { + "hash": "(ignore)", + "source": { + "gitRepository": "repository1", + "gitBranch": "master", + "gitCommit": "commit1" + } + }, + "reason": "staging-test completed", + "at": "(ignore)" + } + } + ], + "compileVersion": "6.1.0", + "globalRotations": [ + "http://fake-global-rotation-tenant1.application1" + ], + "instances": [ + @include(dev-us-west-1.json), + @include(prod-corp-us-east-1.json) + ], + "metrics": { + "queryServiceQuality": 0.5, + "writeServiceQuality": 0.7 + } +} diff --git a/controller-server/src/test/java/com/yahoo/vespa/hosted/controller/restapi/application/responses/dev-us-west-1.json b/controller-server/src/test/java/com/yahoo/vespa/hosted/controller/restapi/application/responses/dev-us-west-1.json new file mode 100644 index 00000000000..de40861739a --- /dev/null +++ b/controller-server/src/test/java/com/yahoo/vespa/hosted/controller/restapi/application/responses/dev-us-west-1.json @@ -0,0 +1,31 @@ +{ + "environment": "dev", + "region": "us-west-1", + "instance": "default", + "serviceUrls": [ + "http://old-endpoint.vespa.yahooapis.com:4080", + "http://qrs-endpoint.vespa.yahooapis.com:4080", + "http://feeding-endpoint.vespa.yahooapis.com:4080", + "http://global-endpoint.vespa.yahooapis.com:4080", + "http://alias-endpoint.vespa.yahooapis.com:4080" + ], + "nodes": "http://localhost:8080/zone/v2/dev/us-west-1/nodes/v2/node/%3F&recursive=true&application=tenant1.application1.default", + "yamasUrl": "http://monitoring-system.test/?environment=dev®ion=us-west-1&application=tenant1.application1", + "version": "6.1.0", + "revision": "(ignore)", + "deployTimeEpochMs": "(ignore)", + "screwdriverId": "123", + "cost": { + "tco": 0, + "waste": 0, + "utilization": 0.0, + "cluster": {} + }, + "metrics": { + "queriesPerSecond": 0.0, + "writesPerSecond": 0.0, + "documentCount": 0.0, + "queryLatencyMillis": 0.0, + "writeLatencyMillis": 0.0 + } +} \ No newline at end of file diff --git a/controller-server/src/test/java/com/yahoo/vespa/hosted/controller/restapi/application/responses/opsdb-tenant-with-id-without-applications.json b/controller-server/src/test/java/com/yahoo/vespa/hosted/controller/restapi/application/responses/opsdb-tenant-with-id-without-applications.json index 8acb4a045f3..a2e70d9c1eb 100644 --- a/controller-server/src/test/java/com/yahoo/vespa/hosted/controller/restapi/application/responses/opsdb-tenant-with-id-without-applications.json +++ b/controller-server/src/test/java/com/yahoo/vespa/hosted/controller/restapi/application/responses/opsdb-tenant-with-id-without-applications.json @@ -1,4 +1,5 @@ { + "tenant": "tenant3", "type": "OPSDB", "property": "property1", "propertyId": "1234", diff --git a/controller-server/src/test/java/com/yahoo/vespa/hosted/controller/restapi/application/responses/opsdb-tenant-with-new-id-without-applications.json b/controller-server/src/test/java/com/yahoo/vespa/hosted/controller/restapi/application/responses/opsdb-tenant-with-new-id-without-applications.json index 3f4b6017971..f9161ea49b1 100644 --- a/controller-server/src/test/java/com/yahoo/vespa/hosted/controller/restapi/application/responses/opsdb-tenant-with-new-id-without-applications.json +++ b/controller-server/src/test/java/com/yahoo/vespa/hosted/controller/restapi/application/responses/opsdb-tenant-with-new-id-without-applications.json @@ -1,4 +1,5 @@ { + "tenant": "tenant3", "type": "OPSDB", "property": "property2", "propertyId": "4321", diff --git a/controller-server/src/test/java/com/yahoo/vespa/hosted/controller/restapi/application/responses/prod-corp-us-east-1.json b/controller-server/src/test/java/com/yahoo/vespa/hosted/controller/restapi/application/responses/prod-corp-us-east-1.json new file mode 100644 index 00000000000..75b257da0ed --- /dev/null +++ b/controller-server/src/test/java/com/yahoo/vespa/hosted/controller/restapi/application/responses/prod-corp-us-east-1.json @@ -0,0 +1,68 @@ +{ + "environment": "prod", + "region": "corp-us-east-1", + "instance": "default", + "bcpStatus": { + "rotationStatus": "UNKNOWN" + }, + "serviceUrls": [ + "http://old-endpoint.vespa.yahooapis.com:4080", + "http://qrs-endpoint.vespa.yahooapis.com:4080", + "http://feeding-endpoint.vespa.yahooapis.com:4080", + "http://global-endpoint.vespa.yahooapis.com:4080", + "http://alias-endpoint.vespa.yahooapis.com:4080" + ], + "nodes": "http://localhost:8080/zone/v2/prod/corp-us-east-1/nodes/v2/node/%3F&recursive=true&application=tenant1.application1.default", + "elkUrl": "http://log.prod.corp-us-east-1.test/#/discover?_g=()&_a=(columns:!(_source),index:'logstash-*',interval:auto,query:(query_string:(analyze_wildcard:!t,query:'HV-tenant:%22tenant1%22%20AND%20HV-application:%22application1%22%20AND%20HV-region:%22corp-us-east-1%22%20AND%20HV-instance:%22default%22%20AND%20HV-environment:%22prod%22')),sort:!('@timestamp',desc))", + "yamasUrl": "http://monitoring-system.test/?environment=prod®ion=corp-us-east-1&application=tenant1.application1", + "version": "6.1.0", + "revision": "(ignore)", + "deployTimeEpochMs": "(ignore)", + "screwdriverId": "123", + "gitRepository": "repository1", + "gitBranch": "master", + "gitCommit": "commit1", + "cost": { + "tco": 74, + "waste": 0, + "utilization": 2.999999999999999, + "cluster": { + "cluster1": { + "count": 2, + "resource": "cpu", + "utilization": 2.999999999999999, + "tco": 74, + "waste": 0, + "flavor": "flavor1", + "flavorCost": 37.0, + "flavorCpu": 2.0, + "flavorMem": 4.0, + "flavorDisk": 50.0, + "type": "content", + "util": { + "cpu": 2.999999999999999, + "mem": 0.4285714285714286, + "disk": 0.5714285714285715, + "diskBusy": 1.0 + }, + "usage": { + "cpu": 0.6, + "mem": 0.3, + "disk": 0.4, + "diskBusy": 0.3 + }, + "hostnames": [ + "host1", + "host2" + ] + } + } + }, + "metrics": { + "queriesPerSecond": 1.0, + "writesPerSecond": 2.0, + "documentCount": 3.0, + "queryLatencyMillis": 4.0, + "writeLatencyMillis": 5.0 + } +} diff --git a/controller-server/src/test/java/com/yahoo/vespa/hosted/controller/restapi/application/responses/recursive-application.json b/controller-server/src/test/java/com/yahoo/vespa/hosted/controller/restapi/application/responses/recursive-application.json deleted file mode 100644 index ee0b7bfa906..00000000000 --- a/controller-server/src/test/java/com/yahoo/vespa/hosted/controller/restapi/application/responses/recursive-application.json +++ /dev/null @@ -1,254 +0,0 @@ -{ - "deploying": { - "version": "6.1" - }, - "deploymentJobs": [ - { - "type": "system-test", - "success": true, - "lastTriggered": { - "id": -1, - "version": "6.1.0", - "revision": { - "hash": "(ignore)", - "source": { - "gitRepository": "repository1", - "gitBranch": "master", - "gitCommit": "commit1" - } - }, - "reason": "", - "at": "(ignore)" - }, - "lastCompleted": { - "id": 42, - "version": "6.1.0", - "revision": { - "hash": "(ignore)", - "source": { - "gitRepository": "repository1", - "gitBranch": "master", - "gitCommit": "commit1" - } - }, - "reason": "", - "at": "(ignore)" - }, - "lastSuccess": { - "id": 42, - "version": "6.1.0", - "revision": { - "hash": "(ignore)", - "source": { - "gitRepository": "repository1", - "gitBranch": "master", - "gitCommit": "commit1" - } - }, - "reason": "", - "at": "(ignore)" - } - }, - { - "type": "staging-test", - "success": true, - "lastTriggered": { - "id": -1, - "version": "6.1.0", - "revision": { - "hash": "(ignore)", - "source": { - "gitRepository": "repository1", - "gitBranch": "master", - "gitCommit": "commit1" - } - }, - "reason": "system-test completed", - "at": "(ignore)" - }, - "lastCompleted": { - "id": 42, - "version": "6.1.0", - "revision": { - "hash": "(ignore)", - "source": { - "gitRepository": "repository1", - "gitBranch": "master", - "gitCommit": "commit1" - } - }, - "reason": "system-test completed", - "at": "(ignore)" - }, - "lastSuccess": { - "id": 42, - "version": "6.1.0", - "revision": { - "hash": "(ignore)", - "source": { - "gitRepository": "repository1", - "gitBranch": "master", - "gitCommit": "commit1" - } - }, - "reason": "system-test completed", - "at": "(ignore)" - } - }, - { - "type": "production-corp-us-east-1", - "success": false, - "lastTriggered": { - "id": -1, - "version": "6.1.0", - "revision": { - "hash": "(ignore)", - "source": { - "gitRepository": "repository1", - "gitBranch": "master", - "gitCommit": "commit1" - } - }, - "reason": "Immediate retry on failure", - "at": "(ignore)" - }, - "lastCompleted": { - "id": 42, - "version": "6.1.0", - "revision": { - "hash": "(ignore)", - "source": { - "gitRepository": "repository1", - "gitBranch": "master", - "gitCommit": "commit1" - } - }, - "reason": "staging-test completed", - "at": "(ignore)" - }, - "firstFailing": { - "id": 42, - "version": "6.1.0", - "revision": { - "hash": "(ignore)", - "source": { - "gitRepository": "repository1", - "gitBranch": "master", - "gitCommit": "commit1" - } - }, - "reason": "staging-test completed", - "at": "(ignore)" - } - } - ], - "compileVersion": "6.1.0", - "globalRotations": [ - "http://fake-global-rotation-tenant1.application1" - ], - "instances": [ - { - "environment": "dev", - "region": "us-west-1", - "instance": "default", - "serviceUrls": [ - "http://old-endpoint.vespa.yahooapis.com:4080", - "http://qrs-endpoint.vespa.yahooapis.com:4080", - "http://feeding-endpoint.vespa.yahooapis.com:4080", - "http://global-endpoint.vespa.yahooapis.com:4080", - "http://alias-endpoint.vespa.yahooapis.com:4080" - ], - "nodes": "http://localhost:8080/zone/v2/dev/us-west-1/nodes/v2/node/%3F&recursive=true&application=tenant1.application1.default", - "yamasUrl": "http://monitoring-system.test/?environment=dev®ion=us-west-1&application=tenant1.application1", - "version": "6.1.0", - "revision": "(ignore)", - "deployTimeEpochMs": "(ignore)", - "screwdriverId": "123", - "cost": { - "tco": 0, - "waste": 0, - "utilization": 0.0, - "cluster": {} - }, - "metrics": { - "queriesPerSecond": 0.0, - "writesPerSecond": 0.0, - "documentCount": 0.0, - "queryLatencyMillis": 0.0, - "writeLatencyMillis": 0.0 - } - }, - { - "environment": "prod", - "region": "corp-us-east-1", - "instance": "default", - "bcpStatus": { - "rotationStatus": "UNKNOWN" - }, - "serviceUrls": [ - "http://old-endpoint.vespa.yahooapis.com:4080", - "http://qrs-endpoint.vespa.yahooapis.com:4080", - "http://feeding-endpoint.vespa.yahooapis.com:4080", - "http://global-endpoint.vespa.yahooapis.com:4080", - "http://alias-endpoint.vespa.yahooapis.com:4080" - ], - "nodes": "http://localhost:8080/zone/v2/prod/corp-us-east-1/nodes/v2/node/%3F&recursive=true&application=tenant1.application1.default", - "elkUrl": "http://log.prod.corp-us-east-1.test/#/discover?_g=()&_a=(columns:!(_source),index:'logstash-*',interval:auto,query:(query_string:(analyze_wildcard:!t,query:'HV-tenant:%22tenant1%22%20AND%20HV-application:%22application1%22%20AND%20HV-region:%22corp-us-east-1%22%20AND%20HV-instance:%22default%22%20AND%20HV-environment:%22prod%22')),sort:!('@timestamp',desc))", - "yamasUrl": "http://monitoring-system.test/?environment=prod®ion=corp-us-east-1&application=tenant1.application1", - "version": "6.1.0", - "revision": "(ignore)", - "deployTimeEpochMs": "(ignore)", - "screwdriverId": "123", - "gitRepository": "repository1", - "gitBranch": "master", - "gitCommit": "commit1", - "cost": { - "tco": 74, - "waste": 0, - "utilization": 2.999999999999999, - "cluster": { - "cluster1": { - "count": 2, - "resource": "cpu", - "utilization": 2.999999999999999, - "tco": 74, - "waste": 0, - "flavor": "flavor1", - "flavorCost": 37.0, - "flavorCpu": 2.0, - "flavorMem": 4.0, - "flavorDisk": 50.0, - "type": "content", - "util": { - "cpu": 2.999999999999999, - "mem": 0.4285714285714286, - "disk": 0.5714285714285715, - "diskBusy": 1.0 - }, - "usage": { - "cpu": 0.6, - "mem": 0.3, - "disk": 0.4, - "diskBusy": 0.3 - }, - "hostnames": [ - "host1", - "host2" - ] - } - } - }, - "metrics": { - "queriesPerSecond": 1.0, - "writesPerSecond": 2.0, - "documentCount": 3.0, - "queryLatencyMillis": 4.0, - "writeLatencyMillis": 5.0 - } - } - ], - "metrics": { - "queryServiceQuality": 0.5, - "writeServiceQuality": 0.7 - } -} diff --git a/controller-server/src/test/java/com/yahoo/vespa/hosted/controller/restapi/application/responses/recursive-root.json b/controller-server/src/test/java/com/yahoo/vespa/hosted/controller/restapi/application/responses/recursive-root.json index 71af7d4be44..5126ad8fa69 100644 --- a/controller-server/src/test/java/com/yahoo/vespa/hosted/controller/restapi/application/responses/recursive-root.json +++ b/controller-server/src/test/java/com/yahoo/vespa/hosted/controller/restapi/application/responses/recursive-root.json @@ -30,268 +30,5 @@ "issueCreationUrl": "www.issues.tld/4321", "contacts": [] }, - { - "tenant": "tenant1", - "type": "ATHENS", - "athensDomain": "domain1", - "property": "property1", - "applications": [ - { - "application": "application1", - "instance": "default", - "deploying": { - "version": "6.1" - }, - "deploymentJobs": [ - { - "type": "system-test", - "success": true, - "lastTriggered": { - "id": -1, - "version": "6.1.0", - "revision": { - "hash": "(ignore)", - "source": { - "gitRepository": "repository1", - "gitBranch": "master", - "gitCommit": "commit1" - } - }, - "reason": "", - "at": "(ignore)" - }, - "lastCompleted": { - "id": 42, - "version": "6.1.0", - "revision": { - "hash": "(ignore)", - "source": { - "gitRepository": "repository1", - "gitBranch": "master", - "gitCommit": "commit1" - } - }, - "reason": "", - "at": "(ignore)" - }, - "lastSuccess": { - "id": 42, - "version": "6.1.0", - "revision": { - "hash": "(ignore)", - "source": { - "gitRepository": "repository1", - "gitBranch": "master", - "gitCommit": "commit1" - } - }, - "reason": "", - "at": "(ignore)" - } - }, - { - "type": "staging-test", - "success": true, - "lastTriggered": { - "id": -1, - "version": "6.1.0", - "revision": { - "hash": "(ignore)", - "source": { - "gitRepository": "repository1", - "gitBranch": "master", - "gitCommit": "commit1" - } - }, - "reason": "system-test completed", - "at": "(ignore)" - }, - "lastCompleted": { - "id": 42, - "version": "6.1.0", - "revision": { - "hash": "(ignore)", - "source": { - "gitRepository": "repository1", - "gitBranch": "master", - "gitCommit": "commit1" - } - }, - "reason": "system-test completed", - "at": "(ignore)" - }, - "lastSuccess": { - "id": 42, - "version": "6.1.0", - "revision": { - "hash": "(ignore)", - "source": { - "gitRepository": "repository1", - "gitBranch": "master", - "gitCommit": "commit1" - } - }, - "reason": "system-test completed", - "at": "(ignore)" - } - }, - { - "type": "production-corp-us-east-1", - "success": false, - "lastTriggered": { - "id": -1, - "version": "6.1.0", - "revision": { - "hash": "(ignore)", - "source": { - "gitRepository": "repository1", - "gitBranch": "master", - "gitCommit": "commit1" - } - }, - "reason": "Immediate retry on failure", - "at": "(ignore)" - }, - "lastCompleted": { - "id": 42, - "version": "6.1.0", - "revision": { - "hash": "(ignore)", - "source": { - "gitRepository": "repository1", - "gitBranch": "master", - "gitCommit": "commit1" - } - }, - "reason": "staging-test completed", - "at": "(ignore)" - }, - "firstFailing": { - "id": 42, - "version": "6.1.0", - "revision": { - "hash": "(ignore)", - "source": { - "gitRepository": "repository1", - "gitBranch": "master", - "gitCommit": "commit1" - } - }, - "reason": "staging-test completed", - "at": "(ignore)" - } - } - ], - "compileVersion": "6.1.0", - "globalRotations": [ - "http://fake-global-rotation-tenant1.application1" - ], - "instances": [ - { - "environment": "dev", - "region": "us-west-1", - "instance": "default", - "serviceUrls": [ - "http://old-endpoint.vespa.yahooapis.com:4080", - "http://qrs-endpoint.vespa.yahooapis.com:4080", - "http://feeding-endpoint.vespa.yahooapis.com:4080", - "http://global-endpoint.vespa.yahooapis.com:4080", - "http://alias-endpoint.vespa.yahooapis.com:4080" - ], - "nodes": "http://localhost:8080/zone/v2/dev/us-west-1/nodes/v2/node/%3F&recursive=true&application=tenant1.application1.default", - "yamasUrl": "http://monitoring-system.test/?environment=dev®ion=us-west-1&application=tenant1.application1", - "version": "6.1.0", - "revision": "(ignore)", - "deployTimeEpochMs": "(ignore)", - "screwdriverId": "123", - "cost": { - "tco": 0, - "waste": 0, - "utilization": 0.0, - "cluster": {} - }, - "metrics": { - "queriesPerSecond": 0.0, - "writesPerSecond": 0.0, - "documentCount": 0.0, - "queryLatencyMillis": 0.0, - "writeLatencyMillis": 0.0 - } - }, - { - "environment": "prod", - "region": "corp-us-east-1", - "instance": "default", - "bcpStatus": { - "rotationStatus": "UNKNOWN" - }, - "serviceUrls": [ - "http://old-endpoint.vespa.yahooapis.com:4080", - "http://qrs-endpoint.vespa.yahooapis.com:4080", - "http://feeding-endpoint.vespa.yahooapis.com:4080", - "http://global-endpoint.vespa.yahooapis.com:4080", - "http://alias-endpoint.vespa.yahooapis.com:4080" - ], - "nodes": "http://localhost:8080/zone/v2/prod/corp-us-east-1/nodes/v2/node/%3F&recursive=true&application=tenant1.application1.default", - "elkUrl": "http://log.prod.corp-us-east-1.test/#/discover?_g=()&_a=(columns:!(_source),index:'logstash-*',interval:auto,query:(query_string:(analyze_wildcard:!t,query:'HV-tenant:%22tenant1%22%20AND%20HV-application:%22application1%22%20AND%20HV-region:%22corp-us-east-1%22%20AND%20HV-instance:%22default%22%20AND%20HV-environment:%22prod%22')),sort:!('@timestamp',desc))", - "yamasUrl": "http://monitoring-system.test/?environment=prod®ion=corp-us-east-1&application=tenant1.application1", - "version": "6.1.0", - "revision": "(ignore)", - "deployTimeEpochMs": "(ignore)", - "screwdriverId": "123", - "gitRepository": "repository1", - "gitBranch": "master", - "gitCommit": "commit1", - "cost": { - "tco": 74, - "waste": 0, - "utilization": 2.999999999999999, - "cluster": { - "cluster1": { - "count": 2, - "resource": "cpu", - "utilization": 2.999999999999999, - "tco": 74, - "waste": 0, - "flavor": "flavor1", - "flavorCost": 37.0, - "flavorCpu": 2.0, - "flavorMem": 4.0, - "flavorDisk": 50.0, - "type": "content", - "util": { - "cpu": 2.999999999999999, - "mem": 0.4285714285714286, - "disk": 0.5714285714285715, - "diskBusy": 1.0 - }, - "usage": { - "cpu": 0.6, - "mem": 0.3, - "disk": 0.4, - "diskBusy": 0.3 - }, - "hostnames": [ - "host1", - "host2" - ] - } - } - }, - "metrics": { - "queriesPerSecond": 1.0, - "writesPerSecond": 2.0, - "documentCount": 3.0, - "queryLatencyMillis": 4.0, - "writeLatencyMillis": 5.0 - } - } - ], - "metrics": { - "queryServiceQuality": 0.5, - "writeServiceQuality": 0.7 - } - } - ] - } + @include(tenant1.json) ] diff --git a/controller-server/src/test/java/com/yahoo/vespa/hosted/controller/restapi/application/responses/recursive-tenant.json b/controller-server/src/test/java/com/yahoo/vespa/hosted/controller/restapi/application/responses/recursive-tenant.json deleted file mode 100644 index e05b05ed1a7..00000000000 --- a/controller-server/src/test/java/com/yahoo/vespa/hosted/controller/restapi/application/responses/recursive-tenant.json +++ /dev/null @@ -1,263 +0,0 @@ -{ - "type": "ATHENS", - "athensDomain": "domain1", - "property": "property1", - "applications": [ - { - "application": "application1", - "instance": "default", - "deploying": { - "version": "6.1" - }, - "deploymentJobs": [ - { - "type": "system-test", - "success": true, - "lastTriggered": { - "id": -1, - "version": "6.1.0", - "revision": { - "hash": "(ignore)", - "source": { - "gitRepository": "repository1", - "gitBranch": "master", - "gitCommit": "commit1" - } - }, - "reason": "", - "at": "(ignore)" - }, - "lastCompleted": { - "id": 42, - "version": "6.1.0", - "revision": { - "hash": "(ignore)", - "source": { - "gitRepository": "repository1", - "gitBranch": "master", - "gitCommit": "commit1" - } - }, - "reason": "", - "at": "(ignore)" - }, - "lastSuccess": { - "id": 42, - "version": "6.1.0", - "revision": { - "hash": "(ignore)", - "source": { - "gitRepository": "repository1", - "gitBranch": "master", - "gitCommit": "commit1" - } - }, - "reason": "", - "at": "(ignore)" - } - }, - { - "type": "staging-test", - "success": true, - "lastTriggered": { - "id": -1, - "version": "6.1.0", - "revision": { - "hash": "(ignore)", - "source": { - "gitRepository": "repository1", - "gitBranch": "master", - "gitCommit": "commit1" - } - }, - "reason": "system-test completed", - "at": "(ignore)" - }, - "lastCompleted": { - "id": 42, - "version": "6.1.0", - "revision": { - "hash": "(ignore)", - "source": { - "gitRepository": "repository1", - "gitBranch": "master", - "gitCommit": "commit1" - } - }, - "reason": "system-test completed", - "at": "(ignore)" - }, - "lastSuccess": { - "id": 42, - "version": "6.1.0", - "revision": { - "hash": "(ignore)", - "source": { - "gitRepository": "repository1", - "gitBranch": "master", - "gitCommit": "commit1" - } - }, - "reason": "system-test completed", - "at": "(ignore)" - } - }, - { - "type": "production-corp-us-east-1", - "success": false, - "lastTriggered": { - "id": -1, - "version": "6.1.0", - "revision": { - "hash": "(ignore)", - "source": { - "gitRepository": "repository1", - "gitBranch": "master", - "gitCommit": "commit1" - } - }, - "reason": "Immediate retry on failure", - "at": "(ignore)" - }, - "lastCompleted": { - "id": 42, - "version": "6.1.0", - "revision": { - "hash": "(ignore)", - "source": { - "gitRepository": "repository1", - "gitBranch": "master", - "gitCommit": "commit1" - } - }, - "reason": "staging-test completed", - "at": "(ignore)" - }, - "firstFailing": { - "id": 42, - "version": "6.1.0", - "revision": { - "hash": "(ignore)", - "source": { - "gitRepository": "repository1", - "gitBranch": "master", - "gitCommit": "commit1" - } - }, - "reason": "staging-test completed", - "at": "(ignore)" - } - } - ], - "compileVersion": "6.1.0", - "globalRotations": [ - "http://fake-global-rotation-tenant1.application1" - ], - "instances": [ - { - "environment": "dev", - "region": "us-west-1", - "instance": "default", - "serviceUrls": [ - "http://old-endpoint.vespa.yahooapis.com:4080", - "http://qrs-endpoint.vespa.yahooapis.com:4080", - "http://feeding-endpoint.vespa.yahooapis.com:4080", - "http://global-endpoint.vespa.yahooapis.com:4080", - "http://alias-endpoint.vespa.yahooapis.com:4080" - ], - "nodes": "http://localhost:8080/zone/v2/dev/us-west-1/nodes/v2/node/%3F&recursive=true&application=tenant1.application1.default", - "yamasUrl": "http://monitoring-system.test/?environment=dev®ion=us-west-1&application=tenant1.application1", - "version": "6.1.0", - "revision": "(ignore)", - "deployTimeEpochMs": "(ignore)", - "screwdriverId": "123", - "cost": { - "tco": 0, - "waste": 0, - "utilization": 0.0, - "cluster": {} - }, - "metrics": { - "queriesPerSecond": 0.0, - "writesPerSecond": 0.0, - "documentCount": 0.0, - "queryLatencyMillis": 0.0, - "writeLatencyMillis": 0.0 - } - }, - { - "environment": "prod", - "region": "corp-us-east-1", - "instance": "default", - "bcpStatus": { - "rotationStatus": "UNKNOWN" - }, - "serviceUrls": [ - "http://old-endpoint.vespa.yahooapis.com:4080", - "http://qrs-endpoint.vespa.yahooapis.com:4080", - "http://feeding-endpoint.vespa.yahooapis.com:4080", - "http://global-endpoint.vespa.yahooapis.com:4080", - "http://alias-endpoint.vespa.yahooapis.com:4080" - ], - "nodes": "http://localhost:8080/zone/v2/prod/corp-us-east-1/nodes/v2/node/%3F&recursive=true&application=tenant1.application1.default", - "elkUrl": "http://log.prod.corp-us-east-1.test/#/discover?_g=()&_a=(columns:!(_source),index:'logstash-*',interval:auto,query:(query_string:(analyze_wildcard:!t,query:'HV-tenant:%22tenant1%22%20AND%20HV-application:%22application1%22%20AND%20HV-region:%22corp-us-east-1%22%20AND%20HV-instance:%22default%22%20AND%20HV-environment:%22prod%22')),sort:!('@timestamp',desc))", - "yamasUrl": "http://monitoring-system.test/?environment=prod®ion=corp-us-east-1&application=tenant1.application1", - "version": "6.1.0", - "revision": "(ignore)", - "deployTimeEpochMs": "(ignore)", - "screwdriverId": "123", - "gitRepository": "repository1", - "gitBranch": "master", - "gitCommit": "commit1", - "cost": { - "tco": 74, - "waste": 0, - "utilization": 2.999999999999999, - "cluster": { - "cluster1": { - "count": 2, - "resource": "cpu", - "utilization": 2.999999999999999, - "tco": 74, - "waste": 0, - "flavor": "flavor1", - "flavorCost": 37.0, - "flavorCpu": 2.0, - "flavorMem": 4.0, - "flavorDisk": 50.0, - "type": "content", - "util": { - "cpu": 2.999999999999999, - "mem": 0.4285714285714286, - "disk": 0.5714285714285715, - "diskBusy": 1.0 - }, - "usage": { - "cpu": 0.6, - "mem": 0.3, - "disk": 0.4, - "diskBusy": 0.3 - }, - "hostnames": [ - "host1", - "host2" - ] - } - } - }, - "metrics": { - "queriesPerSecond": 1.0, - "writesPerSecond": 2.0, - "documentCount": 3.0, - "queryLatencyMillis": 4.0, - "writeLatencyMillis": 5.0 - } - } - ], - "metrics": { - "queryServiceQuality": 0.5, - "writeServiceQuality": 0.7 - } - } - ] -} diff --git a/controller-server/src/test/java/com/yahoo/vespa/hosted/controller/restapi/application/responses/tenant-with-application.json b/controller-server/src/test/java/com/yahoo/vespa/hosted/controller/restapi/application/responses/tenant-with-application.json index 87901218c2e..ad8e65692b4 100644 --- a/controller-server/src/test/java/com/yahoo/vespa/hosted/controller/restapi/application/responses/tenant-with-application.json +++ b/controller-server/src/test/java/com/yahoo/vespa/hosted/controller/restapi/application/responses/tenant-with-application.json @@ -1,4 +1,5 @@ { + "tenant": "tenant1", "type": "ATHENS", "athensDomain": "domain1", "property": "property1", diff --git a/controller-server/src/test/java/com/yahoo/vespa/hosted/controller/restapi/application/responses/tenant-without-applications-with-id.json b/controller-server/src/test/java/com/yahoo/vespa/hosted/controller/restapi/application/responses/tenant-without-applications-with-id.json index ede2413218d..69949c47d8c 100644 --- a/controller-server/src/test/java/com/yahoo/vespa/hosted/controller/restapi/application/responses/tenant-without-applications-with-id.json +++ b/controller-server/src/test/java/com/yahoo/vespa/hosted/controller/restapi/application/responses/tenant-without-applications-with-id.json @@ -1,4 +1,5 @@ { + "tenant": "tenant2", "type": "ATHENS", "athensDomain": "domain2", "property": "property2", diff --git a/controller-server/src/test/java/com/yahoo/vespa/hosted/controller/restapi/application/responses/tenant-without-applications.json b/controller-server/src/test/java/com/yahoo/vespa/hosted/controller/restapi/application/responses/tenant-without-applications.json index 69669b5dfb8..3ad5a307348 100644 --- a/controller-server/src/test/java/com/yahoo/vespa/hosted/controller/restapi/application/responses/tenant-without-applications.json +++ b/controller-server/src/test/java/com/yahoo/vespa/hosted/controller/restapi/application/responses/tenant-without-applications.json @@ -1,4 +1,5 @@ { + "tenant": "tenant1", "type": "ATHENS", "athensDomain": "domain1", "property": "property1", diff --git a/controller-server/src/test/java/com/yahoo/vespa/hosted/controller/restapi/application/responses/tenant1.json b/controller-server/src/test/java/com/yahoo/vespa/hosted/controller/restapi/application/responses/tenant1.json new file mode 100644 index 00000000000..9f9d7642867 --- /dev/null +++ b/controller-server/src/test/java/com/yahoo/vespa/hosted/controller/restapi/application/responses/tenant1.json @@ -0,0 +1,9 @@ +{ + "tenant": "tenant1", + "type": "ATHENS", + "athensDomain": "domain1", + "property": "property1", + "applications": [ + @include(application1.json) + ] +} -- cgit v1.2.3 From a697ac0a9a3e744462c0ed9e5c6f3751f75b88f9 Mon Sep 17 00:00:00 2001 From: Jon Marius Venstad Date: Tue, 14 Nov 2017 14:29:44 +0100 Subject: Fixed more responses" --- .../vespa/hosted/controller/restapi/application/ApplicationApiTest.java | 2 +- .../responses/application-without-change-multiple-deployments.json | 1 + 2 files changed, 2 insertions(+), 1 deletion(-) (limited to 'controller-server') 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 ae3738dfd71..55742c5fec8 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 @@ -643,7 +643,7 @@ public class ApplicationApiTest extends ControllerContainerTest { "{\"athensDomain\":\"domain2\", \"property\":\"property1\"}", Request.Method.PUT, "domain1", authorizedUser), - "{\"type\":\"ATHENS\",\"athensDomain\":\"domain2\",\"property\":\"property1\",\"applications\":[]}", + "{\"tenant\":\"tenant1\",\"type\":\"ATHENS\",\"athensDomain\":\"domain2\",\"property\":\"property1\",\"applications\":[]}", 200); // Deleting a tenant for an Athens domain the user is not admin for is disallowed diff --git a/controller-server/src/test/java/com/yahoo/vespa/hosted/controller/restapi/application/responses/application-without-change-multiple-deployments.json b/controller-server/src/test/java/com/yahoo/vespa/hosted/controller/restapi/application/responses/application-without-change-multiple-deployments.json index a4ce68f93fe..6442ddf5c02 100644 --- a/controller-server/src/test/java/com/yahoo/vespa/hosted/controller/restapi/application/responses/application-without-change-multiple-deployments.json +++ b/controller-server/src/test/java/com/yahoo/vespa/hosted/controller/restapi/application/responses/application-without-change-multiple-deployments.json @@ -1,5 +1,6 @@ { "application": "application1", + "instance": "default", "deploymentJobs": [ { "type": "component", -- cgit v1.2.3 From b87b4d9b74c68caac9e073d1a223d81233e551f7 Mon Sep 17 00:00:00 2001 From: Jon Bratseth Date: Tue, 14 Nov 2017 15:25:58 +0100 Subject: Remove redundant logic - Add retry of failing first job to triggerReadyJobs - Remove triggerFailing as it is now covered by triggerReadyJobs - Rename BlockedChangeDeployer to ReadyJobsTrigger --- .../controller/deployment/DeploymentTrigger.java | 88 +++++----------------- .../maintenance/BlockedChangeDeployer.java | 28 ------- .../maintenance/ControllerMaintenance.java | 9 +-- .../controller/maintenance/FailureRedeployer.java | 35 --------- .../hosted/controller/maintenance/JobControl.java | 3 +- .../hosted/controller/maintenance/Maintainer.java | 2 + .../controller/maintenance/ReadyJobsTrigger.java | 28 +++++++ .../vespa/hosted/controller/ControllerTest.java | 2 +- .../controller/deployment/DeploymentTester.java | 10 +-- .../deployment/DeploymentTriggerTest.java | 24 +++--- .../maintenance/FailureRedeployerTest.java | 16 ++-- .../controller/maintenance/UpgraderTest.java | 20 ++--- .../restapi/controller/responses/maintenance.json | 21 +++--- 13 files changed, 98 insertions(+), 188 deletions(-) delete mode 100644 controller-server/src/main/java/com/yahoo/vespa/hosted/controller/maintenance/BlockedChangeDeployer.java delete mode 100644 controller-server/src/main/java/com/yahoo/vespa/hosted/controller/maintenance/FailureRedeployer.java create mode 100644 controller-server/src/main/java/com/yahoo/vespa/hosted/controller/maintenance/ReadyJobsTrigger.java (limited to 'controller-server') diff --git a/controller-server/src/main/java/com/yahoo/vespa/hosted/controller/deployment/DeploymentTrigger.java b/controller-server/src/main/java/com/yahoo/vespa/hosted/controller/deployment/DeploymentTrigger.java index 78dc01fef19..796437db3f8 100644 --- a/controller-server/src/main/java/com/yahoo/vespa/hosted/controller/deployment/DeploymentTrigger.java +++ b/controller-server/src/main/java/com/yahoo/vespa/hosted/controller/deployment/DeploymentTrigger.java @@ -145,15 +145,24 @@ public class DeploymentTrigger { List jobs = order.jobsFrom(application.deploymentSpec()); // Should the first step be triggered? - // TODO: How can the first job not be systemTest (second ccondition)? - if ( ! jobs.isEmpty() && jobs.get(0).equals(JobType.systemTest) && - application.deploying().get() instanceof Change.VersionChange) { - Version target = ((Change.VersionChange)application.deploying().get()).version(); - JobStatus jobStatus = application.deploymentJobs().jobStatus().get(JobType.systemTest); - if (jobStatus == null || ! jobStatus.lastTriggered().isPresent() - || ! jobStatus.lastTriggered().get().version().equals(target)) { - application = trigger(JobType.systemTest, application, false, "Upgrade to " + target); - controller.applications().store(application); + if ( ! jobs.isEmpty() && jobs.get(0).equals(JobType.systemTest) ) { + JobStatus systemTestStatus = application.deploymentJobs().jobStatus().get(JobType.systemTest); + if (application.deploying().get() instanceof Change.VersionChange) { + Version target = ((Change.VersionChange) application.deploying().get()).version(); + if (systemTestStatus == null + || ! systemTestStatus.lastTriggered().isPresent() + || ! systemTestStatus.isSuccess() + || ! systemTestStatus.lastTriggered().get().version().equals(target)) { + application = trigger(JobType.systemTest, application, false, "Upgrade to " + target); + controller.applications().store(application); + } + } + else { + JobStatus componentStatus = application.deploymentJobs().jobStatus().get(JobType.component); + if (changesAvailable(application, componentStatus, systemTestStatus)) { + application = trigger(JobType.systemTest, application, false, "Available change in component"); + controller.applications().store(application); + } } } @@ -207,35 +216,6 @@ public class DeploymentTrigger { return false; } - /** - * Called periodically to cause triggering of jobs in the background - */ - public void triggerFailing(ApplicationId applicationId) { - try (Lock lock = applications().lock(applicationId)) { - LockedApplication application = applications().require(applicationId, lock); - if ( ! application.deploying().isPresent()) return; // No ongoing change, no need to retry - - // Retry first failing job - for (JobType jobType : order.jobsFrom(application.deploymentSpec())) { - JobStatus jobStatus = application.deploymentJobs().jobStatus().get(jobType); - if (isFailing(application.deploying().get(), jobStatus)) { - if (shouldRetryNow(jobStatus)) { - application = trigger(jobType, application, false, "Retrying failing job"); - applications().store(application); - } - break; - } - } - - // Retry dead job - Optional firstDeadJob = firstDeadJob(application.deploymentJobs()); - if (firstDeadJob.isPresent()) { - application = trigger(firstDeadJob.get().type(), application, false, "Retrying dead job"); - applications().store(application); - } - } - } - /** Triggers jobs that have been delayed according to deployment spec */ public void triggerDelayed() { for (Application application : applications().asList()) { @@ -302,42 +282,10 @@ public class DeploymentTrigger { private ApplicationController applications() { return controller.applications(); } - /** Returns whether a job is failing for the current change in the given application */ - private boolean isFailing(Change change, JobStatus status) { - return status != null - && ! status.isSuccess() - && status.lastCompleted().isPresent() - && status.lastCompleted().get().lastCompletedWas(change); - } - private boolean isCapacityConstrained(JobType jobType) { return jobType == JobType.stagingTest || jobType == JobType.systemTest; } - /** Returns the first job that has been running for more than the given timeout */ - private Optional firstDeadJob(DeploymentJobs jobs) { - Optional oldestRunningJob = jobs.jobStatus().values().stream() - .filter(job -> job.isRunning(Instant.ofEpochMilli(0))) - .sorted(Comparator.comparing(status -> status.lastTriggered().get().at())) - .findFirst(); - return oldestRunningJob.filter(job -> job.lastTriggered().get().at().isBefore(jobTimeoutLimit())); - } - - /** Decide whether the job should be triggered by the periodic trigger */ - private boolean shouldRetryNow(JobStatus job) { - if (job.isSuccess()) return false; - if (job.isRunning(jobTimeoutLimit())) return false; - - // Retry after 10% of the time since it started failing - Duration aTenthOfFailTime = Duration.ofMillis( (clock.millis() - job.firstFailing().get().at().toEpochMilli()) / 10); - if (job.lastCompleted().get().at().isBefore(clock.instant().minus(aTenthOfFailTime))) return true; - - // ... or retry anyway if we haven't tried in 4 hours - if (job.lastCompleted().get().at().isBefore(clock.instant().minus(Duration.ofHours(4)))) return true; - - return false; - } - /** Retry immediately only if this job just started failing. Otherwise retry periodically */ private boolean shouldRetryNow(Application application, JobType jobType) { JobStatus jobStatus = application.deploymentJobs().jobStatus().get(jobType); diff --git a/controller-server/src/main/java/com/yahoo/vespa/hosted/controller/maintenance/BlockedChangeDeployer.java b/controller-server/src/main/java/com/yahoo/vespa/hosted/controller/maintenance/BlockedChangeDeployer.java deleted file mode 100644 index 4a68fd6cfab..00000000000 --- a/controller-server/src/main/java/com/yahoo/vespa/hosted/controller/maintenance/BlockedChangeDeployer.java +++ /dev/null @@ -1,28 +0,0 @@ -// Copyright 2017 Yahoo Holdings. 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.vespa.hosted.controller.Application; -import com.yahoo.vespa.hosted.controller.Controller; -import com.yahoo.vespa.hosted.controller.application.ApplicationList; -import com.yahoo.vespa.hosted.controller.application.Change; - -import java.time.Duration; - -/** - * Deploys application changes which have not made it to production because of a revision change block. - * - * @author bratseth - */ -@SuppressWarnings("unused") -public class BlockedChangeDeployer extends Maintainer { - - public BlockedChangeDeployer(Controller controller, Duration interval, JobControl jobControl) { - super(controller, interval, jobControl); - } - - @Override - protected void maintain() { - controller().applications().deploymentTrigger().triggerReadyJobs(); - } - -} diff --git a/controller-server/src/main/java/com/yahoo/vespa/hosted/controller/maintenance/ControllerMaintenance.java b/controller-server/src/main/java/com/yahoo/vespa/hosted/controller/maintenance/ControllerMaintenance.java index 2fdce2802ab..e29b25f9fb3 100644 --- a/controller-server/src/main/java/com/yahoo/vespa/hosted/controller/maintenance/ControllerMaintenance.java +++ b/controller-server/src/main/java/com/yahoo/vespa/hosted/controller/maintenance/ControllerMaintenance.java @@ -25,12 +25,11 @@ public class ControllerMaintenance extends AbstractComponent { private final DeploymentExpirer deploymentExpirer; private final DeploymentIssueReporter deploymentIssueReporter; private final MetricsReporter metricsReporter; - private final FailureRedeployer failureRedeployer; private final OutstandingChangeDeployer outstandingChangeDeployer; private final VersionStatusUpdater versionStatusUpdater; private final Upgrader upgrader; private final DelayedDeployer delayedDeployer; - private final BlockedChangeDeployer blockedChangeDeployer; + private final ReadyJobsTrigger readyJobsTrigger; private final ClusterInfoMaintainer clusterInfoMaintainer; private final ClusterUtilizationMaintainer clusterUtilizationMaintainer; private final DeploymentMetricsMaintainer deploymentMetricsMaintainer; @@ -44,12 +43,11 @@ public class ControllerMaintenance extends AbstractComponent { deploymentExpirer = new DeploymentExpirer(controller, maintenanceInterval, jobControl); deploymentIssueReporter = new DeploymentIssueReporter(controller, deploymentIssues, maintenanceInterval, jobControl); metricsReporter = new MetricsReporter(controller, metric, chefClient, jobControl, controller.system()); - failureRedeployer = new FailureRedeployer(controller, maintenanceInterval, jobControl); outstandingChangeDeployer = new OutstandingChangeDeployer(controller, maintenanceInterval, jobControl); versionStatusUpdater = new VersionStatusUpdater(controller, Duration.ofMinutes(3), jobControl); upgrader = new Upgrader(controller, maintenanceInterval, jobControl, curator); delayedDeployer = new DelayedDeployer(controller, maintenanceInterval, jobControl); - blockedChangeDeployer = new BlockedChangeDeployer(controller, maintenanceInterval, jobControl); + readyJobsTrigger = new ReadyJobsTrigger(controller, maintenanceInterval, jobControl); clusterInfoMaintainer = new ClusterInfoMaintainer(controller, Duration.ofHours(2), jobControl); clusterUtilizationMaintainer = new ClusterUtilizationMaintainer(controller, Duration.ofHours(2), jobControl); deploymentMetricsMaintainer = new DeploymentMetricsMaintainer(controller, Duration.ofMinutes(10), jobControl); @@ -65,12 +63,11 @@ public class ControllerMaintenance extends AbstractComponent { deploymentExpirer.deconstruct(); deploymentIssueReporter.deconstruct(); metricsReporter.deconstruct(); - failureRedeployer.deconstruct(); outstandingChangeDeployer.deconstruct(); versionStatusUpdater.deconstruct(); upgrader.deconstruct(); delayedDeployer.deconstruct(); - blockedChangeDeployer.deconstruct(); + readyJobsTrigger.deconstruct(); clusterUtilizationMaintainer.deconstruct(); clusterInfoMaintainer.deconstruct(); deploymentMetricsMaintainer.deconstruct(); diff --git a/controller-server/src/main/java/com/yahoo/vespa/hosted/controller/maintenance/FailureRedeployer.java b/controller-server/src/main/java/com/yahoo/vespa/hosted/controller/maintenance/FailureRedeployer.java deleted file mode 100644 index 72f8faa5180..00000000000 --- a/controller-server/src/main/java/com/yahoo/vespa/hosted/controller/maintenance/FailureRedeployer.java +++ /dev/null @@ -1,35 +0,0 @@ -// Copyright 2017 Yahoo Holdings. 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.vespa.hosted.controller.Application; -import com.yahoo.vespa.hosted.controller.Controller; -import com.yahoo.vespa.hosted.controller.application.ApplicationList; - -import java.time.Duration; -import java.util.List; - -/** - * Attempts redeployment of failed jobs and deployments. - * - * @author bratseth - * @author mpolden - */ -public class FailureRedeployer extends Maintainer { - - public FailureRedeployer(Controller controller, Duration interval, JobControl jobControl) { - super(controller, interval, jobControl); - } - - @Override - public void maintain() { - List applications = ApplicationList.from(controller().applications().asList()) - .notPullRequest() - .asList(); - applications.forEach(application -> triggerFailing(application)); - } - - private void triggerFailing(Application application) { - controller().applications().deploymentTrigger().triggerFailing(application.id()); - } - -} diff --git a/controller-server/src/main/java/com/yahoo/vespa/hosted/controller/maintenance/JobControl.java b/controller-server/src/main/java/com/yahoo/vespa/hosted/controller/maintenance/JobControl.java index d7396cb2acb..6aa1b89c605 100644 --- a/controller-server/src/main/java/com/yahoo/vespa/hosted/controller/maintenance/JobControl.java +++ b/controller-server/src/main/java/com/yahoo/vespa/hosted/controller/maintenance/JobControl.java @@ -5,6 +5,7 @@ import com.yahoo.vespa.curator.Lock; import com.yahoo.vespa.hosted.controller.persistence.CuratorDb; import java.util.HashSet; +import java.util.LinkedHashSet; import java.util.Set; import java.util.concurrent.ConcurrentSkipListSet; import java.util.logging.Logger; @@ -40,7 +41,7 @@ public class JobControl { * Returns a snapshot of the set of jobs started on this system (whether deactivated or not). * Each job is represented by its simple (omitting package) class name. */ - public Set jobs() { return new HashSet<>(startedJobs); } + public Set jobs() { return new LinkedHashSet<>(startedJobs); } /** Returns an unmodifiable set containing the currently inactive jobs in this */ public Set inactiveJobs() { return curator.readInactiveJobs(); } diff --git a/controller-server/src/main/java/com/yahoo/vespa/hosted/controller/maintenance/Maintainer.java b/controller-server/src/main/java/com/yahoo/vespa/hosted/controller/maintenance/Maintainer.java index bbef7980273..1d19d8ca522 100644 --- a/controller-server/src/main/java/com/yahoo/vespa/hosted/controller/maintenance/Maintainer.java +++ b/controller-server/src/main/java/com/yahoo/vespa/hosted/controller/maintenance/Maintainer.java @@ -3,6 +3,7 @@ package com.yahoo.vespa.hosted.controller.maintenance; import com.google.common.util.concurrent.UncheckedTimeoutException; import com.yahoo.component.AbstractComponent; +import com.yahoo.component.ComponentId; import com.yahoo.vespa.curator.Lock; import com.yahoo.vespa.hosted.controller.Controller; import com.yahoo.vespa.hosted.controller.persistence.CuratorDb; @@ -29,6 +30,7 @@ public abstract class Maintainer extends AbstractComponent implements Runnable { private final ScheduledExecutorService service; public Maintainer(Controller controller, Duration interval, JobControl jobControl) { + initId(new ComponentId(name())); this.controller = controller; this.maintenanceInterval = interval; this.jobControl = jobControl; diff --git a/controller-server/src/main/java/com/yahoo/vespa/hosted/controller/maintenance/ReadyJobsTrigger.java b/controller-server/src/main/java/com/yahoo/vespa/hosted/controller/maintenance/ReadyJobsTrigger.java new file mode 100644 index 00000000000..f165b4e4ea3 --- /dev/null +++ b/controller-server/src/main/java/com/yahoo/vespa/hosted/controller/maintenance/ReadyJobsTrigger.java @@ -0,0 +1,28 @@ +// Copyright 2017 Yahoo Holdings. 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.vespa.hosted.controller.Application; +import com.yahoo.vespa.hosted.controller.Controller; +import com.yahoo.vespa.hosted.controller.application.ApplicationList; +import com.yahoo.vespa.hosted.controller.application.Change; + +import java.time.Duration; + +/** + * Deploys application changes which have not made it to production because of a revision change block. + * + * @author bratseth + */ +@SuppressWarnings("unused") +public class ReadyJobsTrigger extends Maintainer { + + public ReadyJobsTrigger(Controller controller, Duration interval, JobControl jobControl) { + super(controller, interval, jobControl); + } + + @Override + public void maintain() { + controller().applications().deploymentTrigger().triggerReadyJobs(); + } + +} 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 1574801b77b..5f4d40ed2d8 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 @@ -467,7 +467,7 @@ public class ControllerTest { // back of the queue tester.clock().advance(Duration.ofHours(3)); tester.clock().advance(Duration.ofMinutes(50)); - tester.failureRedeployer().maintain(); + tester.readyJobTrigger().maintain(); List nextJobs = buildSystem.takeJobsToRun(); assertEquals(2, nextJobs.size()); diff --git a/controller-server/src/test/java/com/yahoo/vespa/hosted/controller/deployment/DeploymentTester.java b/controller-server/src/test/java/com/yahoo/vespa/hosted/controller/deployment/DeploymentTester.java index 9f1a373f3dd..23033fbc4f8 100644 --- a/controller-server/src/test/java/com/yahoo/vespa/hosted/controller/deployment/DeploymentTester.java +++ b/controller-server/src/test/java/com/yahoo/vespa/hosted/controller/deployment/DeploymentTester.java @@ -16,7 +16,7 @@ import com.yahoo.vespa.hosted.controller.application.ApplicationPackage; import com.yahoo.vespa.hosted.controller.application.Change; import com.yahoo.vespa.hosted.controller.application.DeploymentJobs; import com.yahoo.vespa.hosted.controller.application.DeploymentJobs.JobType; -import com.yahoo.vespa.hosted.controller.maintenance.FailureRedeployer; +import com.yahoo.vespa.hosted.controller.maintenance.ReadyJobsTrigger; import com.yahoo.vespa.hosted.controller.maintenance.JobControl; import com.yahoo.vespa.hosted.controller.maintenance.Upgrader; import com.yahoo.vespa.hosted.controller.versions.VersionStatus; @@ -46,7 +46,7 @@ public class DeploymentTester { private final ControllerTester tester; private final Upgrader upgrader; - private final FailureRedeployer failureRedeployer; + private final ReadyJobsTrigger readyJobTrigger; public DeploymentTester() { this(new ControllerTester()); @@ -57,13 +57,13 @@ public class DeploymentTester { tester.curator().writeUpgradesPerMinute(100); this.upgrader = new Upgrader(tester.controller(), maintenanceInterval, new JobControl(tester.curator()), tester.curator()); - this.failureRedeployer = new FailureRedeployer(tester.controller(), maintenanceInterval, - new JobControl(tester.curator())); + this.readyJobTrigger = new ReadyJobsTrigger(tester.controller(), maintenanceInterval, + new JobControl(tester.curator())); } public Upgrader upgrader() { return upgrader; } - public FailureRedeployer failureRedeployer() { return failureRedeployer; } + public ReadyJobsTrigger readyJobTrigger() { return readyJobTrigger; } public Controller controller() { return tester.controller(); } 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 3ca5e915ca9..7d9ba93f44b 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 @@ -13,7 +13,7 @@ import com.yahoo.vespa.hosted.controller.application.ApplicationPackage; import com.yahoo.vespa.hosted.controller.application.Change; import com.yahoo.vespa.hosted.controller.application.DeploymentJobs; import com.yahoo.vespa.hosted.controller.application.DeploymentJobs.JobType; -import com.yahoo.vespa.hosted.controller.maintenance.BlockedChangeDeployer; +import com.yahoo.vespa.hosted.controller.maintenance.ReadyJobsTrigger; import com.yahoo.vespa.hosted.controller.maintenance.JobControl; import org.junit.Test; @@ -63,7 +63,7 @@ public class DeploymentTriggerTest { tester.deployAndNotify(app, applicationPackage, false, JobType.systemTest); tester.clock().advance(Duration.ofHours(1)); assertEquals("Nothing scheduled", 0, tester.buildSystem().jobs().size()); - tester.failureRedeployer().maintain(); // Causes retry of systemTests + tester.readyJobTrigger().maintain(); // Causes retry of systemTests assertEquals("Scheduled retry", 1, tester.buildSystem().jobs().size()); tester.deployAndNotify(app, applicationPackage, true, JobType.systemTest); @@ -71,7 +71,7 @@ public class DeploymentTriggerTest { // staging-test times out and is retried tester.buildSystem().takeJobsToRun(); tester.clock().advance(Duration.ofHours(12).plus(Duration.ofSeconds(1))); - tester.failureRedeployer().maintain(); + tester.readyJobTrigger().maintain(); assertEquals("Retried dead job", 1, tester.buildSystem().jobs().size()); assertEquals(JobType.stagingTest.jobName(), tester.buildSystem().jobs().get(0).jobName()); } @@ -270,9 +270,9 @@ public class DeploymentTriggerTest { public void testBlockRevisionChange() { ManualClock clock = new ManualClock(Instant.parse("2017-09-26T17:30:00.00Z")); // Tuesday, 17:30 DeploymentTester tester = new DeploymentTester(new ControllerTester(clock)); - BlockedChangeDeployer blockedChangeDeployer = new BlockedChangeDeployer(tester.controller(), - Duration.ofHours(1), - new JobControl(tester.controllerTester().curator())); + ReadyJobsTrigger readyJobsTrigger = new ReadyJobsTrigger(tester.controller(), + Duration.ofHours(1), + new JobControl(tester.controllerTester().curator())); Version version = Version.fromString("5.0"); tester.updateVersionStatus(version); @@ -291,7 +291,7 @@ public class DeploymentTriggerTest { tester.clock().advance(Duration.ofHours(1)); // --------------- Enter block window: 18:30 - blockedChangeDeployer.run(); + readyJobsTrigger.run(); assertEquals(0, tester.buildSystem().jobs().size()); String searchDefinition = @@ -305,7 +305,7 @@ public class DeploymentTriggerTest { tester.deployTestOnly(app, changedApplication); - blockedChangeDeployer.run(); + readyJobsTrigger.run(); assertEquals(0, tester.buildSystem().jobs().size()); tester.clock().advance(Duration.ofHours(2)); // ---------------- Exit block window: 20:30 @@ -318,14 +318,14 @@ public class DeploymentTriggerTest { @Test public void testUpgradingButNoJobStarted() { DeploymentTester tester = new DeploymentTester(); - BlockedChangeDeployer blockedChangeDeployer = new BlockedChangeDeployer(tester.controller(), - Duration.ofHours(1), - new JobControl(tester.controllerTester().curator())); + ReadyJobsTrigger readyJobsTrigger = new ReadyJobsTrigger(tester.controller(), + Duration.ofHours(1), + new JobControl(tester.controllerTester().curator())); LockedApplication app = (LockedApplication)tester.createAndDeploy("default0", 3, "default"); // Store that we are upgrading but don't start the system-tests job tester.controller().applications().store(app.withDeploying(Optional.of(new Change.VersionChange(Version.fromString("6.2"))))); assertEquals(0, tester.buildSystem().jobs().size()); - blockedChangeDeployer.run(); + readyJobsTrigger.run(); assertEquals(1, tester.buildSystem().jobs().size()); assertEquals("system-test", tester.buildSystem().jobs().get(0).jobName()); } diff --git a/controller-server/src/test/java/com/yahoo/vespa/hosted/controller/maintenance/FailureRedeployerTest.java b/controller-server/src/test/java/com/yahoo/vespa/hosted/controller/maintenance/FailureRedeployerTest.java index d540db7c790..fd00123c697 100644 --- a/controller-server/src/test/java/com/yahoo/vespa/hosted/controller/maintenance/FailureRedeployerTest.java +++ b/controller-server/src/test/java/com/yahoo/vespa/hosted/controller/maintenance/FailureRedeployerTest.java @@ -69,7 +69,7 @@ public class FailureRedeployerTest { // Failure redeployer does not retry failing job for prod.us-east-3 as there's an ongoing deployment tester.clock().advance(Duration.ofMinutes(1)); - tester.failureRedeployer().maintain(); + tester.readyJobTrigger().maintain(); assertFalse("Job is not retried", tester.buildSystem().jobs().stream() .anyMatch(j -> j.jobName().equals(DeploymentJobs.JobType.productionUsEast3.jobName()))); @@ -87,7 +87,7 @@ public class FailureRedeployerTest { // Failure redeployer retries job tester.clock().advance(Duration.ofMinutes(5)); - tester.failureRedeployer().maintain(); + tester.readyJobTrigger().maintain(); assertEquals("Job is retried", 1, tester.buildSystem().jobs().size()); // Production job finally succeeds @@ -111,12 +111,12 @@ public class FailureRedeployerTest { // staging-test starts, but does not complete assertEquals(DeploymentJobs.JobType.stagingTest.jobName(), tester.buildSystem().takeJobsToRun().get(0).jobName()); - tester.failureRedeployer().maintain(); + tester.readyJobTrigger().maintain(); assertTrue("No jobs retried", tester.buildSystem().jobs().isEmpty()); // Just over 12 hours pass, job is retried tester.clock().advance(Duration.ofHours(12).plus(Duration.ofSeconds(1))); - tester.failureRedeployer().maintain(); + tester.readyJobTrigger().maintain(); assertEquals(DeploymentJobs.JobType.stagingTest.jobName(), tester.buildSystem().takeJobsToRun().get(0).jobName()); // Deployment completes @@ -169,7 +169,7 @@ public class FailureRedeployerTest { // Failure re-deployer does not retry failing system-test job as it failed for an older change tester.clock().advance(Duration.ofMinutes(5)); - tester.failureRedeployer().maintain(); + tester.readyJobTrigger().maintain(); assertTrue("No jobs retried", tester.buildSystem().jobs().isEmpty()); } @@ -217,7 +217,7 @@ public class FailureRedeployerTest { tester.buildSystem().takeJobsToRun(); // Failure re-deployer runs - tester.failureRedeployer().maintain(); + tester.readyJobTrigger().maintain(); assertTrue("No jobs retried", tester.buildSystem().jobs().isEmpty()); // Deployment completes @@ -242,7 +242,7 @@ public class FailureRedeployerTest { Application application = tester.controllerTester().createApplication(slime); // Failure redeployer does not restart deployment - tester.failureRedeployer().maintain(); + tester.readyJobTrigger().maintain(); assertTrue("No jobs scheduled", tester.buildSystem().jobs().isEmpty()); } @@ -262,7 +262,7 @@ public class FailureRedeployerTest { tester.controllerTester().createApplication(slime); // Failure redeployer does not restart deployment - tester.failureRedeployer().maintain(); + tester.readyJobTrigger().maintain(); assertTrue("No jobs scheduled", tester.buildSystem().jobs().isEmpty()); } diff --git a/controller-server/src/test/java/com/yahoo/vespa/hosted/controller/maintenance/UpgraderTest.java b/controller-server/src/test/java/com/yahoo/vespa/hosted/controller/maintenance/UpgraderTest.java index e92d5400a3d..64082adc1c0 100644 --- a/controller-server/src/test/java/com/yahoo/vespa/hosted/controller/maintenance/UpgraderTest.java +++ b/controller-server/src/test/java/com/yahoo/vespa/hosted/controller/maintenance/UpgraderTest.java @@ -474,9 +474,9 @@ public class UpgraderTest { public void testBlockVersionChangeHalfwayThough() { ManualClock clock = new ManualClock(Instant.parse("2017-09-26T17:00:00.00Z")); // Tuesday, 17:00 DeploymentTester tester = new DeploymentTester(new ControllerTester(clock)); - BlockedChangeDeployer blockedChangeDeployer = new BlockedChangeDeployer(tester.controller(), - Duration.ofHours(1), - new JobControl(tester.controllerTester().curator())); + ReadyJobsTrigger readyJobsTrigger = new ReadyJobsTrigger(tester.controller(), + Duration.ofHours(1), + new JobControl(tester.controllerTester().curator())); Version version = Version.fromString("5.0"); tester.updateVersionStatus(version); @@ -506,12 +506,12 @@ public class UpgraderTest { // One hour passes, time is 19:00, still no upgrade tester.clock().advance(Duration.ofHours(1)); - blockedChangeDeployer.maintain(); + readyJobsTrigger.maintain(); assertTrue("No jobs scheduled", tester.buildSystem().jobs().isEmpty()); // Another hour pass, time is 20:00 and application upgrades tester.clock().advance(Duration.ofHours(1)); - blockedChangeDeployer.maintain(); + readyJobsTrigger.maintain(); tester.deployAndNotify(app, applicationPackage, true, DeploymentJobs.JobType.productionUsCentral1); tester.deployAndNotify(app, applicationPackage, true, DeploymentJobs.JobType.productionUsEast3); assertTrue("All jobs consumed", tester.buildSystem().jobs().isEmpty()); @@ -528,9 +528,9 @@ public class UpgraderTest { public void testBlockVersionChangeHalfwayThoughThenNewVersion() { ManualClock clock = new ManualClock(Instant.parse("2017-09-29T16:00:00.00Z")); // Friday, 16:00 DeploymentTester tester = new DeploymentTester(new ControllerTester(clock)); - BlockedChangeDeployer blockedChangeDeployer = new BlockedChangeDeployer(tester.controller(), - Duration.ofHours(1), - new JobControl(tester.controllerTester().curator())); + ReadyJobsTrigger readyJobsTrigger = new ReadyJobsTrigger(tester.controller(), + Duration.ofHours(1), + new JobControl(tester.controllerTester().curator())); Version version = Version.fromString("5.0"); tester.updateVersionStatus(version); @@ -565,14 +565,14 @@ public class UpgraderTest { version = Version.fromString("5.2"); tester.updateVersionStatus(version); tester.upgrader().maintain(); - blockedChangeDeployer.maintain(); + readyJobsTrigger.maintain(); assertTrue("Nothing is scheduled", tester.buildSystem().jobs().isEmpty()); // Monday morning: We are not blocked tester.clock().advance(Duration.ofDays(1)); // Sunday, 17:00 tester.clock().advance(Duration.ofHours(17)); // Monday, 10:00 tester.upgrader().maintain(); - blockedChangeDeployer.maintain(); + readyJobsTrigger.maintain(); // We proceed with the new version in the expected order, not starting with the previously blocked version: // Test jobs are run with the new version, but not production as we are in the block window tester.deployAndNotify(app, applicationPackage, true, DeploymentJobs.JobType.systemTest); diff --git a/controller-server/src/test/java/com/yahoo/vespa/hosted/controller/restapi/controller/responses/maintenance.json b/controller-server/src/test/java/com/yahoo/vespa/hosted/controller/restapi/controller/responses/maintenance.json index 3633860772b..b52a0da67ba 100644 --- a/controller-server/src/test/java/com/yahoo/vespa/hosted/controller/restapi/controller/responses/maintenance.json +++ b/controller-server/src/test/java/com/yahoo/vespa/hosted/controller/restapi/controller/responses/maintenance.json @@ -1,19 +1,16 @@ { "jobs": [ { - "name": "DelayedDeployer" - }, - { - "name": "BlockedChangeDeployer" + "name": "ClusterInfoMaintainer" }, { - "name": "Upgrader" + "name": "ClusterUtilizationMaintainer" }, { - "name": "FailureRedeployer" + "name": "DelayedDeployer" }, { - "name": "VersionStatusUpdater" + "name": "DeploymentExpirer" }, { "name": "DeploymentIssueReporter" @@ -22,19 +19,19 @@ "name": "DeploymentMetricsMaintainer" }, { - "name": "OutstandingChangeDeployer" + "name": "MetricsReporter" }, { - "name": "ClusterUtilizationMaintainer" + "name": "OutstandingChangeDeployer" }, { - "name": "ClusterInfoMaintainer" + "name": "ReadyJobsTrigger" }, { - "name": "DeploymentExpirer" + "name": "Upgrader" }, { - "name": "MetricsReporter" + "name": "VersionStatusUpdater" } ], "inactive": [ -- cgit v1.2.3 From 24cb5c6c5242911d02a2804d3b7d78e20bcd852c Mon Sep 17 00:00:00 2001 From: Jon Bratseth Date: Tue, 14 Nov 2017 21:18:36 +0100 Subject: Remove DelayedDeployer as it is covered by ReadyJobsTrigger --- .../controller/deployment/DeploymentTrigger.java | 27 ---------------------- .../maintenance/ControllerMaintenance.java | 3 --- .../controller/maintenance/DelayedDeployer.java | 24 ------------------- .../deployment/DeploymentTriggerTest.java | 10 ++++---- .../restapi/controller/responses/maintenance.json | 3 --- 5 files changed, 5 insertions(+), 62 deletions(-) delete mode 100644 controller-server/src/main/java/com/yahoo/vespa/hosted/controller/maintenance/DelayedDeployer.java (limited to 'controller-server') diff --git a/controller-server/src/main/java/com/yahoo/vespa/hosted/controller/deployment/DeploymentTrigger.java b/controller-server/src/main/java/com/yahoo/vespa/hosted/controller/deployment/DeploymentTrigger.java index 796437db3f8..d02fb9094d6 100644 --- a/controller-server/src/main/java/com/yahoo/vespa/hosted/controller/deployment/DeploymentTrigger.java +++ b/controller-server/src/main/java/com/yahoo/vespa/hosted/controller/deployment/DeploymentTrigger.java @@ -216,33 +216,6 @@ public class DeploymentTrigger { return false; } - /** Triggers jobs that have been delayed according to deployment spec */ - public void triggerDelayed() { - for (Application application : applications().asList()) { - if ( ! application.deploying().isPresent() ) continue; - if (application.deploymentJobs().hasFailures()) continue; - if (application.deploymentJobs().isRunning(controller.applications().deploymentTrigger().jobTimeoutLimit())) continue; - if (application.deploymentSpec().steps().stream().noneMatch(step -> step instanceof DeploymentSpec.Delay)) { - continue; // Application does not have any delayed deployments - } - - Optional lastSuccessfulJob = application.deploymentJobs().jobStatus().values() - .stream() - .filter(j -> j.lastSuccess().isPresent()) - .sorted(Comparator.comparing(j -> j.lastSuccess().get().at()).reversed()) - .findFirst(); - if ( ! lastSuccessfulJob.isPresent() ) continue; - - // Trigger next - try (Lock lock = applications().lock(application.id())) { - LockedApplication lockedApplication = applications().require(application.id(), lock); - lockedApplication = trigger(order.nextAfter(lastSuccessfulJob.get().type(), lockedApplication), - lockedApplication, "Resuming delayed deployment"); - applications().store(lockedApplication); - } - } - } - /** * Triggers a change of this application * diff --git a/controller-server/src/main/java/com/yahoo/vespa/hosted/controller/maintenance/ControllerMaintenance.java b/controller-server/src/main/java/com/yahoo/vespa/hosted/controller/maintenance/ControllerMaintenance.java index e29b25f9fb3..01edc269116 100644 --- a/controller-server/src/main/java/com/yahoo/vespa/hosted/controller/maintenance/ControllerMaintenance.java +++ b/controller-server/src/main/java/com/yahoo/vespa/hosted/controller/maintenance/ControllerMaintenance.java @@ -28,7 +28,6 @@ public class ControllerMaintenance extends AbstractComponent { private final OutstandingChangeDeployer outstandingChangeDeployer; private final VersionStatusUpdater versionStatusUpdater; private final Upgrader upgrader; - private final DelayedDeployer delayedDeployer; private final ReadyJobsTrigger readyJobsTrigger; private final ClusterInfoMaintainer clusterInfoMaintainer; private final ClusterUtilizationMaintainer clusterUtilizationMaintainer; @@ -46,7 +45,6 @@ public class ControllerMaintenance extends AbstractComponent { outstandingChangeDeployer = new OutstandingChangeDeployer(controller, maintenanceInterval, jobControl); versionStatusUpdater = new VersionStatusUpdater(controller, Duration.ofMinutes(3), jobControl); upgrader = new Upgrader(controller, maintenanceInterval, jobControl, curator); - delayedDeployer = new DelayedDeployer(controller, maintenanceInterval, jobControl); readyJobsTrigger = new ReadyJobsTrigger(controller, maintenanceInterval, jobControl); clusterInfoMaintainer = new ClusterInfoMaintainer(controller, Duration.ofHours(2), jobControl); clusterUtilizationMaintainer = new ClusterUtilizationMaintainer(controller, Duration.ofHours(2), jobControl); @@ -66,7 +64,6 @@ public class ControllerMaintenance extends AbstractComponent { outstandingChangeDeployer.deconstruct(); versionStatusUpdater.deconstruct(); upgrader.deconstruct(); - delayedDeployer.deconstruct(); readyJobsTrigger.deconstruct(); clusterUtilizationMaintainer.deconstruct(); clusterInfoMaintainer.deconstruct(); diff --git a/controller-server/src/main/java/com/yahoo/vespa/hosted/controller/maintenance/DelayedDeployer.java b/controller-server/src/main/java/com/yahoo/vespa/hosted/controller/maintenance/DelayedDeployer.java deleted file mode 100644 index cb09c41a034..00000000000 --- a/controller-server/src/main/java/com/yahoo/vespa/hosted/controller/maintenance/DelayedDeployer.java +++ /dev/null @@ -1,24 +0,0 @@ -// Copyright 2017 Yahoo Holdings. 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.vespa.hosted.controller.Controller; - -import java.time.Duration; - -/** - * Maintenance job which triggers jobs that have been delayed according to the applications deployment spec. - * - * @author mpolden - */ -public class DelayedDeployer extends Maintainer { - - public DelayedDeployer(Controller controller, Duration interval, JobControl jobControl) { - super(controller, interval, jobControl); - } - - @Override - protected void maintain() { - controller().applications().deploymentTrigger().triggerDelayed(); - } - -} 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 7d9ba93f44b..10f8e80f318 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 @@ -128,7 +128,7 @@ public class DeploymentTriggerTest { // 30 seconds pass, us-west-1 is triggered tester.clock().advance(Duration.ofSeconds(30)); - tester.deploymentTrigger().triggerDelayed(); + tester.deploymentTrigger().triggerReadyJobs(); // Consume us-west-1 job without reporting completion assertEquals(1, buildSystem.jobs().size()); @@ -137,7 +137,7 @@ public class DeploymentTriggerTest { // 3 minutes pass, delayed trigger does nothing as us-west-1 is still in progress tester.clock().advance(Duration.ofMinutes(3)); - tester.deploymentTrigger().triggerDelayed(); + tester.deploymentTrigger().triggerReadyJobs(); assertTrue("No more jobs triggered at this time", buildSystem.jobs().isEmpty()); // us-west-1 completes @@ -145,18 +145,18 @@ public class DeploymentTriggerTest { tester.notifyJobCompletion(JobType.productionUsWest1, application, true); // Delayed trigger does nothing as not enough time has passed after us-west-1 completion - tester.deploymentTrigger().triggerDelayed(); + tester.deploymentTrigger().triggerReadyJobs(); assertTrue("No more jobs triggered at this time", buildSystem.jobs().isEmpty()); // 3 minutes pass, us-central-1 is triggered tester.clock().advance(Duration.ofMinutes(3)); - tester.deploymentTrigger().triggerDelayed(); + tester.deploymentTrigger().triggerReadyJobs(); tester.deployAndNotify(application, applicationPackage, true, JobType.productionUsCentral1); assertTrue("All jobs consumed", buildSystem.jobs().isEmpty()); // Delayed trigger job runs again, with nothing to trigger tester.clock().advance(Duration.ofMinutes(10)); - tester.deploymentTrigger().triggerDelayed(); + tester.deploymentTrigger().triggerReadyJobs(); assertTrue("All jobs consumed", buildSystem.jobs().isEmpty()); } diff --git a/controller-server/src/test/java/com/yahoo/vespa/hosted/controller/restapi/controller/responses/maintenance.json b/controller-server/src/test/java/com/yahoo/vespa/hosted/controller/restapi/controller/responses/maintenance.json index b52a0da67ba..33b9d4c70d5 100644 --- a/controller-server/src/test/java/com/yahoo/vespa/hosted/controller/restapi/controller/responses/maintenance.json +++ b/controller-server/src/test/java/com/yahoo/vespa/hosted/controller/restapi/controller/responses/maintenance.json @@ -6,9 +6,6 @@ { "name": "ClusterUtilizationMaintainer" }, - { - "name": "DelayedDeployer" - }, { "name": "DeploymentExpirer" }, -- cgit v1.2.3 From 71707bec11f8a9d47986cd6da7b5b739d9f755f9 Mon Sep 17 00:00:00 2001 From: Jon Marius Venstad Date: Wed, 15 Nov 2017 09:01:05 +0100 Subject: Avoid potential NPEs and fix a condition --- .../yahoo/vespa/hosted/controller/deployment/DeploymentTrigger.java | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) (limited to 'controller-server') diff --git a/controller-server/src/main/java/com/yahoo/vespa/hosted/controller/deployment/DeploymentTrigger.java b/controller-server/src/main/java/com/yahoo/vespa/hosted/controller/deployment/DeploymentTrigger.java index 78dc01fef19..7166a53071a 100644 --- a/controller-server/src/main/java/com/yahoo/vespa/hosted/controller/deployment/DeploymentTrigger.java +++ b/controller-server/src/main/java/com/yahoo/vespa/hosted/controller/deployment/DeploymentTrigger.java @@ -184,14 +184,14 @@ public class DeploymentTrigger { if ( ! application.deploying().isPresent()) return false; Change change = application.deploying().get(); - if ( ! previous.lastSuccess().isPresent() && + if ( ! previous.isSuccess() && ! productionUpgradeHasSucceededFor(previous, change)) return false; if (change instanceof Change.VersionChange) { Version targetVersion = ((Change.VersionChange)change).version(); if ( ! (targetVersion.equals(previous.lastSuccess().get().version())) ) return false; // version is outdated - if (isOnNewerVersionInProductionThan(targetVersion, application, next.type())) + if (next != null && isOnNewerVersionInProductionThan(targetVersion, application, next.type())) return false; // Don't downgrade } @@ -200,7 +200,7 @@ public class DeploymentTrigger { JobStatus.JobRun previousSuccess = previous.lastSuccess().get(); JobStatus.JobRun nextSuccess = next.lastSuccess().get(); - if (previousSuccess.revision().isPresent() && ! previousSuccess.revision().get().equals(nextSuccess.revision().get())) + if (previousSuccess.revision().isPresent() && ! previousSuccess.revision().equals(nextSuccess.revision())) return true; if ( ! previousSuccess.version().equals(nextSuccess.version())) return true; -- cgit v1.2.3 From d40da65d5996cdc27c81ba4fbdb52f6fa83ba206 Mon Sep 17 00:00:00 2001 From: Jon Marius Venstad Date: Wed, 15 Nov 2017 11:01:25 +0100 Subject: Restore condition to its intention, without the redundant part --- .../hosted/controller/deployment/DeploymentTrigger.java | 15 +-------------- 1 file changed, 1 insertion(+), 14 deletions(-) (limited to 'controller-server') diff --git a/controller-server/src/main/java/com/yahoo/vespa/hosted/controller/deployment/DeploymentTrigger.java b/controller-server/src/main/java/com/yahoo/vespa/hosted/controller/deployment/DeploymentTrigger.java index 7166a53071a..1faaa15f054 100644 --- a/controller-server/src/main/java/com/yahoo/vespa/hosted/controller/deployment/DeploymentTrigger.java +++ b/controller-server/src/main/java/com/yahoo/vespa/hosted/controller/deployment/DeploymentTrigger.java @@ -184,8 +184,7 @@ public class DeploymentTrigger { if ( ! application.deploying().isPresent()) return false; Change change = application.deploying().get(); - if ( ! previous.isSuccess() && - ! productionUpgradeHasSucceededFor(previous, change)) return false; + if ( ! previous.lastSuccess().isPresent()) return false; if (change instanceof Change.VersionChange) { Version targetVersion = ((Change.VersionChange)change).version(); @@ -446,18 +445,6 @@ public class DeploymentTrigger { } /** - * When upgrading it is ok to trigger the next job even if the previous failed if the previous has earlier succeeded - * on the version we are currently upgrading to - */ - private boolean productionUpgradeHasSucceededFor(JobStatus jobStatus, Change change) { - if ( ! (change instanceof Change.VersionChange) ) return false; - if ( ! isProduction(jobStatus.type())) return false; - Optional lastSuccess = jobStatus.lastSuccess(); - if ( ! lastSuccess.isPresent()) return false; - return lastSuccess.get().version().equals(((Change.VersionChange)change).version()); - } - - /** * Returns whether the current deployed version in the zone given by the job * is newer than the given version. This may be the case even if the production job * in question failed, if the failure happens after deployment. -- cgit v1.2.3 From ea651e354e930dea1535e3ae80d93e8455ab4a43 Mon Sep 17 00:00:00 2001 From: Harald Musum Date: Wed, 15 Nov 2017 12:41:17 +0100 Subject: Revert "Remove redundant logic" --- .../controller/deployment/DeploymentTrigger.java | 115 +++++++++++++++++---- .../maintenance/BlockedChangeDeployer.java | 28 +++++ .../maintenance/ControllerMaintenance.java | 12 ++- .../controller/maintenance/DelayedDeployer.java | 24 +++++ .../controller/maintenance/FailureRedeployer.java | 35 +++++++ .../hosted/controller/maintenance/JobControl.java | 3 +- .../hosted/controller/maintenance/Maintainer.java | 2 - .../controller/maintenance/ReadyJobsTrigger.java | 28 ----- .../vespa/hosted/controller/ControllerTest.java | 2 +- .../controller/deployment/DeploymentTester.java | 10 +- .../deployment/DeploymentTriggerTest.java | 34 +++--- .../maintenance/FailureRedeployerTest.java | 16 +-- .../controller/maintenance/UpgraderTest.java | 20 ++-- .../restapi/controller/responses/maintenance.json | 22 ++-- 14 files changed, 249 insertions(+), 102 deletions(-) create mode 100644 controller-server/src/main/java/com/yahoo/vespa/hosted/controller/maintenance/BlockedChangeDeployer.java create mode 100644 controller-server/src/main/java/com/yahoo/vespa/hosted/controller/maintenance/DelayedDeployer.java create mode 100644 controller-server/src/main/java/com/yahoo/vespa/hosted/controller/maintenance/FailureRedeployer.java delete mode 100644 controller-server/src/main/java/com/yahoo/vespa/hosted/controller/maintenance/ReadyJobsTrigger.java (limited to 'controller-server') diff --git a/controller-server/src/main/java/com/yahoo/vespa/hosted/controller/deployment/DeploymentTrigger.java b/controller-server/src/main/java/com/yahoo/vespa/hosted/controller/deployment/DeploymentTrigger.java index 97ac317d15b..1faaa15f054 100644 --- a/controller-server/src/main/java/com/yahoo/vespa/hosted/controller/deployment/DeploymentTrigger.java +++ b/controller-server/src/main/java/com/yahoo/vespa/hosted/controller/deployment/DeploymentTrigger.java @@ -145,24 +145,15 @@ public class DeploymentTrigger { List jobs = order.jobsFrom(application.deploymentSpec()); // Should the first step be triggered? - if ( ! jobs.isEmpty() && jobs.get(0).equals(JobType.systemTest) ) { - JobStatus systemTestStatus = application.deploymentJobs().jobStatus().get(JobType.systemTest); - if (application.deploying().get() instanceof Change.VersionChange) { - Version target = ((Change.VersionChange) application.deploying().get()).version(); - if (systemTestStatus == null - || ! systemTestStatus.lastTriggered().isPresent() - || ! systemTestStatus.isSuccess() - || ! systemTestStatus.lastTriggered().get().version().equals(target)) { - application = trigger(JobType.systemTest, application, false, "Upgrade to " + target); - controller.applications().store(application); - } - } - else { - JobStatus componentStatus = application.deploymentJobs().jobStatus().get(JobType.component); - if (changesAvailable(application, componentStatus, systemTestStatus)) { - application = trigger(JobType.systemTest, application, false, "Available change in component"); - controller.applications().store(application); - } + // TODO: How can the first job not be systemTest (second ccondition)? + if ( ! jobs.isEmpty() && jobs.get(0).equals(JobType.systemTest) && + application.deploying().get() instanceof Change.VersionChange) { + Version target = ((Change.VersionChange)application.deploying().get()).version(); + JobStatus jobStatus = application.deploymentJobs().jobStatus().get(JobType.systemTest); + if (jobStatus == null || ! jobStatus.lastTriggered().isPresent() + || ! jobStatus.lastTriggered().get().version().equals(target)) { + application = trigger(JobType.systemTest, application, false, "Upgrade to " + target); + controller.applications().store(application); } } @@ -215,6 +206,62 @@ public class DeploymentTrigger { return false; } + /** + * Called periodically to cause triggering of jobs in the background + */ + public void triggerFailing(ApplicationId applicationId) { + try (Lock lock = applications().lock(applicationId)) { + LockedApplication application = applications().require(applicationId, lock); + if ( ! application.deploying().isPresent()) return; // No ongoing change, no need to retry + + // Retry first failing job + for (JobType jobType : order.jobsFrom(application.deploymentSpec())) { + JobStatus jobStatus = application.deploymentJobs().jobStatus().get(jobType); + if (isFailing(application.deploying().get(), jobStatus)) { + if (shouldRetryNow(jobStatus)) { + application = trigger(jobType, application, false, "Retrying failing job"); + applications().store(application); + } + break; + } + } + + // Retry dead job + Optional firstDeadJob = firstDeadJob(application.deploymentJobs()); + if (firstDeadJob.isPresent()) { + application = trigger(firstDeadJob.get().type(), application, false, "Retrying dead job"); + applications().store(application); + } + } + } + + /** Triggers jobs that have been delayed according to deployment spec */ + public void triggerDelayed() { + for (Application application : applications().asList()) { + if ( ! application.deploying().isPresent() ) continue; + if (application.deploymentJobs().hasFailures()) continue; + if (application.deploymentJobs().isRunning(controller.applications().deploymentTrigger().jobTimeoutLimit())) continue; + if (application.deploymentSpec().steps().stream().noneMatch(step -> step instanceof DeploymentSpec.Delay)) { + continue; // Application does not have any delayed deployments + } + + Optional lastSuccessfulJob = application.deploymentJobs().jobStatus().values() + .stream() + .filter(j -> j.lastSuccess().isPresent()) + .sorted(Comparator.comparing(j -> j.lastSuccess().get().at()).reversed()) + .findFirst(); + if ( ! lastSuccessfulJob.isPresent() ) continue; + + // Trigger next + try (Lock lock = applications().lock(application.id())) { + LockedApplication lockedApplication = applications().require(application.id(), lock); + lockedApplication = trigger(order.nextAfter(lastSuccessfulJob.get().type(), lockedApplication), + lockedApplication, "Resuming delayed deployment"); + applications().store(lockedApplication); + } + } + } + /** * Triggers a change of this application * @@ -254,10 +301,42 @@ public class DeploymentTrigger { private ApplicationController applications() { return controller.applications(); } + /** Returns whether a job is failing for the current change in the given application */ + private boolean isFailing(Change change, JobStatus status) { + return status != null + && ! status.isSuccess() + && status.lastCompleted().isPresent() + && status.lastCompleted().get().lastCompletedWas(change); + } + private boolean isCapacityConstrained(JobType jobType) { return jobType == JobType.stagingTest || jobType == JobType.systemTest; } + /** Returns the first job that has been running for more than the given timeout */ + private Optional firstDeadJob(DeploymentJobs jobs) { + Optional oldestRunningJob = jobs.jobStatus().values().stream() + .filter(job -> job.isRunning(Instant.ofEpochMilli(0))) + .sorted(Comparator.comparing(status -> status.lastTriggered().get().at())) + .findFirst(); + return oldestRunningJob.filter(job -> job.lastTriggered().get().at().isBefore(jobTimeoutLimit())); + } + + /** Decide whether the job should be triggered by the periodic trigger */ + private boolean shouldRetryNow(JobStatus job) { + if (job.isSuccess()) return false; + if (job.isRunning(jobTimeoutLimit())) return false; + + // Retry after 10% of the time since it started failing + Duration aTenthOfFailTime = Duration.ofMillis( (clock.millis() - job.firstFailing().get().at().toEpochMilli()) / 10); + if (job.lastCompleted().get().at().isBefore(clock.instant().minus(aTenthOfFailTime))) return true; + + // ... or retry anyway if we haven't tried in 4 hours + if (job.lastCompleted().get().at().isBefore(clock.instant().minus(Duration.ofHours(4)))) return true; + + return false; + } + /** Retry immediately only if this job just started failing. Otherwise retry periodically */ private boolean shouldRetryNow(Application application, JobType jobType) { JobStatus jobStatus = application.deploymentJobs().jobStatus().get(jobType); diff --git a/controller-server/src/main/java/com/yahoo/vespa/hosted/controller/maintenance/BlockedChangeDeployer.java b/controller-server/src/main/java/com/yahoo/vespa/hosted/controller/maintenance/BlockedChangeDeployer.java new file mode 100644 index 00000000000..4a68fd6cfab --- /dev/null +++ b/controller-server/src/main/java/com/yahoo/vespa/hosted/controller/maintenance/BlockedChangeDeployer.java @@ -0,0 +1,28 @@ +// Copyright 2017 Yahoo Holdings. 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.vespa.hosted.controller.Application; +import com.yahoo.vespa.hosted.controller.Controller; +import com.yahoo.vespa.hosted.controller.application.ApplicationList; +import com.yahoo.vespa.hosted.controller.application.Change; + +import java.time.Duration; + +/** + * Deploys application changes which have not made it to production because of a revision change block. + * + * @author bratseth + */ +@SuppressWarnings("unused") +public class BlockedChangeDeployer extends Maintainer { + + public BlockedChangeDeployer(Controller controller, Duration interval, JobControl jobControl) { + super(controller, interval, jobControl); + } + + @Override + protected void maintain() { + controller().applications().deploymentTrigger().triggerReadyJobs(); + } + +} diff --git a/controller-server/src/main/java/com/yahoo/vespa/hosted/controller/maintenance/ControllerMaintenance.java b/controller-server/src/main/java/com/yahoo/vespa/hosted/controller/maintenance/ControllerMaintenance.java index 01edc269116..2fdce2802ab 100644 --- a/controller-server/src/main/java/com/yahoo/vespa/hosted/controller/maintenance/ControllerMaintenance.java +++ b/controller-server/src/main/java/com/yahoo/vespa/hosted/controller/maintenance/ControllerMaintenance.java @@ -25,10 +25,12 @@ public class ControllerMaintenance extends AbstractComponent { private final DeploymentExpirer deploymentExpirer; private final DeploymentIssueReporter deploymentIssueReporter; private final MetricsReporter metricsReporter; + private final FailureRedeployer failureRedeployer; private final OutstandingChangeDeployer outstandingChangeDeployer; private final VersionStatusUpdater versionStatusUpdater; private final Upgrader upgrader; - private final ReadyJobsTrigger readyJobsTrigger; + private final DelayedDeployer delayedDeployer; + private final BlockedChangeDeployer blockedChangeDeployer; private final ClusterInfoMaintainer clusterInfoMaintainer; private final ClusterUtilizationMaintainer clusterUtilizationMaintainer; private final DeploymentMetricsMaintainer deploymentMetricsMaintainer; @@ -42,10 +44,12 @@ public class ControllerMaintenance extends AbstractComponent { deploymentExpirer = new DeploymentExpirer(controller, maintenanceInterval, jobControl); deploymentIssueReporter = new DeploymentIssueReporter(controller, deploymentIssues, maintenanceInterval, jobControl); metricsReporter = new MetricsReporter(controller, metric, chefClient, jobControl, controller.system()); + failureRedeployer = new FailureRedeployer(controller, maintenanceInterval, jobControl); outstandingChangeDeployer = new OutstandingChangeDeployer(controller, maintenanceInterval, jobControl); versionStatusUpdater = new VersionStatusUpdater(controller, Duration.ofMinutes(3), jobControl); upgrader = new Upgrader(controller, maintenanceInterval, jobControl, curator); - readyJobsTrigger = new ReadyJobsTrigger(controller, maintenanceInterval, jobControl); + delayedDeployer = new DelayedDeployer(controller, maintenanceInterval, jobControl); + blockedChangeDeployer = new BlockedChangeDeployer(controller, maintenanceInterval, jobControl); clusterInfoMaintainer = new ClusterInfoMaintainer(controller, Duration.ofHours(2), jobControl); clusterUtilizationMaintainer = new ClusterUtilizationMaintainer(controller, Duration.ofHours(2), jobControl); deploymentMetricsMaintainer = new DeploymentMetricsMaintainer(controller, Duration.ofMinutes(10), jobControl); @@ -61,10 +65,12 @@ public class ControllerMaintenance extends AbstractComponent { deploymentExpirer.deconstruct(); deploymentIssueReporter.deconstruct(); metricsReporter.deconstruct(); + failureRedeployer.deconstruct(); outstandingChangeDeployer.deconstruct(); versionStatusUpdater.deconstruct(); upgrader.deconstruct(); - readyJobsTrigger.deconstruct(); + delayedDeployer.deconstruct(); + blockedChangeDeployer.deconstruct(); clusterUtilizationMaintainer.deconstruct(); clusterInfoMaintainer.deconstruct(); deploymentMetricsMaintainer.deconstruct(); diff --git a/controller-server/src/main/java/com/yahoo/vespa/hosted/controller/maintenance/DelayedDeployer.java b/controller-server/src/main/java/com/yahoo/vespa/hosted/controller/maintenance/DelayedDeployer.java new file mode 100644 index 00000000000..cb09c41a034 --- /dev/null +++ b/controller-server/src/main/java/com/yahoo/vespa/hosted/controller/maintenance/DelayedDeployer.java @@ -0,0 +1,24 @@ +// Copyright 2017 Yahoo Holdings. 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.vespa.hosted.controller.Controller; + +import java.time.Duration; + +/** + * Maintenance job which triggers jobs that have been delayed according to the applications deployment spec. + * + * @author mpolden + */ +public class DelayedDeployer extends Maintainer { + + public DelayedDeployer(Controller controller, Duration interval, JobControl jobControl) { + super(controller, interval, jobControl); + } + + @Override + protected void maintain() { + controller().applications().deploymentTrigger().triggerDelayed(); + } + +} diff --git a/controller-server/src/main/java/com/yahoo/vespa/hosted/controller/maintenance/FailureRedeployer.java b/controller-server/src/main/java/com/yahoo/vespa/hosted/controller/maintenance/FailureRedeployer.java new file mode 100644 index 00000000000..72f8faa5180 --- /dev/null +++ b/controller-server/src/main/java/com/yahoo/vespa/hosted/controller/maintenance/FailureRedeployer.java @@ -0,0 +1,35 @@ +// Copyright 2017 Yahoo Holdings. 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.vespa.hosted.controller.Application; +import com.yahoo.vespa.hosted.controller.Controller; +import com.yahoo.vespa.hosted.controller.application.ApplicationList; + +import java.time.Duration; +import java.util.List; + +/** + * Attempts redeployment of failed jobs and deployments. + * + * @author bratseth + * @author mpolden + */ +public class FailureRedeployer extends Maintainer { + + public FailureRedeployer(Controller controller, Duration interval, JobControl jobControl) { + super(controller, interval, jobControl); + } + + @Override + public void maintain() { + List applications = ApplicationList.from(controller().applications().asList()) + .notPullRequest() + .asList(); + applications.forEach(application -> triggerFailing(application)); + } + + private void triggerFailing(Application application) { + controller().applications().deploymentTrigger().triggerFailing(application.id()); + } + +} diff --git a/controller-server/src/main/java/com/yahoo/vespa/hosted/controller/maintenance/JobControl.java b/controller-server/src/main/java/com/yahoo/vespa/hosted/controller/maintenance/JobControl.java index 6aa1b89c605..d7396cb2acb 100644 --- a/controller-server/src/main/java/com/yahoo/vespa/hosted/controller/maintenance/JobControl.java +++ b/controller-server/src/main/java/com/yahoo/vespa/hosted/controller/maintenance/JobControl.java @@ -5,7 +5,6 @@ import com.yahoo.vespa.curator.Lock; import com.yahoo.vespa.hosted.controller.persistence.CuratorDb; import java.util.HashSet; -import java.util.LinkedHashSet; import java.util.Set; import java.util.concurrent.ConcurrentSkipListSet; import java.util.logging.Logger; @@ -41,7 +40,7 @@ public class JobControl { * Returns a snapshot of the set of jobs started on this system (whether deactivated or not). * Each job is represented by its simple (omitting package) class name. */ - public Set jobs() { return new LinkedHashSet<>(startedJobs); } + public Set jobs() { return new HashSet<>(startedJobs); } /** Returns an unmodifiable set containing the currently inactive jobs in this */ public Set inactiveJobs() { return curator.readInactiveJobs(); } diff --git a/controller-server/src/main/java/com/yahoo/vespa/hosted/controller/maintenance/Maintainer.java b/controller-server/src/main/java/com/yahoo/vespa/hosted/controller/maintenance/Maintainer.java index 1d19d8ca522..bbef7980273 100644 --- a/controller-server/src/main/java/com/yahoo/vespa/hosted/controller/maintenance/Maintainer.java +++ b/controller-server/src/main/java/com/yahoo/vespa/hosted/controller/maintenance/Maintainer.java @@ -3,7 +3,6 @@ package com.yahoo.vespa.hosted.controller.maintenance; import com.google.common.util.concurrent.UncheckedTimeoutException; import com.yahoo.component.AbstractComponent; -import com.yahoo.component.ComponentId; import com.yahoo.vespa.curator.Lock; import com.yahoo.vespa.hosted.controller.Controller; import com.yahoo.vespa.hosted.controller.persistence.CuratorDb; @@ -30,7 +29,6 @@ public abstract class Maintainer extends AbstractComponent implements Runnable { private final ScheduledExecutorService service; public Maintainer(Controller controller, Duration interval, JobControl jobControl) { - initId(new ComponentId(name())); this.controller = controller; this.maintenanceInterval = interval; this.jobControl = jobControl; diff --git a/controller-server/src/main/java/com/yahoo/vespa/hosted/controller/maintenance/ReadyJobsTrigger.java b/controller-server/src/main/java/com/yahoo/vespa/hosted/controller/maintenance/ReadyJobsTrigger.java deleted file mode 100644 index f165b4e4ea3..00000000000 --- a/controller-server/src/main/java/com/yahoo/vespa/hosted/controller/maintenance/ReadyJobsTrigger.java +++ /dev/null @@ -1,28 +0,0 @@ -// Copyright 2017 Yahoo Holdings. 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.vespa.hosted.controller.Application; -import com.yahoo.vespa.hosted.controller.Controller; -import com.yahoo.vespa.hosted.controller.application.ApplicationList; -import com.yahoo.vespa.hosted.controller.application.Change; - -import java.time.Duration; - -/** - * Deploys application changes which have not made it to production because of a revision change block. - * - * @author bratseth - */ -@SuppressWarnings("unused") -public class ReadyJobsTrigger extends Maintainer { - - public ReadyJobsTrigger(Controller controller, Duration interval, JobControl jobControl) { - super(controller, interval, jobControl); - } - - @Override - public void maintain() { - controller().applications().deploymentTrigger().triggerReadyJobs(); - } - -} 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 5f4d40ed2d8..1574801b77b 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 @@ -467,7 +467,7 @@ public class ControllerTest { // back of the queue tester.clock().advance(Duration.ofHours(3)); tester.clock().advance(Duration.ofMinutes(50)); - tester.readyJobTrigger().maintain(); + tester.failureRedeployer().maintain(); List nextJobs = buildSystem.takeJobsToRun(); assertEquals(2, nextJobs.size()); diff --git a/controller-server/src/test/java/com/yahoo/vespa/hosted/controller/deployment/DeploymentTester.java b/controller-server/src/test/java/com/yahoo/vespa/hosted/controller/deployment/DeploymentTester.java index 23033fbc4f8..9f1a373f3dd 100644 --- a/controller-server/src/test/java/com/yahoo/vespa/hosted/controller/deployment/DeploymentTester.java +++ b/controller-server/src/test/java/com/yahoo/vespa/hosted/controller/deployment/DeploymentTester.java @@ -16,7 +16,7 @@ import com.yahoo.vespa.hosted.controller.application.ApplicationPackage; import com.yahoo.vespa.hosted.controller.application.Change; import com.yahoo.vespa.hosted.controller.application.DeploymentJobs; import com.yahoo.vespa.hosted.controller.application.DeploymentJobs.JobType; -import com.yahoo.vespa.hosted.controller.maintenance.ReadyJobsTrigger; +import com.yahoo.vespa.hosted.controller.maintenance.FailureRedeployer; import com.yahoo.vespa.hosted.controller.maintenance.JobControl; import com.yahoo.vespa.hosted.controller.maintenance.Upgrader; import com.yahoo.vespa.hosted.controller.versions.VersionStatus; @@ -46,7 +46,7 @@ public class DeploymentTester { private final ControllerTester tester; private final Upgrader upgrader; - private final ReadyJobsTrigger readyJobTrigger; + private final FailureRedeployer failureRedeployer; public DeploymentTester() { this(new ControllerTester()); @@ -57,13 +57,13 @@ public class DeploymentTester { tester.curator().writeUpgradesPerMinute(100); this.upgrader = new Upgrader(tester.controller(), maintenanceInterval, new JobControl(tester.curator()), tester.curator()); - this.readyJobTrigger = new ReadyJobsTrigger(tester.controller(), maintenanceInterval, - new JobControl(tester.curator())); + this.failureRedeployer = new FailureRedeployer(tester.controller(), maintenanceInterval, + new JobControl(tester.curator())); } public Upgrader upgrader() { return upgrader; } - public ReadyJobsTrigger readyJobTrigger() { return readyJobTrigger; } + public FailureRedeployer failureRedeployer() { return failureRedeployer; } public Controller controller() { return tester.controller(); } 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 10f8e80f318..3ca5e915ca9 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 @@ -13,7 +13,7 @@ import com.yahoo.vespa.hosted.controller.application.ApplicationPackage; import com.yahoo.vespa.hosted.controller.application.Change; import com.yahoo.vespa.hosted.controller.application.DeploymentJobs; import com.yahoo.vespa.hosted.controller.application.DeploymentJobs.JobType; -import com.yahoo.vespa.hosted.controller.maintenance.ReadyJobsTrigger; +import com.yahoo.vespa.hosted.controller.maintenance.BlockedChangeDeployer; import com.yahoo.vespa.hosted.controller.maintenance.JobControl; import org.junit.Test; @@ -63,7 +63,7 @@ public class DeploymentTriggerTest { tester.deployAndNotify(app, applicationPackage, false, JobType.systemTest); tester.clock().advance(Duration.ofHours(1)); assertEquals("Nothing scheduled", 0, tester.buildSystem().jobs().size()); - tester.readyJobTrigger().maintain(); // Causes retry of systemTests + tester.failureRedeployer().maintain(); // Causes retry of systemTests assertEquals("Scheduled retry", 1, tester.buildSystem().jobs().size()); tester.deployAndNotify(app, applicationPackage, true, JobType.systemTest); @@ -71,7 +71,7 @@ public class DeploymentTriggerTest { // staging-test times out and is retried tester.buildSystem().takeJobsToRun(); tester.clock().advance(Duration.ofHours(12).plus(Duration.ofSeconds(1))); - tester.readyJobTrigger().maintain(); + tester.failureRedeployer().maintain(); assertEquals("Retried dead job", 1, tester.buildSystem().jobs().size()); assertEquals(JobType.stagingTest.jobName(), tester.buildSystem().jobs().get(0).jobName()); } @@ -128,7 +128,7 @@ public class DeploymentTriggerTest { // 30 seconds pass, us-west-1 is triggered tester.clock().advance(Duration.ofSeconds(30)); - tester.deploymentTrigger().triggerReadyJobs(); + tester.deploymentTrigger().triggerDelayed(); // Consume us-west-1 job without reporting completion assertEquals(1, buildSystem.jobs().size()); @@ -137,7 +137,7 @@ public class DeploymentTriggerTest { // 3 minutes pass, delayed trigger does nothing as us-west-1 is still in progress tester.clock().advance(Duration.ofMinutes(3)); - tester.deploymentTrigger().triggerReadyJobs(); + tester.deploymentTrigger().triggerDelayed(); assertTrue("No more jobs triggered at this time", buildSystem.jobs().isEmpty()); // us-west-1 completes @@ -145,18 +145,18 @@ public class DeploymentTriggerTest { tester.notifyJobCompletion(JobType.productionUsWest1, application, true); // Delayed trigger does nothing as not enough time has passed after us-west-1 completion - tester.deploymentTrigger().triggerReadyJobs(); + tester.deploymentTrigger().triggerDelayed(); assertTrue("No more jobs triggered at this time", buildSystem.jobs().isEmpty()); // 3 minutes pass, us-central-1 is triggered tester.clock().advance(Duration.ofMinutes(3)); - tester.deploymentTrigger().triggerReadyJobs(); + tester.deploymentTrigger().triggerDelayed(); tester.deployAndNotify(application, applicationPackage, true, JobType.productionUsCentral1); assertTrue("All jobs consumed", buildSystem.jobs().isEmpty()); // Delayed trigger job runs again, with nothing to trigger tester.clock().advance(Duration.ofMinutes(10)); - tester.deploymentTrigger().triggerReadyJobs(); + tester.deploymentTrigger().triggerDelayed(); assertTrue("All jobs consumed", buildSystem.jobs().isEmpty()); } @@ -270,9 +270,9 @@ public class DeploymentTriggerTest { public void testBlockRevisionChange() { ManualClock clock = new ManualClock(Instant.parse("2017-09-26T17:30:00.00Z")); // Tuesday, 17:30 DeploymentTester tester = new DeploymentTester(new ControllerTester(clock)); - ReadyJobsTrigger readyJobsTrigger = new ReadyJobsTrigger(tester.controller(), - Duration.ofHours(1), - new JobControl(tester.controllerTester().curator())); + BlockedChangeDeployer blockedChangeDeployer = new BlockedChangeDeployer(tester.controller(), + Duration.ofHours(1), + new JobControl(tester.controllerTester().curator())); Version version = Version.fromString("5.0"); tester.updateVersionStatus(version); @@ -291,7 +291,7 @@ public class DeploymentTriggerTest { tester.clock().advance(Duration.ofHours(1)); // --------------- Enter block window: 18:30 - readyJobsTrigger.run(); + blockedChangeDeployer.run(); assertEquals(0, tester.buildSystem().jobs().size()); String searchDefinition = @@ -305,7 +305,7 @@ public class DeploymentTriggerTest { tester.deployTestOnly(app, changedApplication); - readyJobsTrigger.run(); + blockedChangeDeployer.run(); assertEquals(0, tester.buildSystem().jobs().size()); tester.clock().advance(Duration.ofHours(2)); // ---------------- Exit block window: 20:30 @@ -318,14 +318,14 @@ public class DeploymentTriggerTest { @Test public void testUpgradingButNoJobStarted() { DeploymentTester tester = new DeploymentTester(); - ReadyJobsTrigger readyJobsTrigger = new ReadyJobsTrigger(tester.controller(), - Duration.ofHours(1), - new JobControl(tester.controllerTester().curator())); + BlockedChangeDeployer blockedChangeDeployer = new BlockedChangeDeployer(tester.controller(), + Duration.ofHours(1), + new JobControl(tester.controllerTester().curator())); LockedApplication app = (LockedApplication)tester.createAndDeploy("default0", 3, "default"); // Store that we are upgrading but don't start the system-tests job tester.controller().applications().store(app.withDeploying(Optional.of(new Change.VersionChange(Version.fromString("6.2"))))); assertEquals(0, tester.buildSystem().jobs().size()); - readyJobsTrigger.run(); + blockedChangeDeployer.run(); assertEquals(1, tester.buildSystem().jobs().size()); assertEquals("system-test", tester.buildSystem().jobs().get(0).jobName()); } diff --git a/controller-server/src/test/java/com/yahoo/vespa/hosted/controller/maintenance/FailureRedeployerTest.java b/controller-server/src/test/java/com/yahoo/vespa/hosted/controller/maintenance/FailureRedeployerTest.java index fd00123c697..d540db7c790 100644 --- a/controller-server/src/test/java/com/yahoo/vespa/hosted/controller/maintenance/FailureRedeployerTest.java +++ b/controller-server/src/test/java/com/yahoo/vespa/hosted/controller/maintenance/FailureRedeployerTest.java @@ -69,7 +69,7 @@ public class FailureRedeployerTest { // Failure redeployer does not retry failing job for prod.us-east-3 as there's an ongoing deployment tester.clock().advance(Duration.ofMinutes(1)); - tester.readyJobTrigger().maintain(); + tester.failureRedeployer().maintain(); assertFalse("Job is not retried", tester.buildSystem().jobs().stream() .anyMatch(j -> j.jobName().equals(DeploymentJobs.JobType.productionUsEast3.jobName()))); @@ -87,7 +87,7 @@ public class FailureRedeployerTest { // Failure redeployer retries job tester.clock().advance(Duration.ofMinutes(5)); - tester.readyJobTrigger().maintain(); + tester.failureRedeployer().maintain(); assertEquals("Job is retried", 1, tester.buildSystem().jobs().size()); // Production job finally succeeds @@ -111,12 +111,12 @@ public class FailureRedeployerTest { // staging-test starts, but does not complete assertEquals(DeploymentJobs.JobType.stagingTest.jobName(), tester.buildSystem().takeJobsToRun().get(0).jobName()); - tester.readyJobTrigger().maintain(); + tester.failureRedeployer().maintain(); assertTrue("No jobs retried", tester.buildSystem().jobs().isEmpty()); // Just over 12 hours pass, job is retried tester.clock().advance(Duration.ofHours(12).plus(Duration.ofSeconds(1))); - tester.readyJobTrigger().maintain(); + tester.failureRedeployer().maintain(); assertEquals(DeploymentJobs.JobType.stagingTest.jobName(), tester.buildSystem().takeJobsToRun().get(0).jobName()); // Deployment completes @@ -169,7 +169,7 @@ public class FailureRedeployerTest { // Failure re-deployer does not retry failing system-test job as it failed for an older change tester.clock().advance(Duration.ofMinutes(5)); - tester.readyJobTrigger().maintain(); + tester.failureRedeployer().maintain(); assertTrue("No jobs retried", tester.buildSystem().jobs().isEmpty()); } @@ -217,7 +217,7 @@ public class FailureRedeployerTest { tester.buildSystem().takeJobsToRun(); // Failure re-deployer runs - tester.readyJobTrigger().maintain(); + tester.failureRedeployer().maintain(); assertTrue("No jobs retried", tester.buildSystem().jobs().isEmpty()); // Deployment completes @@ -242,7 +242,7 @@ public class FailureRedeployerTest { Application application = tester.controllerTester().createApplication(slime); // Failure redeployer does not restart deployment - tester.readyJobTrigger().maintain(); + tester.failureRedeployer().maintain(); assertTrue("No jobs scheduled", tester.buildSystem().jobs().isEmpty()); } @@ -262,7 +262,7 @@ public class FailureRedeployerTest { tester.controllerTester().createApplication(slime); // Failure redeployer does not restart deployment - tester.readyJobTrigger().maintain(); + tester.failureRedeployer().maintain(); assertTrue("No jobs scheduled", tester.buildSystem().jobs().isEmpty()); } diff --git a/controller-server/src/test/java/com/yahoo/vespa/hosted/controller/maintenance/UpgraderTest.java b/controller-server/src/test/java/com/yahoo/vespa/hosted/controller/maintenance/UpgraderTest.java index 64082adc1c0..e92d5400a3d 100644 --- a/controller-server/src/test/java/com/yahoo/vespa/hosted/controller/maintenance/UpgraderTest.java +++ b/controller-server/src/test/java/com/yahoo/vespa/hosted/controller/maintenance/UpgraderTest.java @@ -474,9 +474,9 @@ public class UpgraderTest { public void testBlockVersionChangeHalfwayThough() { ManualClock clock = new ManualClock(Instant.parse("2017-09-26T17:00:00.00Z")); // Tuesday, 17:00 DeploymentTester tester = new DeploymentTester(new ControllerTester(clock)); - ReadyJobsTrigger readyJobsTrigger = new ReadyJobsTrigger(tester.controller(), - Duration.ofHours(1), - new JobControl(tester.controllerTester().curator())); + BlockedChangeDeployer blockedChangeDeployer = new BlockedChangeDeployer(tester.controller(), + Duration.ofHours(1), + new JobControl(tester.controllerTester().curator())); Version version = Version.fromString("5.0"); tester.updateVersionStatus(version); @@ -506,12 +506,12 @@ public class UpgraderTest { // One hour passes, time is 19:00, still no upgrade tester.clock().advance(Duration.ofHours(1)); - readyJobsTrigger.maintain(); + blockedChangeDeployer.maintain(); assertTrue("No jobs scheduled", tester.buildSystem().jobs().isEmpty()); // Another hour pass, time is 20:00 and application upgrades tester.clock().advance(Duration.ofHours(1)); - readyJobsTrigger.maintain(); + blockedChangeDeployer.maintain(); tester.deployAndNotify(app, applicationPackage, true, DeploymentJobs.JobType.productionUsCentral1); tester.deployAndNotify(app, applicationPackage, true, DeploymentJobs.JobType.productionUsEast3); assertTrue("All jobs consumed", tester.buildSystem().jobs().isEmpty()); @@ -528,9 +528,9 @@ public class UpgraderTest { public void testBlockVersionChangeHalfwayThoughThenNewVersion() { ManualClock clock = new ManualClock(Instant.parse("2017-09-29T16:00:00.00Z")); // Friday, 16:00 DeploymentTester tester = new DeploymentTester(new ControllerTester(clock)); - ReadyJobsTrigger readyJobsTrigger = new ReadyJobsTrigger(tester.controller(), - Duration.ofHours(1), - new JobControl(tester.controllerTester().curator())); + BlockedChangeDeployer blockedChangeDeployer = new BlockedChangeDeployer(tester.controller(), + Duration.ofHours(1), + new JobControl(tester.controllerTester().curator())); Version version = Version.fromString("5.0"); tester.updateVersionStatus(version); @@ -565,14 +565,14 @@ public class UpgraderTest { version = Version.fromString("5.2"); tester.updateVersionStatus(version); tester.upgrader().maintain(); - readyJobsTrigger.maintain(); + blockedChangeDeployer.maintain(); assertTrue("Nothing is scheduled", tester.buildSystem().jobs().isEmpty()); // Monday morning: We are not blocked tester.clock().advance(Duration.ofDays(1)); // Sunday, 17:00 tester.clock().advance(Duration.ofHours(17)); // Monday, 10:00 tester.upgrader().maintain(); - readyJobsTrigger.maintain(); + blockedChangeDeployer.maintain(); // We proceed with the new version in the expected order, not starting with the previously blocked version: // Test jobs are run with the new version, but not production as we are in the block window tester.deployAndNotify(app, applicationPackage, true, DeploymentJobs.JobType.systemTest); diff --git a/controller-server/src/test/java/com/yahoo/vespa/hosted/controller/restapi/controller/responses/maintenance.json b/controller-server/src/test/java/com/yahoo/vespa/hosted/controller/restapi/controller/responses/maintenance.json index 33b9d4c70d5..3633860772b 100644 --- a/controller-server/src/test/java/com/yahoo/vespa/hosted/controller/restapi/controller/responses/maintenance.json +++ b/controller-server/src/test/java/com/yahoo/vespa/hosted/controller/restapi/controller/responses/maintenance.json @@ -1,13 +1,19 @@ { "jobs": [ { - "name": "ClusterInfoMaintainer" + "name": "DelayedDeployer" }, { - "name": "ClusterUtilizationMaintainer" + "name": "BlockedChangeDeployer" }, { - "name": "DeploymentExpirer" + "name": "Upgrader" + }, + { + "name": "FailureRedeployer" + }, + { + "name": "VersionStatusUpdater" }, { "name": "DeploymentIssueReporter" @@ -16,19 +22,19 @@ "name": "DeploymentMetricsMaintainer" }, { - "name": "MetricsReporter" + "name": "OutstandingChangeDeployer" }, { - "name": "OutstandingChangeDeployer" + "name": "ClusterUtilizationMaintainer" }, { - "name": "ReadyJobsTrigger" + "name": "ClusterInfoMaintainer" }, { - "name": "Upgrader" + "name": "DeploymentExpirer" }, { - "name": "VersionStatusUpdater" + "name": "MetricsReporter" } ], "inactive": [ -- cgit v1.2.3 From a094c27bd3b5a240b29a762bdc7f2fd827f9216d Mon Sep 17 00:00:00 2001 From: Jon Bratseth Date: Wed, 15 Nov 2017 12:43:55 +0100 Subject: Revert "Revert "Remove redundant logic"" --- .../controller/deployment/DeploymentTrigger.java | 115 ++++----------------- .../maintenance/BlockedChangeDeployer.java | 28 ----- .../maintenance/ControllerMaintenance.java | 12 +-- .../controller/maintenance/DelayedDeployer.java | 24 ----- .../controller/maintenance/FailureRedeployer.java | 35 ------- .../hosted/controller/maintenance/JobControl.java | 3 +- .../hosted/controller/maintenance/Maintainer.java | 2 + .../controller/maintenance/ReadyJobsTrigger.java | 28 +++++ .../vespa/hosted/controller/ControllerTest.java | 2 +- .../controller/deployment/DeploymentTester.java | 10 +- .../deployment/DeploymentTriggerTest.java | 34 +++--- .../maintenance/FailureRedeployerTest.java | 16 +-- .../controller/maintenance/UpgraderTest.java | 20 ++-- .../restapi/controller/responses/maintenance.json | 22 ++-- 14 files changed, 102 insertions(+), 249 deletions(-) delete mode 100644 controller-server/src/main/java/com/yahoo/vespa/hosted/controller/maintenance/BlockedChangeDeployer.java delete mode 100644 controller-server/src/main/java/com/yahoo/vespa/hosted/controller/maintenance/DelayedDeployer.java delete mode 100644 controller-server/src/main/java/com/yahoo/vespa/hosted/controller/maintenance/FailureRedeployer.java create mode 100644 controller-server/src/main/java/com/yahoo/vespa/hosted/controller/maintenance/ReadyJobsTrigger.java (limited to 'controller-server') diff --git a/controller-server/src/main/java/com/yahoo/vespa/hosted/controller/deployment/DeploymentTrigger.java b/controller-server/src/main/java/com/yahoo/vespa/hosted/controller/deployment/DeploymentTrigger.java index 1faaa15f054..97ac317d15b 100644 --- a/controller-server/src/main/java/com/yahoo/vespa/hosted/controller/deployment/DeploymentTrigger.java +++ b/controller-server/src/main/java/com/yahoo/vespa/hosted/controller/deployment/DeploymentTrigger.java @@ -145,15 +145,24 @@ public class DeploymentTrigger { List jobs = order.jobsFrom(application.deploymentSpec()); // Should the first step be triggered? - // TODO: How can the first job not be systemTest (second ccondition)? - if ( ! jobs.isEmpty() && jobs.get(0).equals(JobType.systemTest) && - application.deploying().get() instanceof Change.VersionChange) { - Version target = ((Change.VersionChange)application.deploying().get()).version(); - JobStatus jobStatus = application.deploymentJobs().jobStatus().get(JobType.systemTest); - if (jobStatus == null || ! jobStatus.lastTriggered().isPresent() - || ! jobStatus.lastTriggered().get().version().equals(target)) { - application = trigger(JobType.systemTest, application, false, "Upgrade to " + target); - controller.applications().store(application); + if ( ! jobs.isEmpty() && jobs.get(0).equals(JobType.systemTest) ) { + JobStatus systemTestStatus = application.deploymentJobs().jobStatus().get(JobType.systemTest); + if (application.deploying().get() instanceof Change.VersionChange) { + Version target = ((Change.VersionChange) application.deploying().get()).version(); + if (systemTestStatus == null + || ! systemTestStatus.lastTriggered().isPresent() + || ! systemTestStatus.isSuccess() + || ! systemTestStatus.lastTriggered().get().version().equals(target)) { + application = trigger(JobType.systemTest, application, false, "Upgrade to " + target); + controller.applications().store(application); + } + } + else { + JobStatus componentStatus = application.deploymentJobs().jobStatus().get(JobType.component); + if (changesAvailable(application, componentStatus, systemTestStatus)) { + application = trigger(JobType.systemTest, application, false, "Available change in component"); + controller.applications().store(application); + } } } @@ -206,62 +215,6 @@ public class DeploymentTrigger { return false; } - /** - * Called periodically to cause triggering of jobs in the background - */ - public void triggerFailing(ApplicationId applicationId) { - try (Lock lock = applications().lock(applicationId)) { - LockedApplication application = applications().require(applicationId, lock); - if ( ! application.deploying().isPresent()) return; // No ongoing change, no need to retry - - // Retry first failing job - for (JobType jobType : order.jobsFrom(application.deploymentSpec())) { - JobStatus jobStatus = application.deploymentJobs().jobStatus().get(jobType); - if (isFailing(application.deploying().get(), jobStatus)) { - if (shouldRetryNow(jobStatus)) { - application = trigger(jobType, application, false, "Retrying failing job"); - applications().store(application); - } - break; - } - } - - // Retry dead job - Optional firstDeadJob = firstDeadJob(application.deploymentJobs()); - if (firstDeadJob.isPresent()) { - application = trigger(firstDeadJob.get().type(), application, false, "Retrying dead job"); - applications().store(application); - } - } - } - - /** Triggers jobs that have been delayed according to deployment spec */ - public void triggerDelayed() { - for (Application application : applications().asList()) { - if ( ! application.deploying().isPresent() ) continue; - if (application.deploymentJobs().hasFailures()) continue; - if (application.deploymentJobs().isRunning(controller.applications().deploymentTrigger().jobTimeoutLimit())) continue; - if (application.deploymentSpec().steps().stream().noneMatch(step -> step instanceof DeploymentSpec.Delay)) { - continue; // Application does not have any delayed deployments - } - - Optional lastSuccessfulJob = application.deploymentJobs().jobStatus().values() - .stream() - .filter(j -> j.lastSuccess().isPresent()) - .sorted(Comparator.comparing(j -> j.lastSuccess().get().at()).reversed()) - .findFirst(); - if ( ! lastSuccessfulJob.isPresent() ) continue; - - // Trigger next - try (Lock lock = applications().lock(application.id())) { - LockedApplication lockedApplication = applications().require(application.id(), lock); - lockedApplication = trigger(order.nextAfter(lastSuccessfulJob.get().type(), lockedApplication), - lockedApplication, "Resuming delayed deployment"); - applications().store(lockedApplication); - } - } - } - /** * Triggers a change of this application * @@ -301,42 +254,10 @@ public class DeploymentTrigger { private ApplicationController applications() { return controller.applications(); } - /** Returns whether a job is failing for the current change in the given application */ - private boolean isFailing(Change change, JobStatus status) { - return status != null - && ! status.isSuccess() - && status.lastCompleted().isPresent() - && status.lastCompleted().get().lastCompletedWas(change); - } - private boolean isCapacityConstrained(JobType jobType) { return jobType == JobType.stagingTest || jobType == JobType.systemTest; } - /** Returns the first job that has been running for more than the given timeout */ - private Optional firstDeadJob(DeploymentJobs jobs) { - Optional oldestRunningJob = jobs.jobStatus().values().stream() - .filter(job -> job.isRunning(Instant.ofEpochMilli(0))) - .sorted(Comparator.comparing(status -> status.lastTriggered().get().at())) - .findFirst(); - return oldestRunningJob.filter(job -> job.lastTriggered().get().at().isBefore(jobTimeoutLimit())); - } - - /** Decide whether the job should be triggered by the periodic trigger */ - private boolean shouldRetryNow(JobStatus job) { - if (job.isSuccess()) return false; - if (job.isRunning(jobTimeoutLimit())) return false; - - // Retry after 10% of the time since it started failing - Duration aTenthOfFailTime = Duration.ofMillis( (clock.millis() - job.firstFailing().get().at().toEpochMilli()) / 10); - if (job.lastCompleted().get().at().isBefore(clock.instant().minus(aTenthOfFailTime))) return true; - - // ... or retry anyway if we haven't tried in 4 hours - if (job.lastCompleted().get().at().isBefore(clock.instant().minus(Duration.ofHours(4)))) return true; - - return false; - } - /** Retry immediately only if this job just started failing. Otherwise retry periodically */ private boolean shouldRetryNow(Application application, JobType jobType) { JobStatus jobStatus = application.deploymentJobs().jobStatus().get(jobType); diff --git a/controller-server/src/main/java/com/yahoo/vespa/hosted/controller/maintenance/BlockedChangeDeployer.java b/controller-server/src/main/java/com/yahoo/vespa/hosted/controller/maintenance/BlockedChangeDeployer.java deleted file mode 100644 index 4a68fd6cfab..00000000000 --- a/controller-server/src/main/java/com/yahoo/vespa/hosted/controller/maintenance/BlockedChangeDeployer.java +++ /dev/null @@ -1,28 +0,0 @@ -// Copyright 2017 Yahoo Holdings. 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.vespa.hosted.controller.Application; -import com.yahoo.vespa.hosted.controller.Controller; -import com.yahoo.vespa.hosted.controller.application.ApplicationList; -import com.yahoo.vespa.hosted.controller.application.Change; - -import java.time.Duration; - -/** - * Deploys application changes which have not made it to production because of a revision change block. - * - * @author bratseth - */ -@SuppressWarnings("unused") -public class BlockedChangeDeployer extends Maintainer { - - public BlockedChangeDeployer(Controller controller, Duration interval, JobControl jobControl) { - super(controller, interval, jobControl); - } - - @Override - protected void maintain() { - controller().applications().deploymentTrigger().triggerReadyJobs(); - } - -} diff --git a/controller-server/src/main/java/com/yahoo/vespa/hosted/controller/maintenance/ControllerMaintenance.java b/controller-server/src/main/java/com/yahoo/vespa/hosted/controller/maintenance/ControllerMaintenance.java index 2fdce2802ab..01edc269116 100644 --- a/controller-server/src/main/java/com/yahoo/vespa/hosted/controller/maintenance/ControllerMaintenance.java +++ b/controller-server/src/main/java/com/yahoo/vespa/hosted/controller/maintenance/ControllerMaintenance.java @@ -25,12 +25,10 @@ public class ControllerMaintenance extends AbstractComponent { private final DeploymentExpirer deploymentExpirer; private final DeploymentIssueReporter deploymentIssueReporter; private final MetricsReporter metricsReporter; - private final FailureRedeployer failureRedeployer; private final OutstandingChangeDeployer outstandingChangeDeployer; private final VersionStatusUpdater versionStatusUpdater; private final Upgrader upgrader; - private final DelayedDeployer delayedDeployer; - private final BlockedChangeDeployer blockedChangeDeployer; + private final ReadyJobsTrigger readyJobsTrigger; private final ClusterInfoMaintainer clusterInfoMaintainer; private final ClusterUtilizationMaintainer clusterUtilizationMaintainer; private final DeploymentMetricsMaintainer deploymentMetricsMaintainer; @@ -44,12 +42,10 @@ public class ControllerMaintenance extends AbstractComponent { deploymentExpirer = new DeploymentExpirer(controller, maintenanceInterval, jobControl); deploymentIssueReporter = new DeploymentIssueReporter(controller, deploymentIssues, maintenanceInterval, jobControl); metricsReporter = new MetricsReporter(controller, metric, chefClient, jobControl, controller.system()); - failureRedeployer = new FailureRedeployer(controller, maintenanceInterval, jobControl); outstandingChangeDeployer = new OutstandingChangeDeployer(controller, maintenanceInterval, jobControl); versionStatusUpdater = new VersionStatusUpdater(controller, Duration.ofMinutes(3), jobControl); upgrader = new Upgrader(controller, maintenanceInterval, jobControl, curator); - delayedDeployer = new DelayedDeployer(controller, maintenanceInterval, jobControl); - blockedChangeDeployer = new BlockedChangeDeployer(controller, maintenanceInterval, jobControl); + readyJobsTrigger = new ReadyJobsTrigger(controller, maintenanceInterval, jobControl); clusterInfoMaintainer = new ClusterInfoMaintainer(controller, Duration.ofHours(2), jobControl); clusterUtilizationMaintainer = new ClusterUtilizationMaintainer(controller, Duration.ofHours(2), jobControl); deploymentMetricsMaintainer = new DeploymentMetricsMaintainer(controller, Duration.ofMinutes(10), jobControl); @@ -65,12 +61,10 @@ public class ControllerMaintenance extends AbstractComponent { deploymentExpirer.deconstruct(); deploymentIssueReporter.deconstruct(); metricsReporter.deconstruct(); - failureRedeployer.deconstruct(); outstandingChangeDeployer.deconstruct(); versionStatusUpdater.deconstruct(); upgrader.deconstruct(); - delayedDeployer.deconstruct(); - blockedChangeDeployer.deconstruct(); + readyJobsTrigger.deconstruct(); clusterUtilizationMaintainer.deconstruct(); clusterInfoMaintainer.deconstruct(); deploymentMetricsMaintainer.deconstruct(); diff --git a/controller-server/src/main/java/com/yahoo/vespa/hosted/controller/maintenance/DelayedDeployer.java b/controller-server/src/main/java/com/yahoo/vespa/hosted/controller/maintenance/DelayedDeployer.java deleted file mode 100644 index cb09c41a034..00000000000 --- a/controller-server/src/main/java/com/yahoo/vespa/hosted/controller/maintenance/DelayedDeployer.java +++ /dev/null @@ -1,24 +0,0 @@ -// Copyright 2017 Yahoo Holdings. 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.vespa.hosted.controller.Controller; - -import java.time.Duration; - -/** - * Maintenance job which triggers jobs that have been delayed according to the applications deployment spec. - * - * @author mpolden - */ -public class DelayedDeployer extends Maintainer { - - public DelayedDeployer(Controller controller, Duration interval, JobControl jobControl) { - super(controller, interval, jobControl); - } - - @Override - protected void maintain() { - controller().applications().deploymentTrigger().triggerDelayed(); - } - -} diff --git a/controller-server/src/main/java/com/yahoo/vespa/hosted/controller/maintenance/FailureRedeployer.java b/controller-server/src/main/java/com/yahoo/vespa/hosted/controller/maintenance/FailureRedeployer.java deleted file mode 100644 index 72f8faa5180..00000000000 --- a/controller-server/src/main/java/com/yahoo/vespa/hosted/controller/maintenance/FailureRedeployer.java +++ /dev/null @@ -1,35 +0,0 @@ -// Copyright 2017 Yahoo Holdings. 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.vespa.hosted.controller.Application; -import com.yahoo.vespa.hosted.controller.Controller; -import com.yahoo.vespa.hosted.controller.application.ApplicationList; - -import java.time.Duration; -import java.util.List; - -/** - * Attempts redeployment of failed jobs and deployments. - * - * @author bratseth - * @author mpolden - */ -public class FailureRedeployer extends Maintainer { - - public FailureRedeployer(Controller controller, Duration interval, JobControl jobControl) { - super(controller, interval, jobControl); - } - - @Override - public void maintain() { - List applications = ApplicationList.from(controller().applications().asList()) - .notPullRequest() - .asList(); - applications.forEach(application -> triggerFailing(application)); - } - - private void triggerFailing(Application application) { - controller().applications().deploymentTrigger().triggerFailing(application.id()); - } - -} diff --git a/controller-server/src/main/java/com/yahoo/vespa/hosted/controller/maintenance/JobControl.java b/controller-server/src/main/java/com/yahoo/vespa/hosted/controller/maintenance/JobControl.java index d7396cb2acb..6aa1b89c605 100644 --- a/controller-server/src/main/java/com/yahoo/vespa/hosted/controller/maintenance/JobControl.java +++ b/controller-server/src/main/java/com/yahoo/vespa/hosted/controller/maintenance/JobControl.java @@ -5,6 +5,7 @@ import com.yahoo.vespa.curator.Lock; import com.yahoo.vespa.hosted.controller.persistence.CuratorDb; import java.util.HashSet; +import java.util.LinkedHashSet; import java.util.Set; import java.util.concurrent.ConcurrentSkipListSet; import java.util.logging.Logger; @@ -40,7 +41,7 @@ public class JobControl { * Returns a snapshot of the set of jobs started on this system (whether deactivated or not). * Each job is represented by its simple (omitting package) class name. */ - public Set jobs() { return new HashSet<>(startedJobs); } + public Set jobs() { return new LinkedHashSet<>(startedJobs); } /** Returns an unmodifiable set containing the currently inactive jobs in this */ public Set inactiveJobs() { return curator.readInactiveJobs(); } diff --git a/controller-server/src/main/java/com/yahoo/vespa/hosted/controller/maintenance/Maintainer.java b/controller-server/src/main/java/com/yahoo/vespa/hosted/controller/maintenance/Maintainer.java index bbef7980273..1d19d8ca522 100644 --- a/controller-server/src/main/java/com/yahoo/vespa/hosted/controller/maintenance/Maintainer.java +++ b/controller-server/src/main/java/com/yahoo/vespa/hosted/controller/maintenance/Maintainer.java @@ -3,6 +3,7 @@ package com.yahoo.vespa.hosted.controller.maintenance; import com.google.common.util.concurrent.UncheckedTimeoutException; import com.yahoo.component.AbstractComponent; +import com.yahoo.component.ComponentId; import com.yahoo.vespa.curator.Lock; import com.yahoo.vespa.hosted.controller.Controller; import com.yahoo.vespa.hosted.controller.persistence.CuratorDb; @@ -29,6 +30,7 @@ public abstract class Maintainer extends AbstractComponent implements Runnable { private final ScheduledExecutorService service; public Maintainer(Controller controller, Duration interval, JobControl jobControl) { + initId(new ComponentId(name())); this.controller = controller; this.maintenanceInterval = interval; this.jobControl = jobControl; diff --git a/controller-server/src/main/java/com/yahoo/vespa/hosted/controller/maintenance/ReadyJobsTrigger.java b/controller-server/src/main/java/com/yahoo/vespa/hosted/controller/maintenance/ReadyJobsTrigger.java new file mode 100644 index 00000000000..f165b4e4ea3 --- /dev/null +++ b/controller-server/src/main/java/com/yahoo/vespa/hosted/controller/maintenance/ReadyJobsTrigger.java @@ -0,0 +1,28 @@ +// Copyright 2017 Yahoo Holdings. 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.vespa.hosted.controller.Application; +import com.yahoo.vespa.hosted.controller.Controller; +import com.yahoo.vespa.hosted.controller.application.ApplicationList; +import com.yahoo.vespa.hosted.controller.application.Change; + +import java.time.Duration; + +/** + * Deploys application changes which have not made it to production because of a revision change block. + * + * @author bratseth + */ +@SuppressWarnings("unused") +public class ReadyJobsTrigger extends Maintainer { + + public ReadyJobsTrigger(Controller controller, Duration interval, JobControl jobControl) { + super(controller, interval, jobControl); + } + + @Override + public void maintain() { + controller().applications().deploymentTrigger().triggerReadyJobs(); + } + +} 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 1574801b77b..5f4d40ed2d8 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 @@ -467,7 +467,7 @@ public class ControllerTest { // back of the queue tester.clock().advance(Duration.ofHours(3)); tester.clock().advance(Duration.ofMinutes(50)); - tester.failureRedeployer().maintain(); + tester.readyJobTrigger().maintain(); List nextJobs = buildSystem.takeJobsToRun(); assertEquals(2, nextJobs.size()); diff --git a/controller-server/src/test/java/com/yahoo/vespa/hosted/controller/deployment/DeploymentTester.java b/controller-server/src/test/java/com/yahoo/vespa/hosted/controller/deployment/DeploymentTester.java index 9f1a373f3dd..23033fbc4f8 100644 --- a/controller-server/src/test/java/com/yahoo/vespa/hosted/controller/deployment/DeploymentTester.java +++ b/controller-server/src/test/java/com/yahoo/vespa/hosted/controller/deployment/DeploymentTester.java @@ -16,7 +16,7 @@ import com.yahoo.vespa.hosted.controller.application.ApplicationPackage; import com.yahoo.vespa.hosted.controller.application.Change; import com.yahoo.vespa.hosted.controller.application.DeploymentJobs; import com.yahoo.vespa.hosted.controller.application.DeploymentJobs.JobType; -import com.yahoo.vespa.hosted.controller.maintenance.FailureRedeployer; +import com.yahoo.vespa.hosted.controller.maintenance.ReadyJobsTrigger; import com.yahoo.vespa.hosted.controller.maintenance.JobControl; import com.yahoo.vespa.hosted.controller.maintenance.Upgrader; import com.yahoo.vespa.hosted.controller.versions.VersionStatus; @@ -46,7 +46,7 @@ public class DeploymentTester { private final ControllerTester tester; private final Upgrader upgrader; - private final FailureRedeployer failureRedeployer; + private final ReadyJobsTrigger readyJobTrigger; public DeploymentTester() { this(new ControllerTester()); @@ -57,13 +57,13 @@ public class DeploymentTester { tester.curator().writeUpgradesPerMinute(100); this.upgrader = new Upgrader(tester.controller(), maintenanceInterval, new JobControl(tester.curator()), tester.curator()); - this.failureRedeployer = new FailureRedeployer(tester.controller(), maintenanceInterval, - new JobControl(tester.curator())); + this.readyJobTrigger = new ReadyJobsTrigger(tester.controller(), maintenanceInterval, + new JobControl(tester.curator())); } public Upgrader upgrader() { return upgrader; } - public FailureRedeployer failureRedeployer() { return failureRedeployer; } + public ReadyJobsTrigger readyJobTrigger() { return readyJobTrigger; } public Controller controller() { return tester.controller(); } 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 3ca5e915ca9..10f8e80f318 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 @@ -13,7 +13,7 @@ import com.yahoo.vespa.hosted.controller.application.ApplicationPackage; import com.yahoo.vespa.hosted.controller.application.Change; import com.yahoo.vespa.hosted.controller.application.DeploymentJobs; import com.yahoo.vespa.hosted.controller.application.DeploymentJobs.JobType; -import com.yahoo.vespa.hosted.controller.maintenance.BlockedChangeDeployer; +import com.yahoo.vespa.hosted.controller.maintenance.ReadyJobsTrigger; import com.yahoo.vespa.hosted.controller.maintenance.JobControl; import org.junit.Test; @@ -63,7 +63,7 @@ public class DeploymentTriggerTest { tester.deployAndNotify(app, applicationPackage, false, JobType.systemTest); tester.clock().advance(Duration.ofHours(1)); assertEquals("Nothing scheduled", 0, tester.buildSystem().jobs().size()); - tester.failureRedeployer().maintain(); // Causes retry of systemTests + tester.readyJobTrigger().maintain(); // Causes retry of systemTests assertEquals("Scheduled retry", 1, tester.buildSystem().jobs().size()); tester.deployAndNotify(app, applicationPackage, true, JobType.systemTest); @@ -71,7 +71,7 @@ public class DeploymentTriggerTest { // staging-test times out and is retried tester.buildSystem().takeJobsToRun(); tester.clock().advance(Duration.ofHours(12).plus(Duration.ofSeconds(1))); - tester.failureRedeployer().maintain(); + tester.readyJobTrigger().maintain(); assertEquals("Retried dead job", 1, tester.buildSystem().jobs().size()); assertEquals(JobType.stagingTest.jobName(), tester.buildSystem().jobs().get(0).jobName()); } @@ -128,7 +128,7 @@ public class DeploymentTriggerTest { // 30 seconds pass, us-west-1 is triggered tester.clock().advance(Duration.ofSeconds(30)); - tester.deploymentTrigger().triggerDelayed(); + tester.deploymentTrigger().triggerReadyJobs(); // Consume us-west-1 job without reporting completion assertEquals(1, buildSystem.jobs().size()); @@ -137,7 +137,7 @@ public class DeploymentTriggerTest { // 3 minutes pass, delayed trigger does nothing as us-west-1 is still in progress tester.clock().advance(Duration.ofMinutes(3)); - tester.deploymentTrigger().triggerDelayed(); + tester.deploymentTrigger().triggerReadyJobs(); assertTrue("No more jobs triggered at this time", buildSystem.jobs().isEmpty()); // us-west-1 completes @@ -145,18 +145,18 @@ public class DeploymentTriggerTest { tester.notifyJobCompletion(JobType.productionUsWest1, application, true); // Delayed trigger does nothing as not enough time has passed after us-west-1 completion - tester.deploymentTrigger().triggerDelayed(); + tester.deploymentTrigger().triggerReadyJobs(); assertTrue("No more jobs triggered at this time", buildSystem.jobs().isEmpty()); // 3 minutes pass, us-central-1 is triggered tester.clock().advance(Duration.ofMinutes(3)); - tester.deploymentTrigger().triggerDelayed(); + tester.deploymentTrigger().triggerReadyJobs(); tester.deployAndNotify(application, applicationPackage, true, JobType.productionUsCentral1); assertTrue("All jobs consumed", buildSystem.jobs().isEmpty()); // Delayed trigger job runs again, with nothing to trigger tester.clock().advance(Duration.ofMinutes(10)); - tester.deploymentTrigger().triggerDelayed(); + tester.deploymentTrigger().triggerReadyJobs(); assertTrue("All jobs consumed", buildSystem.jobs().isEmpty()); } @@ -270,9 +270,9 @@ public class DeploymentTriggerTest { public void testBlockRevisionChange() { ManualClock clock = new ManualClock(Instant.parse("2017-09-26T17:30:00.00Z")); // Tuesday, 17:30 DeploymentTester tester = new DeploymentTester(new ControllerTester(clock)); - BlockedChangeDeployer blockedChangeDeployer = new BlockedChangeDeployer(tester.controller(), - Duration.ofHours(1), - new JobControl(tester.controllerTester().curator())); + ReadyJobsTrigger readyJobsTrigger = new ReadyJobsTrigger(tester.controller(), + Duration.ofHours(1), + new JobControl(tester.controllerTester().curator())); Version version = Version.fromString("5.0"); tester.updateVersionStatus(version); @@ -291,7 +291,7 @@ public class DeploymentTriggerTest { tester.clock().advance(Duration.ofHours(1)); // --------------- Enter block window: 18:30 - blockedChangeDeployer.run(); + readyJobsTrigger.run(); assertEquals(0, tester.buildSystem().jobs().size()); String searchDefinition = @@ -305,7 +305,7 @@ public class DeploymentTriggerTest { tester.deployTestOnly(app, changedApplication); - blockedChangeDeployer.run(); + readyJobsTrigger.run(); assertEquals(0, tester.buildSystem().jobs().size()); tester.clock().advance(Duration.ofHours(2)); // ---------------- Exit block window: 20:30 @@ -318,14 +318,14 @@ public class DeploymentTriggerTest { @Test public void testUpgradingButNoJobStarted() { DeploymentTester tester = new DeploymentTester(); - BlockedChangeDeployer blockedChangeDeployer = new BlockedChangeDeployer(tester.controller(), - Duration.ofHours(1), - new JobControl(tester.controllerTester().curator())); + ReadyJobsTrigger readyJobsTrigger = new ReadyJobsTrigger(tester.controller(), + Duration.ofHours(1), + new JobControl(tester.controllerTester().curator())); LockedApplication app = (LockedApplication)tester.createAndDeploy("default0", 3, "default"); // Store that we are upgrading but don't start the system-tests job tester.controller().applications().store(app.withDeploying(Optional.of(new Change.VersionChange(Version.fromString("6.2"))))); assertEquals(0, tester.buildSystem().jobs().size()); - blockedChangeDeployer.run(); + readyJobsTrigger.run(); assertEquals(1, tester.buildSystem().jobs().size()); assertEquals("system-test", tester.buildSystem().jobs().get(0).jobName()); } diff --git a/controller-server/src/test/java/com/yahoo/vespa/hosted/controller/maintenance/FailureRedeployerTest.java b/controller-server/src/test/java/com/yahoo/vespa/hosted/controller/maintenance/FailureRedeployerTest.java index d540db7c790..fd00123c697 100644 --- a/controller-server/src/test/java/com/yahoo/vespa/hosted/controller/maintenance/FailureRedeployerTest.java +++ b/controller-server/src/test/java/com/yahoo/vespa/hosted/controller/maintenance/FailureRedeployerTest.java @@ -69,7 +69,7 @@ public class FailureRedeployerTest { // Failure redeployer does not retry failing job for prod.us-east-3 as there's an ongoing deployment tester.clock().advance(Duration.ofMinutes(1)); - tester.failureRedeployer().maintain(); + tester.readyJobTrigger().maintain(); assertFalse("Job is not retried", tester.buildSystem().jobs().stream() .anyMatch(j -> j.jobName().equals(DeploymentJobs.JobType.productionUsEast3.jobName()))); @@ -87,7 +87,7 @@ public class FailureRedeployerTest { // Failure redeployer retries job tester.clock().advance(Duration.ofMinutes(5)); - tester.failureRedeployer().maintain(); + tester.readyJobTrigger().maintain(); assertEquals("Job is retried", 1, tester.buildSystem().jobs().size()); // Production job finally succeeds @@ -111,12 +111,12 @@ public class FailureRedeployerTest { // staging-test starts, but does not complete assertEquals(DeploymentJobs.JobType.stagingTest.jobName(), tester.buildSystem().takeJobsToRun().get(0).jobName()); - tester.failureRedeployer().maintain(); + tester.readyJobTrigger().maintain(); assertTrue("No jobs retried", tester.buildSystem().jobs().isEmpty()); // Just over 12 hours pass, job is retried tester.clock().advance(Duration.ofHours(12).plus(Duration.ofSeconds(1))); - tester.failureRedeployer().maintain(); + tester.readyJobTrigger().maintain(); assertEquals(DeploymentJobs.JobType.stagingTest.jobName(), tester.buildSystem().takeJobsToRun().get(0).jobName()); // Deployment completes @@ -169,7 +169,7 @@ public class FailureRedeployerTest { // Failure re-deployer does not retry failing system-test job as it failed for an older change tester.clock().advance(Duration.ofMinutes(5)); - tester.failureRedeployer().maintain(); + tester.readyJobTrigger().maintain(); assertTrue("No jobs retried", tester.buildSystem().jobs().isEmpty()); } @@ -217,7 +217,7 @@ public class FailureRedeployerTest { tester.buildSystem().takeJobsToRun(); // Failure re-deployer runs - tester.failureRedeployer().maintain(); + tester.readyJobTrigger().maintain(); assertTrue("No jobs retried", tester.buildSystem().jobs().isEmpty()); // Deployment completes @@ -242,7 +242,7 @@ public class FailureRedeployerTest { Application application = tester.controllerTester().createApplication(slime); // Failure redeployer does not restart deployment - tester.failureRedeployer().maintain(); + tester.readyJobTrigger().maintain(); assertTrue("No jobs scheduled", tester.buildSystem().jobs().isEmpty()); } @@ -262,7 +262,7 @@ public class FailureRedeployerTest { tester.controllerTester().createApplication(slime); // Failure redeployer does not restart deployment - tester.failureRedeployer().maintain(); + tester.readyJobTrigger().maintain(); assertTrue("No jobs scheduled", tester.buildSystem().jobs().isEmpty()); } diff --git a/controller-server/src/test/java/com/yahoo/vespa/hosted/controller/maintenance/UpgraderTest.java b/controller-server/src/test/java/com/yahoo/vespa/hosted/controller/maintenance/UpgraderTest.java index e92d5400a3d..64082adc1c0 100644 --- a/controller-server/src/test/java/com/yahoo/vespa/hosted/controller/maintenance/UpgraderTest.java +++ b/controller-server/src/test/java/com/yahoo/vespa/hosted/controller/maintenance/UpgraderTest.java @@ -474,9 +474,9 @@ public class UpgraderTest { public void testBlockVersionChangeHalfwayThough() { ManualClock clock = new ManualClock(Instant.parse("2017-09-26T17:00:00.00Z")); // Tuesday, 17:00 DeploymentTester tester = new DeploymentTester(new ControllerTester(clock)); - BlockedChangeDeployer blockedChangeDeployer = new BlockedChangeDeployer(tester.controller(), - Duration.ofHours(1), - new JobControl(tester.controllerTester().curator())); + ReadyJobsTrigger readyJobsTrigger = new ReadyJobsTrigger(tester.controller(), + Duration.ofHours(1), + new JobControl(tester.controllerTester().curator())); Version version = Version.fromString("5.0"); tester.updateVersionStatus(version); @@ -506,12 +506,12 @@ public class UpgraderTest { // One hour passes, time is 19:00, still no upgrade tester.clock().advance(Duration.ofHours(1)); - blockedChangeDeployer.maintain(); + readyJobsTrigger.maintain(); assertTrue("No jobs scheduled", tester.buildSystem().jobs().isEmpty()); // Another hour pass, time is 20:00 and application upgrades tester.clock().advance(Duration.ofHours(1)); - blockedChangeDeployer.maintain(); + readyJobsTrigger.maintain(); tester.deployAndNotify(app, applicationPackage, true, DeploymentJobs.JobType.productionUsCentral1); tester.deployAndNotify(app, applicationPackage, true, DeploymentJobs.JobType.productionUsEast3); assertTrue("All jobs consumed", tester.buildSystem().jobs().isEmpty()); @@ -528,9 +528,9 @@ public class UpgraderTest { public void testBlockVersionChangeHalfwayThoughThenNewVersion() { ManualClock clock = new ManualClock(Instant.parse("2017-09-29T16:00:00.00Z")); // Friday, 16:00 DeploymentTester tester = new DeploymentTester(new ControllerTester(clock)); - BlockedChangeDeployer blockedChangeDeployer = new BlockedChangeDeployer(tester.controller(), - Duration.ofHours(1), - new JobControl(tester.controllerTester().curator())); + ReadyJobsTrigger readyJobsTrigger = new ReadyJobsTrigger(tester.controller(), + Duration.ofHours(1), + new JobControl(tester.controllerTester().curator())); Version version = Version.fromString("5.0"); tester.updateVersionStatus(version); @@ -565,14 +565,14 @@ public class UpgraderTest { version = Version.fromString("5.2"); tester.updateVersionStatus(version); tester.upgrader().maintain(); - blockedChangeDeployer.maintain(); + readyJobsTrigger.maintain(); assertTrue("Nothing is scheduled", tester.buildSystem().jobs().isEmpty()); // Monday morning: We are not blocked tester.clock().advance(Duration.ofDays(1)); // Sunday, 17:00 tester.clock().advance(Duration.ofHours(17)); // Monday, 10:00 tester.upgrader().maintain(); - blockedChangeDeployer.maintain(); + readyJobsTrigger.maintain(); // We proceed with the new version in the expected order, not starting with the previously blocked version: // Test jobs are run with the new version, but not production as we are in the block window tester.deployAndNotify(app, applicationPackage, true, DeploymentJobs.JobType.systemTest); diff --git a/controller-server/src/test/java/com/yahoo/vespa/hosted/controller/restapi/controller/responses/maintenance.json b/controller-server/src/test/java/com/yahoo/vespa/hosted/controller/restapi/controller/responses/maintenance.json index 3633860772b..33b9d4c70d5 100644 --- a/controller-server/src/test/java/com/yahoo/vespa/hosted/controller/restapi/controller/responses/maintenance.json +++ b/controller-server/src/test/java/com/yahoo/vespa/hosted/controller/restapi/controller/responses/maintenance.json @@ -1,19 +1,13 @@ { "jobs": [ { - "name": "DelayedDeployer" - }, - { - "name": "BlockedChangeDeployer" - }, - { - "name": "Upgrader" + "name": "ClusterInfoMaintainer" }, { - "name": "FailureRedeployer" + "name": "ClusterUtilizationMaintainer" }, { - "name": "VersionStatusUpdater" + "name": "DeploymentExpirer" }, { "name": "DeploymentIssueReporter" @@ -22,19 +16,19 @@ "name": "DeploymentMetricsMaintainer" }, { - "name": "OutstandingChangeDeployer" + "name": "MetricsReporter" }, { - "name": "ClusterUtilizationMaintainer" + "name": "OutstandingChangeDeployer" }, { - "name": "ClusterInfoMaintainer" + "name": "ReadyJobsTrigger" }, { - "name": "DeploymentExpirer" + "name": "Upgrader" }, { - "name": "MetricsReporter" + "name": "VersionStatusUpdater" } ], "inactive": [ -- cgit v1.2.3 From e0d6c64d3a81b482258bf55400494ee8be72e976 Mon Sep 17 00:00:00 2001 From: Jon Bratseth Date: Wed, 15 Nov 2017 12:48:39 +0100 Subject: Don't call initId --- .../java/com/yahoo/vespa/hosted/controller/maintenance/Maintainer.java | 1 - 1 file changed, 1 deletion(-) (limited to 'controller-server') diff --git a/controller-server/src/main/java/com/yahoo/vespa/hosted/controller/maintenance/Maintainer.java b/controller-server/src/main/java/com/yahoo/vespa/hosted/controller/maintenance/Maintainer.java index 1d19d8ca522..ebab2054d4f 100644 --- a/controller-server/src/main/java/com/yahoo/vespa/hosted/controller/maintenance/Maintainer.java +++ b/controller-server/src/main/java/com/yahoo/vespa/hosted/controller/maintenance/Maintainer.java @@ -30,7 +30,6 @@ public abstract class Maintainer extends AbstractComponent implements Runnable { private final ScheduledExecutorService service; public Maintainer(Controller controller, Duration interval, JobControl jobControl) { - initId(new ComponentId(name())); this.controller = controller; this.maintenanceInterval = interval; this.jobControl = jobControl; -- cgit v1.2.3 From d32d1da912bbaab4385836ed2204d66e83a32b5d Mon Sep 17 00:00:00 2001 From: Martin Polden Date: Thu, 16 Nov 2017 09:13:36 +0100 Subject: Remove unused ControllerCuratorDb --- .../persistence/ControllerCuratorDb.java | 69 ---------------------- 1 file changed, 69 deletions(-) delete mode 100644 controller-server/src/main/java/com/yahoo/vespa/hosted/controller/persistence/ControllerCuratorDb.java (limited to 'controller-server') diff --git a/controller-server/src/main/java/com/yahoo/vespa/hosted/controller/persistence/ControllerCuratorDb.java b/controller-server/src/main/java/com/yahoo/vespa/hosted/controller/persistence/ControllerCuratorDb.java deleted file mode 100644 index 53c152308d9..00000000000 --- a/controller-server/src/main/java/com/yahoo/vespa/hosted/controller/persistence/ControllerCuratorDb.java +++ /dev/null @@ -1,69 +0,0 @@ -// Copyright 2017 Yahoo Holdings. Licensed under the terms of the Apache 2.0 license. See LICENSE in the project root. -package com.yahoo.vespa.hosted.controller.persistence; - -import com.google.inject.Inject; -import com.yahoo.cloud.config.ClusterInfoConfig; -import com.yahoo.cloud.config.ZookeeperServerConfig; -import com.yahoo.net.HostName; -import com.yahoo.vespa.curator.Curator; -import com.yahoo.vespa.zookeeper.ZooKeeperServer; - -import java.util.stream.Collectors; - -/** - * A CuratorDb that configures its own ZooKeeper cluster - * - * @author bratseth - */ -// TODO: Remove when multi controller is enabled -@Deprecated -public class ControllerCuratorDb extends CuratorDb { - - /** Use a nonstandard zk port to avoid interfering with connection to the config server zk cluster */ - private static final int zooKeeperPort = 2281; - - @SuppressWarnings("unused") // This server is used (only) from the curator instance of this over the network */ - private final ZooKeeperServer zooKeeperServer; - - /** Create a curator db which also set up a ZooKeeper server (such that this instance is both client and server) */ - @Inject - public ControllerCuratorDb(ClusterInfoConfig clusterInfo) { - super(new Curator(toConnectionSpec(clusterInfo))); - this.zooKeeperServer = new ZooKeeperServer(toZookeeperServerConfig(clusterInfo)); - } - - private static ZookeeperServerConfig toZookeeperServerConfig(ClusterInfoConfig clusterInfo) { - ZookeeperServerConfig.Builder b = new ZookeeperServerConfig.Builder(); - b.zooKeeperConfigFile("conf/zookeeper/controller-zookeeper.cfg"); - b.dataDir("var/controller-zookeeper"); - b.clientPort(zooKeeperPort); - b.myidFile("var/controller-zookeeper/myid"); - b.myid(myIndex(clusterInfo)); - - for (ClusterInfoConfig.Services clusterMember : clusterInfo.services()) { - ZookeeperServerConfig.Server.Builder server = new ZookeeperServerConfig.Server.Builder(); - server.id(clusterMember.index()); - server.hostname(clusterMember.hostname()); - server.quorumPort(zooKeeperPort + 1); - server.electionPort(zooKeeperPort + 2); - b.server(server); - } - return new ZookeeperServerConfig(b); - } - - private static Integer myIndex(ClusterInfoConfig clusterInfo) { - String hostname = HostName.getLocalhost(); - return clusterInfo.services().stream() - .filter(service -> service.hostname().equals(hostname)) - .map(ClusterInfoConfig.Services::index) - .findFirst() - .orElseThrow(() -> new IllegalStateException("Unable to find index for this node by hostname '" + - hostname + "'")); - } - - private static String toConnectionSpec(ClusterInfoConfig clusterInfo) { - return clusterInfo.services().stream() - .map(member -> member.hostname() + ":" + zooKeeperPort) - .collect(Collectors.joining(",")); - } -} -- cgit v1.2.3