summaryrefslogtreecommitdiffstats
path: root/controller-server
diff options
context:
space:
mode:
authorMartin Polden <mpolden@mpolden.no>2022-10-20 12:32:33 +0200
committerGitHub <noreply@github.com>2022-10-20 12:32:33 +0200
commit1912e2a98a8e564cfadd652cdf83b4b1e64908bb (patch)
treefd4a667f7579f022ee2ca156a216803914f4bb2e /controller-server
parent8a91e259064b40f2f5fde5f8233c9892446d105e (diff)
parentfe76c41b344b2b3fe67e97b700f97372a8a214f6 (diff)
Merge pull request #24512 from vespa-engine/jonmv/cross-instance-region-application-endpoints
Jonmv/cross instance region application endpoints
Diffstat (limited to 'controller-server')
-rw-r--r--controller-server/src/main/java/com/yahoo/vespa/hosted/controller/RoutingController.java35
-rw-r--r--controller-server/src/main/java/com/yahoo/vespa/hosted/controller/application/pkg/ApplicationPackageValidator.java43
-rw-r--r--controller-server/src/main/java/com/yahoo/vespa/hosted/controller/routing/RoutingPolicies.java34
-rw-r--r--controller-server/src/test/java/com/yahoo/vespa/hosted/controller/ControllerTest.java130
-rw-r--r--controller-server/src/test/java/com/yahoo/vespa/hosted/controller/certificate/EndpointCertificatesTest.java15
-rw-r--r--controller-server/src/test/java/com/yahoo/vespa/hosted/controller/deployment/ApplicationPackageBuilder.java19
-rw-r--r--controller-server/src/test/java/com/yahoo/vespa/hosted/controller/deployment/DeploymentTriggerTest.java20
-rw-r--r--controller-server/src/test/java/com/yahoo/vespa/hosted/controller/integration/ZoneRegistryMock.java6
-rw-r--r--controller-server/src/test/java/com/yahoo/vespa/hosted/controller/maintenance/OsVersionStatusUpdaterTest.java13
-rw-r--r--controller-server/src/test/java/com/yahoo/vespa/hosted/controller/restapi/controller/ControllerApiTest.java2
-rw-r--r--controller-server/src/test/java/com/yahoo/vespa/hosted/controller/restapi/controller/responses/maintenance.json3
-rw-r--r--controller-server/src/test/java/com/yahoo/vespa/hosted/controller/restapi/deployment/responses/root.json2
-rw-r--r--controller-server/src/test/java/com/yahoo/vespa/hosted/controller/restapi/routing/responses/discovery/environment.json3
-rw-r--r--controller-server/src/test/java/com/yahoo/vespa/hosted/controller/restapi/routing/responses/recursion/environment.json12
-rw-r--r--controller-server/src/test/java/com/yahoo/vespa/hosted/controller/routing/RoutingPoliciesTest.java146
15 files changed, 305 insertions, 178 deletions
diff --git a/controller-server/src/main/java/com/yahoo/vespa/hosted/controller/RoutingController.java b/controller-server/src/main/java/com/yahoo/vespa/hosted/controller/RoutingController.java
index 91bca1e481c..38c06e4dac2 100644
--- a/controller-server/src/main/java/com/yahoo/vespa/hosted/controller/RoutingController.java
+++ b/controller-server/src/main/java/com/yahoo/vespa/hosted/controller/RoutingController.java
@@ -55,6 +55,9 @@ import java.util.Set;
import java.util.TreeMap;
import java.util.stream.Collectors;
+import static java.util.stream.Collectors.groupingBy;
+import static java.util.stream.Collectors.toMap;
+
/**
* The routing controller encapsulates state and methods for inspecting and manipulating deployment endpoints in a
* hosted Vespa system.
@@ -155,21 +158,23 @@ public class RoutingController {
}
// Add application endpoints
for (var declaredEndpoint : deploymentSpec.endpoints()) {
- Map<DeploymentId, Integer> deployments = declaredEndpoint.targets().stream()
- .collect(Collectors.toMap(t -> new DeploymentId(application.id().instance(t.instance()),
- ZoneId.from(Environment.prod, t.region())),
- t -> t.weight()));
- // An application endpoint can only target a single zone, so we just pick the zone of any deployment target
- ZoneId zone = deployments.keySet().iterator().next().zoneId();
- // Application endpoints are only supported when using direct routing methods
- RoutingMethod routingMethod = usesSharedRouting(zone) ? RoutingMethod.sharedLayer4 : RoutingMethod.exclusive;
- endpoints.add(Endpoint.of(application.id())
- .targetApplication(EndpointId.of(declaredEndpoint.endpointId()),
- ClusterSpec.Id.from(declaredEndpoint.containerId()),
- deployments)
- .routingMethod(routingMethod)
- .on(Port.fromRoutingMethod(routingMethod))
- .in(controller.system()));
+ Map<ZoneId, Map<DeploymentId, Integer>> deployments = declaredEndpoint.targets().stream()
+ .collect(groupingBy(t -> ZoneId.from(Environment.prod, t.region()),
+ toMap(t -> new DeploymentId(application.id().instance(t.instance()),
+ ZoneId.from(Environment.prod, t.region())),
+ t -> t.weight())));
+
+ deployments.forEach((zone, weightedInstances) -> {
+ // Application endpoints are only supported when using direct routing methods
+ RoutingMethod routingMethod = usesSharedRouting(zone) ? RoutingMethod.sharedLayer4 : RoutingMethod.exclusive;
+ endpoints.add(Endpoint.of(application.id())
+ .targetApplication(EndpointId.of(declaredEndpoint.endpointId()),
+ ClusterSpec.Id.from(declaredEndpoint.containerId()),
+ weightedInstances)
+ .routingMethod(routingMethod)
+ .on(Port.fromRoutingMethod(routingMethod))
+ .in(controller.system()));
+ });
}
return EndpointList.copyOf(endpoints);
}
diff --git a/controller-server/src/main/java/com/yahoo/vespa/hosted/controller/application/pkg/ApplicationPackageValidator.java b/controller-server/src/main/java/com/yahoo/vespa/hosted/controller/application/pkg/ApplicationPackageValidator.java
index f72b6f2e9f0..4d29231f6d4 100644
--- a/controller-server/src/main/java/com/yahoo/vespa/hosted/controller/application/pkg/ApplicationPackageValidator.java
+++ b/controller-server/src/main/java/com/yahoo/vespa/hosted/controller/application/pkg/ApplicationPackageValidator.java
@@ -5,11 +5,13 @@ import com.yahoo.component.Version;
import com.yahoo.config.application.api.DeploymentInstanceSpec;
import com.yahoo.config.application.api.DeploymentSpec;
import com.yahoo.config.application.api.Endpoint;
+import com.yahoo.config.application.api.Endpoint.Level;
import com.yahoo.config.application.api.ValidationId;
import com.yahoo.config.application.api.ValidationOverrides;
import com.yahoo.config.provision.CloudName;
import com.yahoo.config.provision.Environment;
import com.yahoo.config.provision.InstanceName;
+import com.yahoo.config.provision.RegionName;
import com.yahoo.config.provision.zone.ZoneApi;
import com.yahoo.config.provision.zone.ZoneId;
import com.yahoo.vespa.hosted.controller.Application;
@@ -19,6 +21,7 @@ import com.yahoo.vespa.hosted.controller.versions.VespaVersion;
import java.time.Instant;
import java.util.ArrayList;
+import java.util.EnumSet;
import java.util.HashMap;
import java.util.HashSet;
import java.util.List;
@@ -90,22 +93,40 @@ public class ApplicationPackageValidator {
}
}
- /** Verify that no single endpoint contains regions in different clouds */
+ /** Verify that:
+ * <ul>
+ * <li>no single endpoint contains regions in different clouds</li>
+ * <li>application endpoints with different regions must be contained in CGP and AWS</li>
+ * </ul>
+ */
private void validateEndpointRegions(DeploymentSpec deploymentSpec) {
for (var instance : deploymentSpec.instances()) {
- for (var endpoint : instance.endpoints()) {
- var clouds = new HashSet<CloudName>();
- for (var region : endpoint.regions()) {
- for (ZoneApi zone : controller.zoneRegistry().zones().all().in(Environment.prod).in(region).zones()) {
- clouds.add(zone.getCloudName());
- }
- }
- if (clouds.size() != 1 && !clouds.equals(Set.of(CloudName.GCP, CloudName.AWS))) {
- throw new IllegalArgumentException("Endpoint '" + endpoint.endpointId() + "' in " + instance +
- " cannot contain regions in different clouds: " +
+ validateEndpointRegions(instance.endpoints(), instance);
+ }
+ validateEndpointRegions(deploymentSpec.endpoints(), null);
+ }
+
+ private void validateEndpointRegions(List<Endpoint> endpoints, DeploymentInstanceSpec instance) {
+ for (var endpoint : endpoints) {
+ RegionName[] regions = new HashSet<>(endpoint.regions()).toArray(RegionName[]::new);
+ Set<CloudName> clouds = controller.zoneRegistry().zones().all().in(Environment.prod)
+ .in(regions)
+ .zones().stream()
+ .map(ZoneApi::getCloudName)
+ .collect(Collectors.toSet());
+ String endpointString = instance == null ? "Application endpoint '" + endpoint.endpointId() + "'"
+ : "Endpoint '" + endpoint.endpointId() + "' in " + instance;
+ if (Set.of(CloudName.GCP, CloudName.AWS).containsAll(clouds)) { } // Everything is fine!
+ else if (Set.of(CloudName.DEFAULT).containsAll(clouds)) {
+ if (endpoint.level() == Level.application && regions.length != 1) {
+ throw new IllegalArgumentException(endpointString + " cannot contain different regions: " +
endpoint.regions().stream().sorted().toList());
}
}
+ else {
+ throw new IllegalArgumentException(endpointString + " cannot contain regions in different clouds: " +
+ endpoint.regions().stream().sorted().toList());
+ }
}
}
diff --git a/controller-server/src/main/java/com/yahoo/vespa/hosted/controller/routing/RoutingPolicies.java b/controller-server/src/main/java/com/yahoo/vespa/hosted/controller/routing/RoutingPolicies.java
index fc0badae9ea..27247c065ed 100644
--- a/controller-server/src/main/java/com/yahoo/vespa/hosted/controller/routing/RoutingPolicies.java
+++ b/controller-server/src/main/java/com/yahoo/vespa/hosted/controller/routing/RoutingPolicies.java
@@ -256,24 +256,22 @@ public class RoutingPolicies {
EndpointList endpoints = controller.routing().declaredEndpointsOf(application)
.scope(Endpoint.Scope.application)
.named(routingId.endpointId());
- if (endpoints.isEmpty()) continue;
- if (endpoints.size() > 1) {
- throw new IllegalArgumentException("Expected at most 1 endpoint with ID '" + routingId.endpointId() +
- ", got " + endpoints.size());
- }
- Endpoint endpoint = endpoints.asList().get(0);
- for (var policy : routeEntry.getValue()) {
- for (var target : endpoint.targets()) {
- if (!policy.appliesTo(target.deployment())) continue;
- if (policy.dnsZone().isEmpty() && policy.canonicalName().isPresent()) continue; // Does not support ALIAS records
- ZoneRoutingPolicy zonePolicy = db.readZoneRoutingPolicy(policy.id().zone());
-
- Set<Target> activeTargets = targetsByEndpoint.computeIfAbsent(endpoint, (k) -> new LinkedHashSet<>());
- Set<Target> inactiveTargets = inactiveTargetsByEndpoint.computeIfAbsent(endpoint, (k) -> new LinkedHashSet<>());
- if (isConfiguredOut(zonePolicy, policy, inactiveZones)) {
- inactiveTargets.add(Target.weighted(policy, target));
- } else {
- activeTargets.add(Target.weighted(policy, target));
+ for (Endpoint endpoint : endpoints) {
+ for (var policy : routeEntry.getValue()) {
+ for (var target : endpoint.targets()) {
+ if (!policy.appliesTo(target.deployment())) continue;
+ if (policy.dnsZone().isEmpty() && policy.canonicalName().isPresent())
+ continue; // Does not support ALIAS records
+ ZoneRoutingPolicy zonePolicy = db.readZoneRoutingPolicy(policy.id().zone());
+
+ Set<Target> activeTargets = targetsByEndpoint.computeIfAbsent(endpoint, (k) -> new LinkedHashSet<>());
+ Set<Target> inactiveTargets = inactiveTargetsByEndpoint.computeIfAbsent(endpoint, (k) -> new LinkedHashSet<>());
+ if (isConfiguredOut(zonePolicy, policy, inactiveZones)) {
+ inactiveTargets.add(Target.weighted(policy, target));
+ }
+ else {
+ activeTargets.add(Target.weighted(policy, target));
+ }
}
}
}
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 cd3d6ca7531..43a4ac0f6fc 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
@@ -62,6 +62,7 @@ import java.util.Map;
import java.util.Optional;
import java.util.OptionalInt;
import java.util.Set;
+import java.util.TreeSet;
import java.util.function.Function;
import java.util.stream.Collectors;
import java.util.stream.Stream;
@@ -72,6 +73,7 @@ import static com.yahoo.vespa.hosted.controller.deployment.DeploymentContext.pro
import static com.yahoo.vespa.hosted.controller.deployment.DeploymentContext.productionUsWest1;
import static com.yahoo.vespa.hosted.controller.deployment.DeploymentContext.stagingTest;
import static com.yahoo.vespa.hosted.controller.deployment.DeploymentContext.systemTest;
+import static java.util.Comparator.comparing;
import static org.junit.jupiter.api.Assertions.assertArrayEquals;
import static org.junit.jupiter.api.Assertions.assertEquals;
import static org.junit.jupiter.api.Assertions.assertFalse;
@@ -344,7 +346,7 @@ public class ControllerTest {
List<String> globalDnsNames = tester.controller().routing().readDeclaredEndpointsOf(context.instanceId())
.scope(Endpoint.Scope.global)
- .sortedBy(Comparator.comparing(Endpoint::dnsName))
+ .sortedBy(comparing(Endpoint::dnsName))
.mapToList(Endpoint::dnsName);
assertEquals(List.of("app1.tenant1.global.vespa.oath.cloud"),
globalDnsNames);
@@ -636,63 +638,107 @@ public class ControllerTest {
var context = tester.newDeploymentContext(beta);
ApplicationPackage applicationPackage = new ApplicationPackageBuilder()
.instances("beta,main")
- .region("us-west-1")
.region("us-east-3")
- .applicationEndpoint("a", "default", "us-west-1",
- Map.of(beta.instance(), 2,
- main.instance(), 8))
- .applicationEndpoint("b", "default", "us-west-1",
- Map.of(beta.instance(), 1,
- main.instance(), 1))
- .applicationEndpoint("c", "default", "us-east-3",
- Map.of(beta.instance(), 4,
- main.instance(), 6))
+ .region("us-west-1")
+ .region("aws-us-east-1a")
+ .region("aws-us-east-1b")
+ .applicationEndpoint("a", "default",
+ Map.of("aws-us-east-1a", Map.of(beta.instance(), 2,
+ main.instance(), 8),
+ "aws-us-east-1b", Map.of(main.instance(), 1)))
+ .applicationEndpoint("b", "default", "aws-us-east-1a",
+ Map.of(beta.instance(), 1,
+ main.instance(), 1))
+ .applicationEndpoint("c", "default", "aws-us-east-1b",
+ Map.of(beta.instance(), 4))
+ .applicationEndpoint("d", "default", "us-west-1",
+ Map.of(main.instance(), 7,
+ beta.instance(), 3))
+ .applicationEndpoint("e", "default", "us-east-3",
+ Map.of(main.instance(), 3))
.build();
context.submit(applicationPackage).deploy();
- ZoneId usWest = ZoneId.from("prod", "us-west-1");
- ZoneId usEast = ZoneId.from("prod", "us-east-3");
+ ZoneId east3 = ZoneId.from("prod", "us-east-3");
+ ZoneId west1 = ZoneId.from("prod", "us-west-1");
+ ZoneId east1a = ZoneId.from("prod", "aws-us-east-1a");
+ ZoneId east1b = ZoneId.from("prod", "aws-us-east-1b");
// Expected container endpoints are passed to each deployment
Map<DeploymentId, Map<String, Integer>> deploymentEndpoints = Map.of(
- new DeploymentId(beta, usWest), Map.of("a.app1.tenant1.us-west-1-r.vespa.oath.cloud", 2,
- "b.app1.tenant1.us-west-1-r.vespa.oath.cloud", 1),
- new DeploymentId(main, usWest), Map.of("a.app1.tenant1.us-west-1-r.vespa.oath.cloud", 8,
- "b.app1.tenant1.us-west-1-r.vespa.oath.cloud", 1),
- new DeploymentId(beta, usEast), Map.of("c.app1.tenant1.us-east-3-r.vespa.oath.cloud", 4),
- new DeploymentId(main, usEast), Map.of("c.app1.tenant1.us-east-3-r.vespa.oath.cloud", 6)
+ new DeploymentId(beta, east3), Map.of(),
+ new DeploymentId(main, east3), Map.of("e.app1.tenant1.us-east-3-r.vespa.oath.cloud", 3),
+ new DeploymentId(beta, west1), Map.of("d.app1.tenant1.us-west-1-r.vespa.oath.cloud", 3),
+ new DeploymentId(main, west1), Map.of("d.app1.tenant1.us-west-1-r.vespa.oath.cloud", 7),
+ new DeploymentId(beta, east1a), Map.of("a.app1.tenant1.aws-us-east-1a-r.vespa.oath.cloud", 2,
+ "b.app1.tenant1.aws-us-east-1a-r.vespa.oath.cloud", 1),
+ new DeploymentId(main, east1a), Map.of("a.app1.tenant1.aws-us-east-1a-r.vespa.oath.cloud", 8,
+ "b.app1.tenant1.aws-us-east-1a-r.vespa.oath.cloud", 1),
+ new DeploymentId(beta, east1b), Map.of("c.app1.tenant1.aws-us-east-1b-r.vespa.oath.cloud", 4),
+ new DeploymentId(main, east1b), Map.of("a.app1.tenant1.aws-us-east-1b-r.vespa.oath.cloud", 1)
);
deploymentEndpoints.forEach((deployment, endpoints) -> {
Set<ContainerEndpoint> expected = endpoints.entrySet().stream()
- .map(kv -> new ContainerEndpoint("default", "application",
- List.of(kv.getKey()),
- OptionalInt.of(kv.getValue()),
- RoutingMethod.sharedLayer4))
- .collect(Collectors.toSet());
+ .map(kv -> new ContainerEndpoint("default", "application",
+ List.of(kv.getKey()),
+ OptionalInt.of(kv.getValue()),
+ tester.controller().zoneRegistry().routingMethod(deployment.zoneId())))
+ .collect(Collectors.toSet());
assertEquals(expected,
- tester.configServer().containerEndpoints().get(deployment),
- "Endpoint names for " + deployment + " are passed to config server");
+ tester.configServer().containerEndpoints().get(deployment),
+ "Endpoint names for " + deployment + " are passed to config server");
});
context.flushDnsUpdates();
// DNS records are created for each endpoint
Set<Record> records = tester.controllerTester().nameService().records();
- assertEquals(Set.of(new Record(Record.Type.CNAME,
- RecordName.from("a.app1.tenant1.us-west-1-r.vespa.oath.cloud"),
- RecordData.from("vip.prod.us-west-1.")),
- new Record(Record.Type.CNAME,
- RecordName.from("b.app1.tenant1.us-west-1-r.vespa.oath.cloud"),
- RecordData.from("vip.prod.us-west-1.")),
- new Record(Record.Type.CNAME,
- RecordName.from("c.app1.tenant1.us-east-3-r.vespa.oath.cloud"),
- RecordData.from("vip.prod.us-east-3."))),
- records);
+ assertEquals(new TreeSet<>(Set.of(new Record(Record.Type.CNAME,
+ RecordName.from("beta.app1.tenant1.aws-us-east-1a.vespa.oath.cloud"),
+ RecordData.from("lb-0--tenant1.app1.beta--prod.aws-us-east-1a.")),
+ new Record(Record.Type.CNAME,
+ RecordName.from("beta.app1.tenant1.aws-us-east-1b.vespa.oath.cloud"),
+ RecordData.from("lb-0--tenant1.app1.beta--prod.aws-us-east-1b.")),
+ new Record(Record.Type.CNAME,
+ RecordName.from("main.app1.tenant1.aws-us-east-1a.vespa.oath.cloud"),
+ RecordData.from("lb-0--tenant1.app1.main--prod.aws-us-east-1a.")),
+ new Record(Record.Type.CNAME,
+ RecordName.from("main.app1.tenant1.aws-us-east-1b.vespa.oath.cloud"),
+ RecordData.from("lb-0--tenant1.app1.main--prod.aws-us-east-1b.")),
+ new Record(Record.Type.ALIAS,
+ RecordName.from("a.app1.tenant1.aws-us-east-1a-r.vespa.oath.cloud"),
+ RecordData.from("weighted/lb-0--tenant1.app1.beta--prod.aws-us-east-1a/dns-zone-1/prod.aws-us-east-1a/2")),
+ new Record(Record.Type.ALIAS,
+ RecordName.from("a.app1.tenant1.aws-us-east-1a-r.vespa.oath.cloud"),
+ RecordData.from("weighted/lb-0--tenant1.app1.main--prod.aws-us-east-1a/dns-zone-1/prod.aws-us-east-1a/8")),
+ new Record(Record.Type.ALIAS,
+ RecordName.from("a.app1.tenant1.aws-us-east-1b-r.vespa.oath.cloud"),
+ RecordData.from("weighted/lb-0--tenant1.app1.main--prod.aws-us-east-1b/dns-zone-1/prod.aws-us-east-1b/1")),
+ new Record(Record.Type.ALIAS,
+ RecordName.from("b.app1.tenant1.aws-us-east-1a-r.vespa.oath.cloud"),
+ RecordData.from("weighted/lb-0--tenant1.app1.beta--prod.aws-us-east-1a/dns-zone-1/prod.aws-us-east-1a/1")),
+ new Record(Record.Type.ALIAS,
+ RecordName.from("b.app1.tenant1.aws-us-east-1a-r.vespa.oath.cloud"),
+ RecordData.from("weighted/lb-0--tenant1.app1.main--prod.aws-us-east-1a/dns-zone-1/prod.aws-us-east-1a/1")),
+ new Record(Record.Type.ALIAS,
+ RecordName.from("c.app1.tenant1.aws-us-east-1b-r.vespa.oath.cloud"),
+ RecordData.from("weighted/lb-0--tenant1.app1.beta--prod.aws-us-east-1b/dns-zone-1/prod.aws-us-east-1b/4")),
+ new Record(Record.Type.CNAME,
+ RecordName.from("d.app1.tenant1.us-west-1-r.vespa.oath.cloud"),
+ RecordData.from("vip.prod.us-west-1.")),
+ new Record(Record.Type.CNAME,
+ RecordName.from("e.app1.tenant1.us-east-3-r.vespa.oath.cloud"),
+ RecordData.from("vip.prod.us-east-3.")))),
+ new TreeSet<>(records));
List<String> endpointDnsNames = tester.controller().routing().declaredEndpointsOf(context.application())
- .scope(Endpoint.Scope.application)
- .mapToList(Endpoint::dnsName);
- assertEquals(List.of("a.app1.tenant1.us-west-1-r.vespa.oath.cloud",
- "b.app1.tenant1.us-west-1-r.vespa.oath.cloud",
- "c.app1.tenant1.us-east-3-r.vespa.oath.cloud"),
- endpointDnsNames);
+ .scope(Endpoint.Scope.application)
+ .sortedBy(comparing(Endpoint::dnsName))
+ .mapToList(Endpoint::dnsName);
+ assertEquals(List.of("a.app1.tenant1.aws-us-east-1a-r.vespa.oath.cloud",
+ "a.app1.tenant1.aws-us-east-1b-r.vespa.oath.cloud",
+ "b.app1.tenant1.aws-us-east-1a-r.vespa.oath.cloud",
+ "c.app1.tenant1.aws-us-east-1b-r.vespa.oath.cloud",
+ "d.app1.tenant1.us-west-1-r.vespa.oath.cloud",
+ "e.app1.tenant1.us-east-3-r.vespa.oath.cloud"),
+ endpointDnsNames);
}
@Test
diff --git a/controller-server/src/test/java/com/yahoo/vespa/hosted/controller/certificate/EndpointCertificatesTest.java b/controller-server/src/test/java/com/yahoo/vespa/hosted/controller/certificate/EndpointCertificatesTest.java
index 274cf3c5867..b06b4eb0cfa 100644
--- a/controller-server/src/test/java/com/yahoo/vespa/hosted/controller/certificate/EndpointCertificatesTest.java
+++ b/controller-server/src/test/java/com/yahoo/vespa/hosted/controller/certificate/EndpointCertificatesTest.java
@@ -191,7 +191,7 @@ public class EndpointCertificatesTest {
@Test
void reprovisions_certificate_with_added_sans_when_deploying_to_new_zone() {
- ZoneId testZone = tester.zoneRegistry().zones().all().routingMethod(RoutingMethod.exclusive).in(Environment.prod).zones().stream().skip(1).findFirst().orElseThrow().getId();
+ ZoneId testZone = ZoneId.from("prod.ap-northeast-1");
mockCuratorDb.writeEndpointCertificateMetadata(testInstance.id(), new EndpointCertificateMetadata(testKeyName, testCertName, -1, 0, "original-request-uuid", Optional.of("leaf-request-uuid"), expectedSans, "mockCa", Optional.empty(), Optional.empty()));
secretStore.setSecret("vespa.tls.default.default.default-key", KeyUtils.toPem(testKeyPair.getPrivate()), -1);
@@ -243,14 +243,13 @@ public class EndpointCertificatesTest {
.region(zone1.region())
.region(zone2.region())
.applicationEndpoint("a", "qrs", zone2.region().value(),
- Map.of(InstanceName.from("beta"), 2,
- InstanceName.from("main"), 8))
+ Map.of(InstanceName.from("beta"), 2))
.applicationEndpoint("b", "qrs", zone2.region().value(),
- Map.of(InstanceName.from("beta"), 1,
- InstanceName.from("main"), 1))
- .applicationEndpoint("c", "qrs", zone1.region().value(),
- Map.of(InstanceName.from("beta"), 4,
- InstanceName.from("main"), 6))
+ Map.of(InstanceName.from("beta"), 1))
+ .applicationEndpoint("c", "qrs",
+ Map.of(zone1.region().value(), Map.of(InstanceName.from("beta"), 4,
+ InstanceName.from("main"), 6),
+ zone2.region().value(), Map.of(InstanceName.from("main"), 2)))
.build();
ControllerTester tester = new ControllerTester(SystemName.Public);
EndpointCertificateValidatorImpl endpointCertificateValidator = new EndpointCertificateValidatorImpl(secretStore, clock);
diff --git a/controller-server/src/test/java/com/yahoo/vespa/hosted/controller/deployment/ApplicationPackageBuilder.java b/controller-server/src/test/java/com/yahoo/vespa/hosted/controller/deployment/ApplicationPackageBuilder.java
index 7909651716a..7fb85af0d4a 100644
--- a/controller-server/src/test/java/com/yahoo/vespa/hosted/controller/deployment/ApplicationPackageBuilder.java
+++ b/controller-server/src/test/java/com/yahoo/vespa/hosted/controller/deployment/ApplicationPackageBuilder.java
@@ -120,17 +120,24 @@ public class ApplicationPackageBuilder {
public ApplicationPackageBuilder applicationEndpoint(String id, String containerId, String region,
Map<InstanceName, Integer> instanceWeights) {
+ return applicationEndpoint(id, containerId, Map.of(region, instanceWeights));
+ }
+
+ public ApplicationPackageBuilder applicationEndpoint(String id, String containerId,
+ Map<String, Map<InstanceName, Integer>> instanceWeights) {
if (instanceWeights.isEmpty()) throw new IllegalArgumentException("At least one instance must be given");
applicationEndpointsBody.append(" <endpoint");
applicationEndpointsBody.append(" id='").append(id).append("'");
applicationEndpointsBody.append(" container-id='").append(containerId).append("'");
- applicationEndpointsBody.append(" region='").append(region).append("'");
applicationEndpointsBody.append(">\n");
- for (var kv : new TreeMap<>(instanceWeights).entrySet()) {
- applicationEndpointsBody.append(" <instance weight='").append(kv.getValue().toString()).append("'>")
- .append(kv.getKey().value())
- .append("</instance>\n");
- }
+ new TreeMap<>(instanceWeights).forEach((region, instances) -> {
+ new TreeMap<>(instances).forEach((instance, weight) -> {
+ applicationEndpointsBody.append(" <instance weight='").append(weight.toString()).append("' region='").append(region).append("'>")
+ .append(instance)
+ .append("</instance>\n");
+
+ });
+ });
applicationEndpointsBody.append(" </endpoint>\n");
return this;
}
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 73630488969..6d1e5cebe0e 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
@@ -1305,11 +1305,11 @@ public class DeploymentTriggerTest {
</steps>
<steps>
<delay hours='3' />
- <region active='true'>aws-us-east-1a</region>
+ <region active='true'>us-central-1</region>
<parallel>
<region active='true' athenz-service='no-service'>ap-northeast-1</region>
<region active='true'>ap-northeast-2</region>
- <test>aws-us-east-1a</test>
+ <test>us-central-1</test>
</parallel>
</steps>
<delay hours='3' minutes='30' />
@@ -1388,10 +1388,10 @@ public class DeploymentTriggerTest {
assertEquals(List.of(), tester.jobs().active());
tester.clock().advance(Duration.ofHours(1));
- app1.runJob(productionAwsUsEast1a);
+ app1.runJob(productionUsCentral1);
tester.triggerJobs();
assertEquals(3, tester.jobs().active().size());
- app1.runJob(testAwsUsEast1a);
+ app1.runJob(testUsCentral1);
tester.triggerJobs();
assertEquals(2, tester.jobs().active().size());
app1.runJob(productionApNortheast2);
@@ -1448,11 +1448,11 @@ public class DeploymentTriggerTest {
tester.clock().advance(Duration.ofHours(2));
app1.runJob(productionEuWest1);
tester.clock().advance(Duration.ofHours(1));
- app1.runJob(productionAwsUsEast1a);
- app1.runJob(testAwsUsEast1a);
+ app1.runJob(productionUsCentral1);
+ app1.runJob(testUsCentral1);
tester.clock().advance(Duration.ofSeconds(1));
- app1.runJob(productionAwsUsEast1a); // R
- app1.runJob(testAwsUsEast1a); // R
+ app1.runJob(productionUsCentral1); // R
+ app1.runJob(testUsCentral1); // R
app1.runJob(productionApNortheast2);
app1.runJob(productionApNortheast1);
tester.clock().advance(Duration.ofHours(1));
@@ -1996,8 +1996,8 @@ public class DeploymentTriggerTest {
@Test
void mixedDirectAndPipelineJobsInProduction() {
ApplicationPackage cdPackage = new ApplicationPackageBuilder().region("us-east-3")
- .region("aws-us-east-1a")
- .build();
+ .region("aws-us-east-1a")
+ .build();
ControllerTester wrapped = new ControllerTester(cd);
wrapped.upgradeSystem(Version.fromString("6.1"));
wrapped.computeVersionStatus();
diff --git a/controller-server/src/test/java/com/yahoo/vespa/hosted/controller/integration/ZoneRegistryMock.java b/controller-server/src/test/java/com/yahoo/vespa/hosted/controller/integration/ZoneRegistryMock.java
index 0b520328cb2..a3ea56ccc72 100644
--- a/controller-server/src/test/java/com/yahoo/vespa/hosted/controller/integration/ZoneRegistryMock.java
+++ b/controller-server/src/test/java/com/yahoo/vespa/hosted/controller/integration/ZoneRegistryMock.java
@@ -71,7 +71,8 @@ public class ZoneRegistryMock extends AbstractComponent implements ZoneRegistry
ZoneApiMock.fromId("dev.us-east-1"),
ZoneApiMock.fromId("dev.aws-us-east-2a"),
ZoneApiMock.fromId("perf.us-east-3"),
- ZoneApiMock.fromId("prod.aws-us-east-1a"),
+ ZoneApiMock.newBuilder().withId("prod.aws-us-east-1a").withCloud("aws").build(),
+ ZoneApiMock.newBuilder().withId("prod.aws-us-east-1b").withCloud("aws").build(),
ZoneApiMock.fromId("prod.ap-northeast-1"),
ZoneApiMock.fromId("prod.ap-northeast-2"),
ZoneApiMock.fromId("prod.ap-southeast-1"),
@@ -79,7 +80,8 @@ public class ZoneRegistryMock extends AbstractComponent implements ZoneRegistry
ZoneApiMock.fromId("prod.us-west-1"),
ZoneApiMock.fromId("prod.us-central-1"),
ZoneApiMock.fromId("prod.eu-west-1"));
- setRoutingMethod(this.zones, RoutingMethod.sharedLayer4);
+ for (ZoneApi zone : this.zones)
+ setRoutingMethod(zone, zone.getCloudName().equals(CloudName.DEFAULT) ? RoutingMethod.sharedLayer4 : RoutingMethod.exclusive);
}
}
diff --git a/controller-server/src/test/java/com/yahoo/vespa/hosted/controller/maintenance/OsVersionStatusUpdaterTest.java b/controller-server/src/test/java/com/yahoo/vespa/hosted/controller/maintenance/OsVersionStatusUpdaterTest.java
index 2608a722e49..454a1ac9ee9 100644
--- a/controller-server/src/test/java/com/yahoo/vespa/hosted/controller/maintenance/OsVersionStatusUpdaterTest.java
+++ b/controller-server/src/test/java/com/yahoo/vespa/hosted/controller/maintenance/OsVersionStatusUpdaterTest.java
@@ -44,9 +44,20 @@ public class OsVersionStatusUpdaterTest {
statusUpdater.maintain();
var osVersions = tester.controller().osVersionStatus().versions();
- assertEquals(2, osVersions.size());
+ assertEquals(3, osVersions.size());
assertFalse(osVersions.get(new OsVersion(Version.emptyVersion, cloud)).isEmpty(), "All nodes on unknown version");
assertTrue(osVersions.get(new OsVersion(version1, cloud)).isEmpty(), "No nodes on current target");
+
+ CloudName otherCloud = CloudName.AWS;
+ tester.controller().upgradeOsIn(otherCloud, version1, Duration.ZERO, false);
+ statusUpdater.maintain();
+
+ osVersions = tester.controller().osVersionStatus().versions();
+ assertEquals(4, osVersions.size()); // 2 in cloud, 2 in otherCloud.
+ assertFalse(osVersions.get(new OsVersion(Version.emptyVersion, cloud)).isEmpty(), "All nodes on unknown version");
+ assertTrue(osVersions.get(new OsVersion(version1, cloud)).isEmpty(), "No nodes on current target");
+ assertFalse(osVersions.get(new OsVersion(Version.emptyVersion, otherCloud)).isEmpty(), "All nodes on unknown version");
+ assertTrue(osVersions.get(new OsVersion(version1, otherCloud)).isEmpty(), "No nodes on current target");
}
}
diff --git a/controller-server/src/test/java/com/yahoo/vespa/hosted/controller/restapi/controller/ControllerApiTest.java b/controller-server/src/test/java/com/yahoo/vespa/hosted/controller/restapi/controller/ControllerApiTest.java
index 9148ad36d46..80bcbc7ee7e 100644
--- a/controller-server/src/test/java/com/yahoo/vespa/hosted/controller/restapi/controller/ControllerApiTest.java
+++ b/controller-server/src/test/java/com/yahoo/vespa/hosted/controller/restapi/controller/ControllerApiTest.java
@@ -51,7 +51,7 @@ public class ControllerApiTest extends ControllerContainerTest {
// GET a list of all maintenance jobs
tester.assertResponse(authenticatedRequest("http://localhost:8080/controller/v1/maintenance/", "", Request.Method.GET),
- new File("maintenance.json"));
+ new File("maintenance.json"));
}
@Test
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 6226e94f7b4..48771ac064b 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
@@ -16,6 +16,9 @@
"name": "ArtifactExpirer"
},
{
+ "name": "AwsOsUpgrader"
+ },
+ {
"name": "BillingDatabaseMaintainer"
},
{
diff --git a/controller-server/src/test/java/com/yahoo/vespa/hosted/controller/restapi/deployment/responses/root.json b/controller-server/src/test/java/com/yahoo/vespa/hosted/controller/restapi/deployment/responses/root.json
index 6ef57aaed21..864fb628e92 100644
--- a/controller-server/src/test/java/com/yahoo/vespa/hosted/controller/restapi/deployment/responses/root.json
+++ b/controller-server/src/test/java/com/yahoo/vespa/hosted/controller/restapi/deployment/responses/root.json
@@ -365,6 +365,8 @@
"test-ap-southeast-1",
"production-aws-us-east-1a",
"test-aws-us-east-1a",
+ "production-aws-us-east-1b",
+ "test-aws-us-east-1b",
"production-eu-west-1",
"test-eu-west-1",
"production-us-central-1",
diff --git a/controller-server/src/test/java/com/yahoo/vespa/hosted/controller/restapi/routing/responses/discovery/environment.json b/controller-server/src/test/java/com/yahoo/vespa/hosted/controller/restapi/routing/responses/discovery/environment.json
index 1e06b279873..d8a64afb34e 100644
--- a/controller-server/src/test/java/com/yahoo/vespa/hosted/controller/restapi/routing/responses/discovery/environment.json
+++ b/controller-server/src/test/java/com/yahoo/vespa/hosted/controller/restapi/routing/responses/discovery/environment.json
@@ -22,6 +22,9 @@
"url": "http://localhost:8080/routing/v1/status/environment/prod/region/aws-us-east-1a/"
},
{
+ "url": "http://localhost:8080/routing/v1/status/environment/prod/region/aws-us-east-1b/"
+ },
+ {
"url": "http://localhost:8080/routing/v1/status/environment/prod/region/eu-west-1/"
},
{
diff --git a/controller-server/src/test/java/com/yahoo/vespa/hosted/controller/restapi/routing/responses/recursion/environment.json b/controller-server/src/test/java/com/yahoo/vespa/hosted/controller/restapi/routing/responses/recursion/environment.json
index 1711bb1f856..2d4553978c6 100644
--- a/controller-server/src/test/java/com/yahoo/vespa/hosted/controller/restapi/routing/responses/recursion/environment.json
+++ b/controller-server/src/test/java/com/yahoo/vespa/hosted/controller/restapi/routing/responses/recursion/environment.json
@@ -41,11 +41,19 @@
"changedAt": 0
},
{
- "routingMethod": "sharedLayer4",
+ "routingMethod": "exclusive",
"environment": "prod",
"region": "aws-us-east-1a",
"status": "in",
- "agent": "operator",
+ "agent": "system",
+ "changedAt": 0
+ },
+ {
+ "routingMethod": "exclusive",
+ "environment": "prod",
+ "region": "aws-us-east-1b",
+ "status": "in",
+ "agent": "system",
"changedAt": 0
},
{
diff --git a/controller-server/src/test/java/com/yahoo/vespa/hosted/controller/routing/RoutingPoliciesTest.java b/controller-server/src/test/java/com/yahoo/vespa/hosted/controller/routing/RoutingPoliciesTest.java
index 29834863976..7b00e7040b5 100644
--- a/controller-server/src/test/java/com/yahoo/vespa/hosted/controller/routing/RoutingPoliciesTest.java
+++ b/controller-server/src/test/java/com/yahoo/vespa/hosted/controller/routing/RoutingPoliciesTest.java
@@ -26,6 +26,7 @@ import com.yahoo.vespa.hosted.controller.api.integration.dns.RecordName;
import com.yahoo.vespa.hosted.controller.application.Endpoint;
import com.yahoo.vespa.hosted.controller.application.EndpointId;
import com.yahoo.vespa.hosted.controller.application.EndpointList;
+import com.yahoo.vespa.hosted.controller.application.SystemApplication;
import com.yahoo.vespa.hosted.controller.application.TenantAndApplicationId;
import com.yahoo.vespa.hosted.controller.application.pkg.ApplicationPackage;
import com.yahoo.vespa.hosted.controller.deployment.ApplicationPackageBuilder;
@@ -62,6 +63,8 @@ public class RoutingPoliciesTest {
private static final ZoneId zone2 = ZoneId.from("prod", "us-central-1");
private static final ZoneId zone3 = ZoneId.from("prod", "aws-us-east-1a");
private static final ZoneId zone4 = ZoneId.from("prod", "aws-us-east-1b");
+ private static final ZoneId zone5 = ZoneId.from("prod", "north");
+ private static final ZoneId zone6 = ZoneId.from("prod", "south");
private static final ApplicationPackage applicationPackage = applicationPackageBuilder().region(zone1.region())
.region(zone2.region())
@@ -399,15 +402,15 @@ public class RoutingPoliciesTest {
context.submit(applicationPackage).deploy();
tester.assertTargets(context.instanceId(), EndpointId.defaultId(),
- ClusterSpec.Id.from("default"), 0,
- Map.of(zone1, 1L, zone2, 1L));
+ ClusterSpec.Id.from("default"), 0,
+ Map.of(zone1, 1L, zone2, 1L));
assertEquals(Set.of("app1.tenant1.aws-eu-west-1.w.vespa-app.cloud",
- "app1.tenant1.aws-eu-west-1a.z.vespa-app.cloud",
- "app1.tenant1.aws-us-east-1.w.vespa-app.cloud",
- "app1.tenant1.aws-us-east-1c.z.vespa-app.cloud",
- "app1.tenant1.g.vespa-app.cloud"),
- tester.recordNames(),
- "Registers expected DNS names");
+ "app1.tenant1.aws-eu-west-1a.z.vespa-app.cloud",
+ "app1.tenant1.aws-us-east-1.w.vespa-app.cloud",
+ "app1.tenant1.aws-us-east-1c.z.vespa-app.cloud",
+ "app1.tenant1.g.vespa-app.cloud"),
+ tester.recordNames(),
+ "Registers expected DNS names");
}
@Test
@@ -419,8 +422,8 @@ public class RoutingPoliciesTest {
var zone = ZoneId.from("dev", "us-east-1");
var zoneApi = ZoneApiMock.from(zone.environment(), zone.region());
tester.controllerTester().serviceRegistry().zoneRegistry()
- .setZones(zoneApi)
- .exclusiveRoutingIn(zoneApi);
+ .setZones(zoneApi)
+ .exclusiveRoutingIn(zoneApi);
// Deploy to dev
context.runJob(zone, emptyApplicationPackage);
@@ -735,16 +738,17 @@ public class RoutingPoliciesTest {
DeploymentContext mainContext = tester.newDeploymentContext(mainInstance);
var applicationPackage = applicationPackageBuilder()
.instances("beta,main")
- .region(zone1.region())
- .region(zone2.region())
- .applicationEndpoint("a0", "c0", "us-west-1",
- Map.of(betaInstance.instance(), 2,
- mainInstance.instance(), 8))
- .applicationEndpoint("a1", "c1", "us-central-1",
- Map.of(betaInstance.instance(), 4,
- mainInstance.instance(), 6))
+ .region(zone5.region())
+ .region(zone6.region())
+ .applicationEndpoint("a0", "c0",
+ Map.of(zone5.region().value(), Map.of(betaInstance.instance(), 2,
+ mainInstance.instance(), 8),
+ zone6.region().value(), Map.of(mainInstance.instance(), 7)))
+ .applicationEndpoint("a1", "c1", zone6.region().value(),
+ Map.of(betaInstance.instance(), 4,
+ mainInstance.instance(), 6))
.build();
- for (var zone : List.of(zone1, zone2)) {
+ for (var zone : List.of(zone5, zone6)) {
tester.provisionLoadBalancers(2, betaInstance, zone);
tester.provisionLoadBalancers(2, mainInstance, zone);
}
@@ -753,50 +757,53 @@ public class RoutingPoliciesTest {
betaContext.submit(applicationPackage).deploy();
// Application endpoint points to both instances with correct weights
- DeploymentId betaZone1 = betaContext.deploymentIdIn(zone1);
- DeploymentId mainZone1 = mainContext.deploymentIdIn(zone1);
- DeploymentId betaZone2 = betaContext.deploymentIdIn(zone2);
- DeploymentId mainZone2 = mainContext.deploymentIdIn(zone2);
+ DeploymentId betaZone5 = betaContext.deploymentIdIn(zone5);
+ DeploymentId mainZone5 = mainContext.deploymentIdIn(zone5);
+ DeploymentId betaZone6 = betaContext.deploymentIdIn(zone6);
+ DeploymentId mainZone6 = mainContext.deploymentIdIn(zone6);
tester.assertTargets(application, EndpointId.of("a0"), ClusterSpec.Id.from("c0"), 0,
- Map.of(betaZone1, 2,
- mainZone1, 8));
+ Map.of(betaZone5, 2,
+ mainZone5, 8,
+ mainZone6, 7));
tester.assertTargets(application, EndpointId.of("a1"), ClusterSpec.Id.from("c1"), 1,
- Map.of(betaZone2, 4,
- mainZone2, 6));
+ Map.of(betaZone6, 4,
+ mainZone6, 6));
// Weights are updated
applicationPackage = applicationPackageBuilder()
.instances("beta,main")
- .region(zone1.region())
- .region(zone2.region())
- .applicationEndpoint("a0", "c0", "us-west-1",
- Map.of(betaInstance.instance(), 3,
- mainInstance.instance(), 7))
- .applicationEndpoint("a1", "c1", "us-central-1",
- Map.of(betaInstance.instance(), 1,
- mainInstance.instance(), 9))
+ .region(zone5.region())
+ .region(zone6.region())
+ .applicationEndpoint("a0", "c0",
+ Map.of(zone5.region().value(), Map.of(betaInstance.instance(), 3,
+ mainInstance.instance(), 7),
+ zone6.region().value(), Map.of(mainInstance.instance(), 2)))
+ .applicationEndpoint("a1", "c1", zone6.region().value(),
+ Map.of(betaInstance.instance(), 1,
+ mainInstance.instance(), 9))
.build();
betaContext.submit(applicationPackage).deploy();
tester.assertTargets(application, EndpointId.of("a0"), ClusterSpec.Id.from("c0"), 0,
- Map.of(betaZone1, 3,
- mainZone1, 7));
+ Map.of(betaZone5, 3,
+ mainZone5, 7,
+ mainZone6, 2));
tester.assertTargets(application, EndpointId.of("a1"), ClusterSpec.Id.from("c1"), 1,
- Map.of(betaZone2, 1,
- mainZone2, 9));
+ Map.of(betaZone6, 1,
+ mainZone6, 9));
// An endpoint is removed
applicationPackage = applicationPackageBuilder()
.instances("beta,main")
- .region(zone1.region())
- .region(zone2.region())
- .applicationEndpoint("a0", "c0", "us-west-1",
- Map.of(betaInstance.instance(), 1))
+ .region(zone5.region())
+ .region(zone6.region())
+ .applicationEndpoint("a0", "c0", zone5.region().value(),
+ Map.of(betaInstance.instance(), 1))
.build();
betaContext.submit(applicationPackage).deploy();
// Application endpoints now point to a single instance
tester.assertTargets(application, EndpointId.of("a0"), ClusterSpec.Id.from("c0"), 0,
- Map.of(betaZone1, 1));
+ Map.of(betaZone5, 1));
assertTrue(tester.controllerTester().controller().routing()
.readDeclaredEndpointsOf(application)
.named(EndpointId.of("a1")).isEmpty(),
@@ -814,50 +821,59 @@ public class RoutingPoliciesTest {
DeploymentContext mainContext = tester.newDeploymentContext(mainInstance);
var applicationPackage = applicationPackageBuilder()
.instances("beta,main")
- .region(zone1.region())
- .applicationEndpoint("a0", "c0", "us-west-1",
- Map.of(betaInstance.instance(), 2,
- mainInstance.instance(), 8))
+ .region(zone5.region())
+ .region(zone6.region())
+ .applicationEndpoint("a0", "c0", Map.of(zone5.region().value(), Map.of(betaInstance.instance(), 2,
+ mainInstance.instance(), 8),
+ zone6.region().value(), Map.of(mainInstance.instance(), 9)))
.build();
- tester.provisionLoadBalancers(1, betaInstance, zone1);
- tester.provisionLoadBalancers(1, mainInstance, zone1);
+ tester.provisionLoadBalancers(1, betaInstance, zone5);
+ tester.provisionLoadBalancers(1, mainInstance, zone5);
+ tester.provisionLoadBalancers(1, mainInstance, zone6);
// Deploy both instances
betaContext.submit(applicationPackage).deploy();
// Application endpoint points to both instances with correct weights
- DeploymentId betaZone1 = betaContext.deploymentIdIn(zone1);
- DeploymentId mainZone1 = mainContext.deploymentIdIn(zone1);
+ DeploymentId betaZone1 = betaContext.deploymentIdIn(zone5);
+ DeploymentId mainZone1 = mainContext.deploymentIdIn(zone5);
+ DeploymentId mainZone2 = mainContext.deploymentIdIn(zone6);
tester.assertTargets(application, EndpointId.of("a0"), ClusterSpec.Id.from("c0"), 0,
- Map.of(betaZone1, 2,
- mainZone1, 8));
+ Map.of(betaZone1, 2,
+ mainZone1, 8,
+ mainZone2, 9));
// Changing routing status removes deployment from DNS
tester.routingPolicies().setRoutingStatus(mainZone1, RoutingStatus.Value.out, RoutingStatus.Agent.tenant);
betaContext.flushDnsUpdates();
tester.assertTargets(application, EndpointId.of("a0"), ClusterSpec.Id.from("c0"), 0,
- Map.of(betaZone1, 2));
+ Map.of(betaZone1, 2,
+ mainZone2, 9));
- // Changing routing status for remaining deployment adds back all deployments, because removing all deployments
+ // Changing routing status for remaining deployments adds back all deployments, because removing all deployments
// puts all IN
tester.routingPolicies().setRoutingStatus(betaZone1, RoutingStatus.Value.out, RoutingStatus.Agent.tenant);
+ tester.routingPolicies().setRoutingStatus(mainZone2, RoutingStatus.Value.out, RoutingStatus.Agent.tenant);
betaContext.flushDnsUpdates();
tester.assertTargets(application, EndpointId.of("a0"), ClusterSpec.Id.from("c0"), 0,
- Map.of(betaZone1, 2,
- mainZone1, 8));
+ Map.of(betaZone1, 2,
+ mainZone1, 8,
+ mainZone2, 9));
// Activating main deployment allows us to deactivate the beta deployment
tester.routingPolicies().setRoutingStatus(mainZone1, RoutingStatus.Value.in, RoutingStatus.Agent.tenant);
betaContext.flushDnsUpdates();
tester.assertTargets(application, EndpointId.of("a0"), ClusterSpec.Id.from("c0"), 0,
- Map.of(mainZone1, 8));
+ Map.of(mainZone1, 8));
// Activate all deployments again
tester.routingPolicies().setRoutingStatus(betaZone1, RoutingStatus.Value.in, RoutingStatus.Agent.tenant);
+ tester.routingPolicies().setRoutingStatus(mainZone2, RoutingStatus.Value.in, RoutingStatus.Agent.tenant);
betaContext.flushDnsUpdates();
tester.assertTargets(application, EndpointId.of("a0"), ClusterSpec.Id.from("c0"), 0,
Map.of(betaZone1, 2,
- mainZone1, 8));
+ mainZone1, 8,
+ mainZone2, 9));
}
/** Returns an application package builder that satisfies requirements for a directly routed endpoint */
@@ -919,11 +935,17 @@ public class RoutingPoliciesTest {
List<ZoneId> zones;
if (tester.controller().system().isPublic()) {
zones = publicZones();
+ tester.controllerTester().setZones(zones);
} else {
zones = new ArrayList<>(tester.controllerTester().zoneRegistry().zones().all().ids()); // Default zones
zones.add(zone4); // Missing from default ZoneRegistryMock zones
+ tester.controllerTester().setZones(zones);
+ tester.controllerTester().zoneRegistry().addZones(ZoneApiMock.newBuilder().withId(zone5.value()).withCloud("aws").build());
+ tester.controllerTester().zoneRegistry().addZones(ZoneApiMock.newBuilder().withId(zone6.value()).withCloud("gcp").build());
+ zones.add(zone5);
+ zones.add(zone6);
+ tester.configServer().bootstrap(zones, SystemApplication.notController());
}
- tester.controllerTester().setZones(zones);
if (exclusiveRouting) {
tester.controllerTester().setRoutingMethod(zones, RoutingMethod.exclusive);
}
@@ -997,7 +1019,7 @@ public class RoutingPoliciesTest {
deploymentsByDnsName.computeIfAbsent(dnsName, (k) -> new ArrayList<>())
.add(deployment);
}
- assertEquals(1, deploymentsByDnsName.size(), "Found " + endpointId + " for " + application);
+ assertTrue(1 <= deploymentsByDnsName.size(), "Found " + endpointId + " for " + application);
deploymentsByDnsName.forEach((dnsName, deployments) -> {
Set<String> weightedTargets = deployments.stream()
.map(d -> "weighted/lb-" + loadBalancerId + "--" +