summaryrefslogtreecommitdiffstats
path: root/controller-server
diff options
context:
space:
mode:
authorMartin Polden <mpolden@mpolden.no>2019-01-04 15:36:43 +0100
committerMartin Polden <mpolden@mpolden.no>2019-01-07 09:46:33 +0100
commit7ff11c33a2a4e353f2306b1580ee9b7cd6164bd9 (patch)
tree437a31550f1f4642965ca8cea35f509b9467dcfe /controller-server
parent505753a6fd032c025197dcedb229721960a89eeb (diff)
Fix global rotation override
Removes guesswork and sends the correct identifier (upstream name) to the API on the config server.
Diffstat (limited to 'controller-server')
-rw-r--r--controller-server/src/main/java/com/yahoo/vespa/hosted/controller/ApplicationController.java104
-rw-r--r--controller-server/src/main/java/com/yahoo/vespa/hosted/controller/restapi/application/ApplicationApiHandler.java58
-rw-r--r--controller-server/src/test/java/com/yahoo/vespa/hosted/controller/ControllerTest.java66
-rw-r--r--controller-server/src/test/java/com/yahoo/vespa/hosted/controller/deployment/InternalDeploymentTester.java7
-rw-r--r--controller-server/src/test/java/com/yahoo/vespa/hosted/controller/deployment/InternalStepRunnerTest.java6
-rw-r--r--controller-server/src/test/java/com/yahoo/vespa/hosted/controller/integration/RoutingGeneratorMock.java21
-rw-r--r--controller-server/src/test/java/com/yahoo/vespa/hosted/controller/restapi/application/ApplicationApiTest.java23
-rw-r--r--controller-server/src/test/java/com/yahoo/vespa/hosted/controller/restapi/application/responses/global-rotation-delete.json2
-rw-r--r--controller-server/src/test/java/com/yahoo/vespa/hosted/controller/restapi/application/responses/global-rotation-get.json2
-rw-r--r--controller-server/src/test/java/com/yahoo/vespa/hosted/controller/restapi/application/responses/global-rotation-put.json2
10 files changed, 140 insertions, 151 deletions
diff --git a/controller-server/src/main/java/com/yahoo/vespa/hosted/controller/ApplicationController.java b/controller-server/src/main/java/com/yahoo/vespa/hosted/controller/ApplicationController.java
index eb86f0c2919..7214a371460 100644
--- a/controller-server/src/main/java/com/yahoo/vespa/hosted/controller/ApplicationController.java
+++ b/controller-server/src/main/java/com/yahoo/vespa/hosted/controller/ApplicationController.java
@@ -28,6 +28,7 @@ import com.yahoo.vespa.hosted.controller.api.integration.configserver.NoInstance
import com.yahoo.vespa.hosted.controller.api.integration.configserver.Node;
import com.yahoo.vespa.hosted.controller.api.integration.configserver.PrepareResponse;
import com.yahoo.vespa.hosted.controller.api.integration.deployment.ApplicationStore;
+import com.yahoo.vespa.hosted.controller.api.integration.deployment.ApplicationVersion;
import com.yahoo.vespa.hosted.controller.api.integration.deployment.ArtifactRepository;
import com.yahoo.vespa.hosted.controller.api.integration.deployment.JobType;
import com.yahoo.vespa.hosted.controller.api.integration.deployment.TesterId;
@@ -40,7 +41,6 @@ import com.yahoo.vespa.hosted.controller.api.integration.routing.RoutingEndpoint
import com.yahoo.vespa.hosted.controller.api.integration.routing.RoutingGenerator;
import com.yahoo.vespa.hosted.controller.api.integration.zone.ZoneId;
import com.yahoo.vespa.hosted.controller.application.ApplicationPackage;
-import com.yahoo.vespa.hosted.controller.api.integration.deployment.ApplicationVersion;
import com.yahoo.vespa.hosted.controller.application.Deployment;
import com.yahoo.vespa.hosted.controller.application.JobList;
import com.yahoo.vespa.hosted.controller.application.JobStatus;
@@ -60,16 +60,14 @@ import com.yahoo.vespa.hosted.rotation.config.RotationsConfig;
import com.yahoo.yolean.Exceptions;
import java.io.IOException;
+import java.io.UncheckedIOException;
import java.net.URI;
-import java.net.URISyntaxException;
import java.time.Clock;
import java.time.Duration;
import java.time.Instant;
-import java.util.ArrayList;
import java.util.Collections;
import java.util.Comparator;
import java.util.EnumSet;
-import java.util.HashMap;
import java.util.HashSet;
import java.util.List;
import java.util.Map;
@@ -180,83 +178,35 @@ public class ApplicationController {
.orElse(controller.systemVersion());
}
- /**
- * Set the rotations marked as 'global' either 'in' or 'out of' service.
- *
- * @return The canonical endpoint altered if any
- * @throws IOException if rotation status cannot be updated
- */
- public List<String> setGlobalRotationStatus(DeploymentId deploymentId, EndpointStatus status) throws IOException {
- List<String> rotations = new ArrayList<>();
- Optional<String> endpoint = getCanonicalGlobalEndpoint(deploymentId);
-
- if (endpoint.isPresent()) {
- configServer.setGlobalRotationStatus(deploymentId, endpoint.get(), status);
- rotations.add(endpoint.get());
- }
-
- return rotations;
- }
-
- /**
- * Get the endpoint status for the global endpoint of this application
- *
- * @return Map between the endpoint and the rotation status
- * @throws IOException if global rotation status cannot be determined
- */
- public Map<String, EndpointStatus> getGlobalRotationStatus(DeploymentId deploymentId) throws IOException {
- Map<String, EndpointStatus> result = new HashMap<>();
- Optional<String> endpoint = getCanonicalGlobalEndpoint(deploymentId);
-
- if (endpoint.isPresent()) {
- EndpointStatus status = configServer.getGlobalRotationStatus(deploymentId, endpoint.get());
- result.put(endpoint.get(), status);
- }
-
- return result;
+ /** Change the global endpoint status for given deployment */
+ public void setGlobalRotationStatus(DeploymentId deployment, EndpointStatus status) {
+ findGlobalEndpoint(deployment).map(endpoint -> {
+ try {
+ configServer.setGlobalRotationStatus(deployment, endpoint.upstreamName(), status);
+ return endpoint;
+ } catch (IOException e) {
+ throw new UncheckedIOException("Failed to set rotation status of " + deployment, e);
+ }
+ }).orElseThrow(() -> new IllegalArgumentException("No global endpoint exists for " + deployment));
}
- /**
- * Global rotations (plural as we can have aliases) map to exactly one service endpoint.
- * This method finds that one service endpoint and strips the URI part that
- * the routingGenerator is wrapping around the endpoint.
- *
- * @param deploymentId The deployment to retrieve global service endpoint for
- * @return Empty if no global endpoint exist, otherwise the service endpoint ([clustername.]app.tenant.region.env)
- */
- Optional<String> getCanonicalGlobalEndpoint(DeploymentId deploymentId) throws IOException {
- Map<String, RoutingEndpoint> hostToGlobalEndpoint = new HashMap<>();
- Map<String, String> hostToCanonicalEndpoint = new HashMap<>();
-
- for (RoutingEndpoint endpoint : routingGenerator.endpoints(deploymentId)) {
+ /** Get global endpoint status for given deployment */
+ public Map<RoutingEndpoint, EndpointStatus> globalRotationStatus(DeploymentId deployment) {
+ return findGlobalEndpoint(deployment).map(endpoint -> {
try {
- URI uri = new URI(endpoint.getEndpoint());
- String serviceEndpoint = uri.getHost();
- if (serviceEndpoint == null) {
- throw new IOException("Unexpected endpoints returned from the Routing Generator");
- }
- String canonicalEndpoint = serviceEndpoint
- .replaceAll(".vespa.yahooapis.com", "")
- .replaceAll(".vespa.oath.cloud", "");
- String hostname = endpoint.getHostname();
-
- // Book-keeping
- if (endpoint.isGlobal()) {
- hostToGlobalEndpoint.put(hostname, endpoint);
- } else {
- hostToCanonicalEndpoint.put(hostname, canonicalEndpoint);
- }
-
- // Return as soon as we have a map between a global and a canonical endpoint
- if (hostToGlobalEndpoint.containsKey(hostname) && hostToCanonicalEndpoint.containsKey(hostname)) {
- return Optional.of(hostToCanonicalEndpoint.get(hostname));
- }
- } catch (URISyntaxException use) {
- throw new IOException(use);
+ EndpointStatus status = configServer.getGlobalRotationStatus(deployment, endpoint.upstreamName());
+ return Collections.singletonMap(endpoint, status);
+ } catch (IOException e) {
+ throw new UncheckedIOException("Failed to get rotation status of " + deployment, e);
}
- }
+ }).orElseGet(Collections::emptyMap);
+ }
- return Optional.empty();
+ /** Find the global endpoint of given deployment, if any */
+ public Optional<RoutingEndpoint> findGlobalEndpoint(DeploymentId deployment) {
+ return routingGenerator.endpoints(deployment).stream()
+ .filter(RoutingEndpoint::isGlobal)
+ .findFirst();
}
/**
@@ -553,7 +503,7 @@ public class ApplicationController {
try {
return Optional.of(ImmutableList.copyOf(routingGenerator.endpoints(deploymentId).stream()
- .map(RoutingEndpoint::getEndpoint)
+ .map(RoutingEndpoint::endpoint)
.map(URI::create)
.iterator()));
}
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 cfd36a25de8..57694517c3b 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
@@ -53,6 +53,7 @@ import com.yahoo.vespa.hosted.controller.api.integration.deployment.ApplicationV
import com.yahoo.vespa.hosted.controller.api.integration.deployment.JobType;
import com.yahoo.vespa.hosted.controller.api.integration.deployment.RunId;
import com.yahoo.vespa.hosted.controller.api.integration.deployment.SourceRevision;
+import com.yahoo.vespa.hosted.controller.api.integration.routing.RoutingEndpoint;
import com.yahoo.vespa.hosted.controller.api.integration.zone.ZoneId;
import com.yahoo.vespa.hosted.controller.application.ApplicationPackage;
import com.yahoo.vespa.hosted.controller.application.Change;
@@ -590,31 +591,26 @@ public class ApplicationApiHandler extends LoggingRequestHandler {
}
private HttpResponse setGlobalRotationOverride(String tenantName, String applicationName, String instanceName, String environment, String region, boolean inService, HttpRequest request) {
-
- // Check if request is authorized
- Optional<Tenant> existingTenant = controller.tenants().tenant(tenantName);
- if (!existingTenant.isPresent())
- return ErrorResponse.notFoundError("Tenant '" + tenantName + "' does not exist");
-
-
- // Decode payload (reason) and construct parameter to the configserver
+ Application application = controller.applications().require(ApplicationId.from(tenantName, applicationName, instanceName));
+ ZoneId zone = ZoneId.from(environment, region);
+ Deployment deployment = application.deployments().get(zone);
+ if (deployment == null) {
+ throw new NotExistsException(application + " has no deployment in " + zone);
+ }
Inspector requestData = toSlime(request.getData()).get();
String reason = mandatory("reason", requestData).asString();
String agent = getUserPrincipal(request).getIdentity().getFullName();
long timestamp = controller.clock().instant().getEpochSecond();
EndpointStatus.Status status = inService ? EndpointStatus.Status.in : EndpointStatus.Status.out;
- EndpointStatus endPointStatus = new EndpointStatus(status, reason, agent, timestamp);
-
- // DeploymentId identifies the zone and application we are dealing with
- DeploymentId deploymentId = new DeploymentId(ApplicationId.from(tenantName, applicationName, instanceName),
- ZoneId.from(environment, region));
- try {
- List<String> rotations = controller.applications().setGlobalRotationStatus(deploymentId, endPointStatus);
- return new MessageResponse(String.format("Rotations %s successfully set to %s service", rotations.toString(), inService ? "in" : "out of"));
- } catch (IOException e) {
- return ErrorResponse.internalServerError("Unable to alter rotation status: " + e.getMessage());
- }
+ EndpointStatus endpointStatus = new EndpointStatus(status, reason, agent, timestamp);
+ controller.applications().setGlobalRotationStatus(new DeploymentId(application.id(), deployment.zone()),
+ endpointStatus);
+ return new MessageResponse(String.format("Successfully set %s in %s.%s %s service",
+ application.id().toShortString(),
+ deployment.zone().environment().value(),
+ deployment.zone().region().value(),
+ inService ? "in" : "out of"));
}
private HttpResponse getGlobalRotationOverride(String tenantName, String applicationName, String instanceName, String environment, String region) {
@@ -623,20 +619,16 @@ public class ApplicationApiHandler extends LoggingRequestHandler {
ZoneId.from(environment, region));
Slime slime = new Slime();
- Cursor c1 = slime.setObject().setArray("globalrotationoverride");
- try {
- Map<String, EndpointStatus> rotations = controller.applications().getGlobalRotationStatus(deploymentId);
- for (String rotation : rotations.keySet()) {
- EndpointStatus currentStatus = rotations.get(rotation);
- c1.addString(rotation);
- Cursor c2 = c1.addObject();
- c2.setString("status", currentStatus.getStatus().name());
- c2.setString("reason", currentStatus.getReason() == null ? "" : currentStatus.getReason());
- c2.setString("agent", currentStatus.getAgent() == null ? "" : currentStatus.getAgent());
- c2.setLong("timestamp", currentStatus.getEpoch());
- }
- } catch (IOException e) {
- return ErrorResponse.internalServerError("Unable to get rotation status: " + e.getMessage());
+ Cursor array = slime.setObject().setArray("globalrotationoverride");
+ Map<RoutingEndpoint, EndpointStatus> status = controller.applications().globalRotationStatus(deploymentId);
+ for (RoutingEndpoint endpoint : status.keySet()) {
+ EndpointStatus currentStatus = status.get(endpoint);
+ array.addString(endpoint.upstreamName());
+ Cursor statusObject = array.addObject();
+ statusObject.setString("status", currentStatus.getStatus().name());
+ statusObject.setString("reason", currentStatus.getReason() == null ? "" : currentStatus.getReason());
+ statusObject.setString("agent", currentStatus.getAgent() == null ? "" : currentStatus.getAgent());
+ statusObject.setLong("timestamp", currentStatus.getEpoch());
}
return new SlimeJsonResponse(slime);
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 25a051e192f..b7a881c672e 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
@@ -15,15 +15,16 @@ import com.yahoo.vespa.athenz.api.OktaAccessToken;
import com.yahoo.vespa.hosted.controller.api.application.v4.model.DeployOptions;
import com.yahoo.vespa.hosted.controller.api.application.v4.model.EndpointStatus;
import com.yahoo.vespa.hosted.controller.api.identifiers.DeploymentId;
+import com.yahoo.vespa.hosted.controller.api.integration.deployment.ApplicationVersion;
+import com.yahoo.vespa.hosted.controller.api.integration.deployment.SourceRevision;
import com.yahoo.vespa.hosted.controller.api.integration.dns.Record;
import com.yahoo.vespa.hosted.controller.api.integration.dns.RecordName;
+import com.yahoo.vespa.hosted.controller.api.integration.routing.RoutingEndpoint;
import com.yahoo.vespa.hosted.controller.api.integration.zone.ZoneId;
import com.yahoo.vespa.hosted.controller.application.ApplicationPackage;
-import com.yahoo.vespa.hosted.controller.api.integration.deployment.ApplicationVersion;
import com.yahoo.vespa.hosted.controller.application.Deployment;
import com.yahoo.vespa.hosted.controller.application.DeploymentJobs.JobError;
import com.yahoo.vespa.hosted.controller.application.JobStatus;
-import com.yahoo.vespa.hosted.controller.api.integration.deployment.SourceRevision;
import com.yahoo.vespa.hosted.controller.deployment.ApplicationPackageBuilder;
import com.yahoo.vespa.hosted.controller.deployment.BuildJob;
import com.yahoo.vespa.hosted.controller.deployment.DeploymentTester;
@@ -31,16 +32,17 @@ import com.yahoo.vespa.hosted.controller.rotation.RotationId;
import com.yahoo.vespa.hosted.controller.rotation.RotationLock;
import org.junit.Test;
-import java.io.IOException;
import java.time.Duration;
-import java.util.List;
+import java.util.Arrays;
import java.util.Map;
import java.util.Optional;
+import java.util.function.Function;
+import java.util.function.Supplier;
import static com.yahoo.config.provision.SystemName.main;
import static com.yahoo.vespa.hosted.controller.api.integration.deployment.JobType.component;
-import static com.yahoo.vespa.hosted.controller.api.integration.deployment.JobType.productionUsWest1;
import static com.yahoo.vespa.hosted.controller.api.integration.deployment.JobType.productionUsEast3;
+import static com.yahoo.vespa.hosted.controller.api.integration.deployment.JobType.productionUsWest1;
import static com.yahoo.vespa.hosted.controller.api.integration.deployment.JobType.stagingTest;
import static com.yahoo.vespa.hosted.controller.api.integration.deployment.JobType.systemTest;
import static java.time.temporal.ChronoUnit.MILLIS;
@@ -218,29 +220,51 @@ public class ControllerTest {
}
@Test
- public void testGlobalRotations() throws IOException {
- // Setup tester and app def
+ public void testGlobalRotations() {
+ // Setup
ControllerTester tester = new ControllerTester();
ZoneId zone = ZoneId.from(Environment.defaultEnvironment(), RegionName.defaultName());
- ApplicationId appId = ApplicationId.from("tenant", "app1", "default");
- DeploymentId deployId = new DeploymentId(appId, zone);
+ ApplicationId app = ApplicationId.from("tenant", "app1", "default");
+ DeploymentId deployment = new DeploymentId(app, zone);
+ tester.routingGenerator().putEndpoints(deployment, Arrays.asList(
+ new RoutingEndpoint("http://old-endpoint.vespa.yahooapis.com:4080", "host1", false, "upstream2"),
+ new RoutingEndpoint("http://qrs-endpoint.vespa.yahooapis.com:4080", "host1", false, "upstream1"),
+ new RoutingEndpoint("http://feeding-endpoint.vespa.yahooapis.com:4080", "host2", false, "upstream3"),
+ new RoutingEndpoint("http://global-endpoint.vespa.yahooapis.com:4080", "host1", true, "upstream1"),
+ new RoutingEndpoint("http://alias-endpoint.vespa.yahooapis.com:4080", "host1", true, "upstream1")
+ ));
+
+ Supplier<Map<RoutingEndpoint, EndpointStatus>> rotationStatus = () -> tester.controller().applications().globalRotationStatus(deployment);
+ Function<String, Optional<EndpointStatus>> findStatusByUpstream = (upstreamName) -> {
+ return rotationStatus.get()
+ .entrySet().stream()
+ .filter(kv -> kv.getKey().upstreamName().equals(upstreamName))
+ .findFirst()
+ .map(Map.Entry::getValue);
+ };
// Check initial rotation status
- Map<String, EndpointStatus> rotationStatus = tester.controller().applications().getGlobalRotationStatus(deployId);
- assertEquals(1, rotationStatus.size());
-
- assertEquals(rotationStatus.get("qrs-endpoint").getStatus(), EndpointStatus.Status.in);
+ assertEquals(1, rotationStatus.get().size());
+ assertEquals(findStatusByUpstream.apply("upstream1").get().getStatus(), EndpointStatus.Status.in);
// Set the global rotations out of service
EndpointStatus status = new EndpointStatus(EndpointStatus.Status.out, "unit-test", "Test", tester.clock().instant().getEpochSecond());
- List<String> overrides = tester.controller().applications().setGlobalRotationStatus(deployId, status);
- assertEquals(1, overrides.size());
-
- // Recheck the override rotation status
- rotationStatus = tester.controller().applications().getGlobalRotationStatus(deployId);
- assertEquals(1, rotationStatus.size());
- assertEquals(rotationStatus.get("qrs-endpoint").getStatus(), EndpointStatus.Status.out);
- assertEquals("unit-test", rotationStatus.get("qrs-endpoint").getReason());
+ tester.controller().applications().setGlobalRotationStatus(deployment, status);
+ assertEquals(1, rotationStatus.get().size());
+ assertEquals(findStatusByUpstream.apply("upstream1").get().getStatus(), EndpointStatus.Status.out);
+ assertEquals("unit-test", findStatusByUpstream.apply("upstream1").get().getReason());
+
+ // Deployment without a global endpoint
+ tester.routingGenerator().putEndpoints(deployment, Arrays.asList(
+ new RoutingEndpoint("http://old-endpoint.vespa.yahooapis.com:4080", "host1", false, "upstream2"),
+ new RoutingEndpoint("http://qrs-endpoint.vespa.yahooapis.com:4080", "host1", false, "upstream1"),
+ new RoutingEndpoint("http://feeding-endpoint.vespa.yahooapis.com:4080", "host2", false, "upstream3")
+ ));
+ assertFalse("No global endpoint exists", findStatusByUpstream.apply("upstream1").isPresent());
+ try {
+ tester.controller().applications().setGlobalRotationStatus(deployment, status);
+ fail("Expected exception");
+ } catch (IllegalArgumentException ignored) {}
}
@Test
diff --git a/controller-server/src/test/java/com/yahoo/vespa/hosted/controller/deployment/InternalDeploymentTester.java b/controller-server/src/test/java/com/yahoo/vespa/hosted/controller/deployment/InternalDeploymentTester.java
index ebda3482a50..80cbbfa2c30 100644
--- a/controller-server/src/test/java/com/yahoo/vespa/hosted/controller/deployment/InternalDeploymentTester.java
+++ b/controller-server/src/test/java/com/yahoo/vespa/hosted/controller/deployment/InternalDeploymentTester.java
@@ -107,7 +107,12 @@ public class InternalDeploymentTester {
zone.region().value(),
zone.environment().value()),
"host1",
- false)));
+ false,
+ String.format("cluster1.%s.%s.%s.%s",
+ id.application().value(),
+ id.tenant().value(),
+ zone.region().value(),
+ zone.environment().value()))));
}
/**
diff --git a/controller-server/src/test/java/com/yahoo/vespa/hosted/controller/deployment/InternalStepRunnerTest.java b/controller-server/src/test/java/com/yahoo/vespa/hosted/controller/deployment/InternalStepRunnerTest.java
index bb4b4fae5a5..c5484e1db07 100644
--- a/controller-server/src/test/java/com/yahoo/vespa/hosted/controller/deployment/InternalStepRunnerTest.java
+++ b/controller-server/src/test/java/com/yahoo/vespa/hosted/controller/deployment/InternalStepRunnerTest.java
@@ -17,7 +17,6 @@ import com.yahoo.vespa.hosted.controller.api.integration.LogEntry;
import com.yahoo.vespa.hosted.controller.api.integration.deployment.JobType;
import com.yahoo.vespa.hosted.controller.api.integration.deployment.RunId;
import com.yahoo.vespa.hosted.controller.api.integration.deployment.TesterCloud;
-import com.yahoo.vespa.hosted.controller.api.integration.organization.Mail;
import com.yahoo.vespa.hosted.controller.api.integration.stubs.MockMailer;
import com.yahoo.vespa.hosted.controller.api.integration.zone.ZoneId;
import org.junit.Before;
@@ -32,7 +31,6 @@ import java.nio.file.Paths;
import java.time.Duration;
import java.util.Arrays;
import java.util.Collections;
-import java.util.List;
import java.util.Optional;
import static com.yahoo.vespa.hosted.controller.api.integration.LogEntry.Type.debug;
@@ -236,7 +234,7 @@ public class InternalStepRunnerTest {
RunId id = tester.startSystemTestTests();
tester.runner().run();
assertEquals(unfinished, tester.jobs().run(id).get().steps().get(Step.endTests));
- assertEquals(URI.create(tester.routing().endpoints(new DeploymentId(testerId.id(), JobType.systemTest.zone(tester.tester().controller().system()))).get(0).getEndpoint()),
+ assertEquals(URI.create(tester.routing().endpoints(new DeploymentId(testerId.id(), JobType.systemTest.zone(tester.tester().controller().system()))).get(0).endpoint()),
tester.cloud().testerUrl());
Inspector configObject = SlimeUtils.jsonToSlime(tester.cloud().config()).get();
assertEquals(appId.serializedForm(), configObject.field("application").asString());
@@ -245,7 +243,7 @@ public class InternalStepRunnerTest {
assertEquals(1, configObject.field("endpoints").children());
assertEquals(1, configObject.field("endpoints").field(JobType.systemTest.zone(tester.tester().controller().system()).value()).entries());
configObject.field("endpoints").field(JobType.systemTest.zone(tester.tester().controller().system()).value()).traverse((ArrayTraverser) (__, endpoint) ->
- assertEquals(tester.routing().endpoints(new DeploymentId(appId, JobType.systemTest.zone(tester.tester().controller().system()))).get(0).getEndpoint(), endpoint.asString()));
+ assertEquals(tester.routing().endpoints(new DeploymentId(appId, JobType.systemTest.zone(tester.tester().controller().system()))).get(0).endpoint(), endpoint.asString()));
long lastId = tester.jobs().details(id).get().lastId().getAsLong();
tester.cloud().add(new LogEntry(0, 123, info, "Ready!"));
diff --git a/controller-server/src/test/java/com/yahoo/vespa/hosted/controller/integration/RoutingGeneratorMock.java b/controller-server/src/test/java/com/yahoo/vespa/hosted/controller/integration/RoutingGeneratorMock.java
index 28b255e9d0a..7c32e593eec 100644
--- a/controller-server/src/test/java/com/yahoo/vespa/hosted/controller/integration/RoutingGeneratorMock.java
+++ b/controller-server/src/test/java/com/yahoo/vespa/hosted/controller/integration/RoutingGeneratorMock.java
@@ -19,27 +19,28 @@ import java.util.concurrent.ConcurrentHashMap;
*/
public class RoutingGeneratorMock implements RoutingGenerator {
- private final Map<DeploymentId, List<RoutingEndpoint>> allEndpoints = new ConcurrentHashMap<>();
+ private final Map<DeploymentId, List<RoutingEndpoint>> routingTable = new ConcurrentHashMap<>();
+
private static final List<RoutingEndpoint> defaultEndpoints =
- Arrays.asList(new RoutingEndpoint("http://old-endpoint.vespa.yahooapis.com:4080", "host1", false),
- new RoutingEndpoint("http://qrs-endpoint.vespa.yahooapis.com:4080", "host1", false),
- new RoutingEndpoint("http://feeding-endpoint.vespa.yahooapis.com:4080", "host2", false),
- new RoutingEndpoint("http://global-endpoint.vespa.yahooapis.com:4080", "host1", true),
- new RoutingEndpoint("http://alias-endpoint.vespa.yahooapis.com:4080", "host1", true));
+ Arrays.asList(new RoutingEndpoint("http://old-endpoint.vespa.yahooapis.com:4080", "host1", false, "upstream3"),
+ new RoutingEndpoint("http://qrs-endpoint.vespa.yahooapis.com:4080", "host1", false, "upstream1"),
+ new RoutingEndpoint("http://feeding-endpoint.vespa.yahooapis.com:4080", "host2", false, "upstream2"),
+ new RoutingEndpoint("http://global-endpoint.vespa.yahooapis.com:4080", "host1", true, "upstream1"),
+ new RoutingEndpoint("http://alias-endpoint.vespa.yahooapis.com:4080", "host1", true, "upstream1"));
@Override
public List<RoutingEndpoint> endpoints(DeploymentId deployment) {
- return allEndpoints.isEmpty()
+ return routingTable.isEmpty()
? defaultEndpoints
- : allEndpoints.getOrDefault(deployment, Collections.emptyList());
+ : routingTable.getOrDefault(deployment, Collections.emptyList());
}
public void putEndpoints(DeploymentId deployment, List<RoutingEndpoint> endpoints) {
- allEndpoints.put(deployment, endpoints);
+ routingTable.put(deployment, endpoints);
}
public void removeEndpoints(DeploymentId deployment) {
- allEndpoints.remove(deployment);
+ routingTable.remove(deployment);
}
}
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 22ef61839be..981972356a5 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
@@ -556,6 +556,25 @@ public class ApplicationApiTest extends ControllerContainerTest {
.submit();
setZoneInRotation("rotation-fqdn-1", ZoneId.from("prod", "us-west-1"));
+ // Invalid application fails
+ tester.assertResponse(request("/application/v4/tenant/tenant2/application/application2/environment/prod/region/us-west-1/instance/default/global-rotation", GET)
+ .userIdentity(USER_ID),
+ "{\"error-code\":\"BAD_REQUEST\",\"message\":\"tenant2.application2 not found\"}",
+ 400);
+
+ // Invalid deployment fails
+ tester.assertResponse(request("/application/v4/tenant/tenant1/application/application1/environment/prod/region/us-east-3/instance/default/global-rotation", GET)
+ .userIdentity(USER_ID),
+ "{\"error-code\":\"NOT_FOUND\",\"message\":\"application 'tenant1.application1' has no deployment in zone prod.us-east-3 in default\"}",
+ 404);
+
+ // Change status of non-existing deployment fails
+ tester.assertResponse(request("/application/v4/tenant/tenant1/application/application1/environment/prod/region/us-east-3/instance/default/global-rotation/override", PUT)
+ .userIdentity(USER_ID)
+ .data("{\"reason\":\"unit-test\"}"),
+ "{\"error-code\":\"NOT_FOUND\",\"message\":\"application 'tenant1.application1' has no deployment in zone prod.us-east-3 in default\"}",
+ 404);
+
// GET global rotation status
setZoneInRotation("rotation-fqdn-1", ZoneId.from("prod", "us-west-1"));
tester.assertResponse(request("/application/v4/tenant/tenant1/application/application1/environment/prod/region/us-west-1/instance/default/global-rotation", GET)
@@ -570,13 +589,13 @@ public class ApplicationApiTest extends ControllerContainerTest {
// SET global rotation override status
tester.assertResponse(request("/application/v4/tenant/tenant1/application/application1/environment/prod/region/us-west-1/instance/default/global-rotation/override", PUT)
.userIdentity(USER_ID)
- .data("{\"reason\":\"because i can\"}"),
+ .data("{\"reason\":\"unit-test\"}"),
new File("global-rotation-put.json"));
// DELETE global rotation override status
tester.assertResponse(request("/application/v4/tenant/tenant1/application/application1/environment/prod/region/us-west-1/instance/default/global-rotation/override", DELETE)
.userIdentity(USER_ID)
- .data("{\"reason\":\"because i can\"}"),
+ .data("{\"reason\":\"unit-test\"}"),
new File("global-rotation-delete.json"));
}
diff --git a/controller-server/src/test/java/com/yahoo/vespa/hosted/controller/restapi/application/responses/global-rotation-delete.json b/controller-server/src/test/java/com/yahoo/vespa/hosted/controller/restapi/application/responses/global-rotation-delete.json
index c7ee62a3fcc..048ddcbc5c5 100644
--- a/controller-server/src/test/java/com/yahoo/vespa/hosted/controller/restapi/application/responses/global-rotation-delete.json
+++ b/controller-server/src/test/java/com/yahoo/vespa/hosted/controller/restapi/application/responses/global-rotation-delete.json
@@ -1 +1 @@
-{"message":"Rotations [qrs-endpoint] successfully set to in service"} \ No newline at end of file
+{"message":"Successfully set tenant1.application1 in prod.us-west-1 in service"}
diff --git a/controller-server/src/test/java/com/yahoo/vespa/hosted/controller/restapi/application/responses/global-rotation-get.json b/controller-server/src/test/java/com/yahoo/vespa/hosted/controller/restapi/application/responses/global-rotation-get.json
index 5fe96bd4d78..860d6c49cdf 100644
--- a/controller-server/src/test/java/com/yahoo/vespa/hosted/controller/restapi/application/responses/global-rotation-get.json
+++ b/controller-server/src/test/java/com/yahoo/vespa/hosted/controller/restapi/application/responses/global-rotation-get.json
@@ -1 +1 @@
-{"globalrotationoverride":["qrs-endpoint",{"status":"in","reason":"","agent":"","timestamp":1497618757}]} \ No newline at end of file
+{"globalrotationoverride":["upstream1",{"status":"in","reason":"","agent":"","timestamp":1497618757}]}
diff --git a/controller-server/src/test/java/com/yahoo/vespa/hosted/controller/restapi/application/responses/global-rotation-put.json b/controller-server/src/test/java/com/yahoo/vespa/hosted/controller/restapi/application/responses/global-rotation-put.json
index abe9658d882..f67b8dd56d9 100644
--- a/controller-server/src/test/java/com/yahoo/vespa/hosted/controller/restapi/application/responses/global-rotation-put.json
+++ b/controller-server/src/test/java/com/yahoo/vespa/hosted/controller/restapi/application/responses/global-rotation-put.json
@@ -1 +1 @@
-{"message":"Rotations [qrs-endpoint] successfully set to out of service"} \ No newline at end of file
+{"message":"Successfully set tenant1.application1 in prod.us-west-1 out of service"}