diff options
author | Martin Polden <mpolden@mpolden.no> | 2020-03-11 15:28:09 +0100 |
---|---|---|
committer | Martin Polden <mpolden@mpolden.no> | 2020-03-12 12:12:20 +0100 |
commit | 58df1263e48ff6a089ee722d62715a2c9820169c (patch) | |
tree | a6e93908d4dbe13f731133e198807ce845789660 | |
parent | 3da641f5e5295f0f67ebf062618464327c2d7f40 (diff) |
Restrict directly routed zone endpoints to qualified deployments
10 files changed, 159 insertions, 29 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 1c22a37af8d..c8f936c2147 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 @@ -1,23 +1,30 @@ // Copyright 2020 Oath Inc. Licensed under the terms of the Apache 2.0 license. See LICENSE in the project root. package com.yahoo.vespa.hosted.controller; +import com.google.common.base.Suppliers; +import com.yahoo.component.Version; import com.yahoo.config.application.api.DeploymentInstanceSpec; import com.yahoo.config.application.api.DeploymentSpec; import com.yahoo.config.provision.ApplicationId; -import com.yahoo.config.provision.ClusterSpec; import com.yahoo.config.provision.Environment; import com.yahoo.config.provision.InstanceName; import com.yahoo.config.provision.zone.RoutingMethod; import com.yahoo.config.provision.zone.ZoneId; +import com.yahoo.vespa.flags.BooleanFlag; +import com.yahoo.vespa.flags.FetchVector; +import com.yahoo.vespa.flags.Flags; 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.configserver.ContainerEndpoint; +import com.yahoo.vespa.hosted.controller.api.integration.deployment.ApplicationVersion; import com.yahoo.vespa.hosted.controller.api.integration.dns.Record; import com.yahoo.vespa.hosted.controller.api.integration.dns.RecordData; import com.yahoo.vespa.hosted.controller.api.integration.dns.RecordName; +import com.yahoo.vespa.hosted.controller.application.Deployment; import com.yahoo.vespa.hosted.controller.application.Endpoint; import com.yahoo.vespa.hosted.controller.application.Endpoint.Port; import com.yahoo.vespa.hosted.controller.application.EndpointList; +import com.yahoo.vespa.hosted.controller.application.TenantAndApplicationId; import com.yahoo.vespa.hosted.controller.dns.NameServiceQueue.Priority; import com.yahoo.vespa.hosted.controller.rotation.RotationLock; import com.yahoo.vespa.hosted.controller.rotation.RotationRepository; @@ -25,7 +32,6 @@ import com.yahoo.vespa.hosted.controller.routing.RoutingId; import com.yahoo.vespa.hosted.controller.routing.RoutingPolicies; import com.yahoo.vespa.hosted.rotation.config.RotationsConfig; -import java.net.URI; import java.util.ArrayList; import java.util.Collection; import java.util.Collections; @@ -37,9 +43,9 @@ import java.util.LinkedHashSet; import java.util.List; import java.util.Map; import java.util.Objects; +import java.util.Optional; import java.util.Set; import java.util.TreeMap; -import java.util.function.Function; import java.util.stream.Collectors; /** @@ -52,15 +58,21 @@ import java.util.stream.Collectors; */ public class RoutingController { + /** The minimum Vespa version that supports directly routed endpoints */ + public static final Version DIRECT_ROUTING_MIN_VERSION = new Version(Integer.MAX_VALUE, Integer.MAX_VALUE, + Integer.MAX_VALUE); + private final Controller controller; private final RoutingPolicies routingPolicies; private final RotationRepository rotationRepository; + private final BooleanFlag allowDirectRouting; public RoutingController(Controller controller, RotationsConfig rotationsConfig) { this.controller = Objects.requireNonNull(controller, "controller must be non-null"); this.routingPolicies = new RoutingPolicies(controller); this.rotationRepository = new RotationRepository(rotationsConfig, controller.applications(), controller.curator()); + this.allowDirectRouting = Flags.ALLOW_DIRECT_ROUTING.bindTo(controller.flagSource()); } public RoutingPolicies policies() { @@ -83,9 +95,12 @@ public class RoutingController { .on(Port.fromRoutingMethod(RoutingMethod.shared)) .in(controller.system()))); boolean hasSharedEndpoint = !endpoints.isEmpty(); + // Avoid reading application more than once per call to this + var application = Suppliers.memoize(() -> controller.applications().requireApplication(TenantAndApplicationId.from(deployment.applicationId()))); for (var policy : routingPolicies.get(deployment).values()) { if (!policy.status().isActive()) continue; for (var routingMethod : controller.zoneRegistry().routingMethods(policy.id().zone())) { + if (routingMethod.isDirect() && !canRouteDirectlyTo(deployment, application.get())) continue; if (hasSharedEndpoint && routingMethod == RoutingMethod.shared) continue; endpoints.add(policy.endpointIn(controller.system(), routingMethod)); } @@ -113,7 +128,7 @@ public class RoutingController { .requiresRotation() .forEach(endpoints::add); } - // Add global endpoints provided by routing policices + // Add global endpoints provided by routing policies var zonesByRoutingId = new LinkedHashMap<RoutingId, List<ZoneId>>(); for (var policy : routingPolicies.get(instance.id()).values()) { if (!policy.status().isActive()) continue; @@ -249,4 +264,30 @@ public class RoutingController { return Collections.unmodifiableList(routingMethods); } + /** Returns whether traffic can be directly routed to given deployment */ + private boolean canRouteDirectlyTo(DeploymentId deploymentId, Application application) { + if (controller.system().isPublic()) return true; // Public always supports direct routing + + // Check Athenz service presence. The test framework uses this identity when sending requests to the + // deployment's container(s). + var athenzService = application.deploymentSpec().instance(deploymentId.applicationId().instance()) + .flatMap(instance -> instance.athenzService(deploymentId.zoneId().environment(), + deploymentId.zoneId().region())); + if (athenzService.isEmpty()) return false; + + // Check minimum required compile-version + var instance = application.require(deploymentId.applicationId().instance()); + var compileVersion = Optional.ofNullable(instance.deployments().get(deploymentId.zoneId())) + .map(Deployment::applicationVersion) + .flatMap(ApplicationVersion::compileVersion); + if (compileVersion.isEmpty()) return false; + if (compileVersion.get().isBefore(DIRECT_ROUTING_MIN_VERSION)) return false; + + // Check feature flag + // TODO(mpolden): Remove once we make this default + return this.allowDirectRouting.with(FetchVector.Dimension.APPLICATION_ID, + deploymentId.applicationId().serializedForm()) + .value(); + } + } 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 b58dd0dd08e..06cf13fe7db 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 @@ -6,6 +6,8 @@ import com.yahoo.component.Version; import com.yahoo.config.application.api.DeploymentSpec; import com.yahoo.config.application.api.ValidationId; import com.yahoo.config.application.api.ValidationOverrides; +import com.yahoo.config.provision.AthenzDomain; +import com.yahoo.config.provision.AthenzService; import com.yahoo.config.provision.CloudName; import com.yahoo.config.provision.Environment; import com.yahoo.config.provision.RegionName; @@ -13,6 +15,8 @@ import com.yahoo.config.provision.SystemName; import com.yahoo.config.provision.TenantName; import com.yahoo.config.provision.zone.RoutingMethod; import com.yahoo.config.provision.zone.ZoneId; +import com.yahoo.vespa.flags.Flags; +import com.yahoo.vespa.flags.InMemoryFlagSource; 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; @@ -26,6 +30,7 @@ import com.yahoo.vespa.hosted.controller.application.ApplicationPackage; import com.yahoo.vespa.hosted.controller.application.AssignedRotation; import com.yahoo.vespa.hosted.controller.application.Deployment; import com.yahoo.vespa.hosted.controller.application.DeploymentMetrics; +import com.yahoo.vespa.hosted.controller.application.Endpoint; import com.yahoo.vespa.hosted.controller.application.SystemApplication; import com.yahoo.vespa.hosted.controller.deployment.ApplicationPackageBuilder; import com.yahoo.vespa.hosted.controller.deployment.DeploymentContext; @@ -42,6 +47,7 @@ import java.util.List; import java.util.Optional; import java.util.Set; import java.util.function.Function; +import java.util.function.Supplier; import java.util.stream.Collectors; import java.util.stream.Stream; @@ -697,7 +703,9 @@ public class ControllerTest { var context1 = tester.newDeploymentContext("tenant1", "app1", "default"); var prodZone = ZoneId.from("prod", "us-west-1"); tester.controllerTester().zoneRegistry().exclusiveRoutingIn(ZoneApiMock.from(prodZone)); - var applicationPackage = new ApplicationPackageBuilder().environment(prodZone.environment()) + var applicationPackage = new ApplicationPackageBuilder().athenzIdentity(AthenzDomain.from("domain"), AthenzService.from("service")) + .compileVersion(RoutingController.DIRECT_ROUTING_MIN_VERSION) + .environment(prodZone.environment()) .region(prodZone.region()) .build(); // Deploy app1 in production @@ -847,4 +855,40 @@ public class ControllerTest { assertEquals(expectedRecords, List.copyOf(tester.controllerTester().nameService().records())); } + @Test + public void testDirectRoutingSupport() { + var context = tester.newDeploymentContext(); + var zone = ZoneId.from("prod", "us-west-1"); + var applicationPackageBuilder = new ApplicationPackageBuilder() + .region(zone.region()); + tester.controllerTester().zoneRegistry().setRoutingMethod(ZoneApiMock.from(zone), RoutingMethod.shared, RoutingMethod.sharedLayer4); + Supplier<Set<RoutingMethod>> routingMethods = () -> tester.controller().routing().endpointsOf(context.deploymentIdIn(zone)) + .asList() + .stream() + .map(Endpoint::routingMethod) + .collect(Collectors.toSet()); + ((InMemoryFlagSource) tester.controller().flagSource()).withBooleanFlag(Flags.ALLOW_DIRECT_ROUTING.id(), false); + + // Without everything + context.submit(applicationPackageBuilder.build()).deploy(); + assertEquals(Set.of(RoutingMethod.shared), routingMethods.get()); + + // Without Athenz service + context.submit(applicationPackageBuilder.compileVersion(RoutingController.DIRECT_ROUTING_MIN_VERSION).build()) + .deploy(); + assertEquals(Set.of(RoutingMethod.shared), routingMethods.get()); + + // Without feature flag + var applicationPackage = applicationPackageBuilder.compileVersion(RoutingController.DIRECT_ROUTING_MIN_VERSION) + .athenzIdentity(AthenzDomain.from("domain"), AthenzService.from("service")) + .build(); + context.submit(applicationPackage).deploy(); + assertEquals(Set.of(RoutingMethod.shared), routingMethods.get()); + + // With everything required + ((InMemoryFlagSource) tester.controller().flagSource()).withBooleanFlag(Flags.ALLOW_DIRECT_ROUTING.id(), true); + context.submit(applicationPackage).deploy(); + assertEquals(Set.of(RoutingMethod.shared, RoutingMethod.sharedLayer4), routingMethods.get()); + } + } 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 58175762129..2f2b1fbb364 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 @@ -1,6 +1,7 @@ // 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.deployment; +import com.yahoo.component.Version; import com.yahoo.config.application.api.ValidationId; import com.yahoo.config.provision.AthenzDomain; import com.yahoo.config.provision.AthenzService; @@ -57,6 +58,7 @@ public class ApplicationPackageBuilder { private String searchDefinition = "search test { }"; private boolean explicitSystemTest = false; private boolean explicitStagingTest = false; + private Version compileVersion = Version.fromString("6.1"); public ApplicationPackageBuilder majorVersion(int majorVersion) { this.majorVersion = OptionalInt.of(majorVersion); @@ -164,6 +166,11 @@ public class ApplicationPackageBuilder { return this; } + public ApplicationPackageBuilder compileVersion(Version version) { + compileVersion = version; + return this; + } + public ApplicationPackageBuilder athenzIdentity(AthenzDomain domain, AthenzService service) { this.athenzIdentityAttributes = String.format("athenz-domain='%s' athenz-service='%s'", domain.value(), service.value()); @@ -260,8 +267,8 @@ public class ApplicationPackageBuilder { return searchDefinition.getBytes(UTF_8); } - private static byte[] buildMeta() { - return "{\"compileVersion\":\"6.1\",\"buildTime\":1000}".getBytes(UTF_8); + private static byte[] buildMeta(Version compileVersion) { + return ("{\"compileVersion\":\"" + compileVersion.toFullString() + "\",\"buildTime\":1000}").getBytes(UTF_8); } public ApplicationPackage build() { @@ -285,7 +292,7 @@ public class ApplicationPackageBuilder { out.write(searchDefinition()); out.closeEntry(); out.putNextEntry(new ZipEntry(dir + "build-meta.json")); - out.write(buildMeta()); + out.write(buildMeta(compileVersion)); out.closeEntry(); out.putNextEntry(new ZipEntry(dir + "security/clients.pem")); out.write(X509CertificateUtils.toPem(trustedCertificates).getBytes(UTF_8)); @@ -307,7 +314,7 @@ public class ApplicationPackageBuilder { out.write(deploymentXml.getBytes(UTF_8)); out.closeEntry(); out.putNextEntry(new ZipEntry("build-meta.json")); - out.write(buildMeta()); + out.write(buildMeta(Version.fromString("6.1"))); out.closeEntry(); } catch (IOException e) { throw new UncheckedIOException(e); diff --git a/controller-server/src/test/java/com/yahoo/vespa/hosted/controller/deployment/DeploymentContext.java b/controller-server/src/test/java/com/yahoo/vespa/hosted/controller/deployment/DeploymentContext.java index 4550b29d2fd..706a7cec2a9 100644 --- a/controller-server/src/test/java/com/yahoo/vespa/hosted/controller/deployment/DeploymentContext.java +++ b/controller-server/src/test/java/com/yahoo/vespa/hosted/controller/deployment/DeploymentContext.java @@ -13,6 +13,8 @@ import com.yahoo.security.KeyAlgorithm; import com.yahoo.security.KeyUtils; import com.yahoo.security.SignatureAlgorithm; import com.yahoo.security.X509CertificateBuilder; +import com.yahoo.vespa.flags.Flags; +import com.yahoo.vespa.flags.InMemoryFlagSource; import com.yahoo.vespa.hosted.controller.Application; import com.yahoo.vespa.hosted.controller.ControllerTester; import com.yahoo.vespa.hosted.controller.Instance; @@ -91,6 +93,7 @@ public class DeploymentContext { .emailAddress("b@a") .trust(generateCertificate()) .build(); + public static final SourceRevision defaultSourceRevision = new SourceRevision("repository1", "master", "commit1"); private final TenantAndApplicationId applicationId; @@ -104,7 +107,6 @@ public class DeploymentContext { private boolean deferDnsUpdates = false; public DeploymentContext(ApplicationId instanceId, DeploymentTester tester) { - this.applicationId = TenantAndApplicationId.from(instanceId); this.instanceId = instanceId; this.testerId = TesterId.of(instanceId); @@ -112,6 +114,7 @@ public class DeploymentContext { this.runner = tester.runner(); this.tester = tester; createTenantAndApplication(); + ((InMemoryFlagSource) tester.controller().flagSource()).withBooleanFlag(Flags.ALLOW_DIRECT_ROUTING.id(), true); } private void createTenantAndApplication() { 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 d2835c8b830..2b5e8b3e91c 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 @@ -1087,7 +1087,7 @@ public class DeploymentTriggerTest { services.zoneRegistry() .setSystemName(SystemName.cd) .setZones(zones) - .setRoutingMethod(zones, RoutingMethod.exclusive); + .setRoutingMethod(zones, RoutingMethod.shared); tester = new DeploymentTester(new ControllerTester(services)); tester.configServer().bootstrap(services.zoneRegistry().zones().all().ids(), SystemApplication.values()); tester.controllerTester().upgradeSystem(Version.fromString("6.1")); 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 a3d1b9adb35..21b6e729e41 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 @@ -4,6 +4,8 @@ package com.yahoo.vespa.hosted.controller.deployment; import com.google.common.collect.ImmutableList; import com.yahoo.component.Version; import com.yahoo.config.application.api.DeploymentSpec; +import com.yahoo.config.provision.AthenzDomain; +import com.yahoo.config.provision.AthenzService; import com.yahoo.config.provision.HostName; import com.yahoo.config.provision.NodeResources; import com.yahoo.config.provision.SystemName; @@ -11,6 +13,7 @@ import com.yahoo.config.provision.zone.RoutingMethod; import com.yahoo.config.provision.zone.ZoneId; import com.yahoo.slime.Inspector; import com.yahoo.slime.SlimeUtils; +import com.yahoo.vespa.hosted.controller.RoutingController; import com.yahoo.vespa.hosted.controller.api.application.v4.model.configserverbindings.ConfigChangeActions; import com.yahoo.vespa.hosted.controller.api.application.v4.model.configserverbindings.RefeedAction; import com.yahoo.vespa.hosted.controller.api.application.v4.model.configserverbindings.RestartAction; @@ -258,7 +261,16 @@ public class InternalStepRunnerTest { var systemTestZone = JobType.systemTest.zone(system()); var stagingZone = JobType.stagingTest.zone(system()); tester.controllerTester().zoneRegistry().exclusiveRoutingIn(ZoneApiMock.from(systemTestZone), ZoneApiMock.from(stagingZone)); - app.newRun(JobType.systemTest); + var applicationPackage = new ApplicationPackageBuilder() + .athenzIdentity(AthenzDomain.from("domain"), AthenzService.from("service")) + .upgradePolicy("default") + .region("us-central-1") + .parallel("us-west-1", "us-east-3") + .compileVersion(RoutingController.DIRECT_ROUTING_MIN_VERSION) + .build(); + app.submit(applicationPackage) + .triggerJobs(); + tester.runner().run(); assertEquals(unfinished, tester.jobs().last(app.instanceId(), JobType.systemTest).get().stepStatuses().get(Step.installReal)); assertEquals(unfinished, tester.jobs().last(app.instanceId(), JobType.systemTest).get().stepStatuses().get(Step.installTester)); @@ -266,7 +278,7 @@ public class InternalStepRunnerTest { app.flushDnsUpdates(); tester.configServer().convergeServices(app.instanceId(), JobType.systemTest.zone(system())); tester.configServer().convergeServices(app.testerId().id(), JobType.systemTest.zone(system())); - tester.runner().run();; + tester.runner().run(); assertEquals(succeeded, tester.jobs().last(app.instanceId(), JobType.systemTest).get().stepStatuses().get(Step.installReal)); assertEquals(succeeded, tester.jobs().last(app.instanceId(), JobType.systemTest).get().stepStatuses().get(Step.installTester)); } 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 b6f4fa22984..c83961e315a 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 @@ -24,6 +24,7 @@ import com.yahoo.vespa.hosted.controller.Application; import com.yahoo.vespa.hosted.controller.ControllerTester; import com.yahoo.vespa.hosted.controller.Instance; import com.yahoo.vespa.hosted.controller.LockedTenant; +import com.yahoo.vespa.hosted.controller.RoutingController; import com.yahoo.vespa.hosted.controller.api.application.v4.EnvironmentResource; import com.yahoo.vespa.hosted.controller.api.application.v4.model.DeployOptions; import com.yahoo.vespa.hosted.controller.api.identifiers.DeploymentId; @@ -1503,6 +1504,8 @@ public class ApplicationApiTest extends ControllerContainerTest { deploymentTester.controllerTester().zoneRegistry().setRoutingMethod(ZoneApiMock.from(zone), List.of(RoutingMethod.exclusive, RoutingMethod.shared)); ApplicationPackage applicationPackage = new ApplicationPackageBuilder() + .athenzIdentity(com.yahoo.config.provision.AthenzDomain.from("domain"), AthenzService.from("service")) + .compileVersion(RoutingController.DIRECT_ROUTING_MIN_VERSION) .environment(Environment.prod) .instances("instance1") .region(zone.region().value()) diff --git a/controller-server/src/test/java/com/yahoo/vespa/hosted/controller/restapi/routing/RoutingApiTest.java b/controller-server/src/test/java/com/yahoo/vespa/hosted/controller/restapi/routing/RoutingApiTest.java index f079bd1d7e6..fefd23eb67c 100644 --- a/controller-server/src/test/java/com/yahoo/vespa/hosted/controller/restapi/routing/RoutingApiTest.java +++ b/controller-server/src/test/java/com/yahoo/vespa/hosted/controller/restapi/routing/RoutingApiTest.java @@ -2,9 +2,12 @@ package com.yahoo.vespa.hosted.controller.restapi.routing; import com.yahoo.application.container.handler.Request; +import com.yahoo.config.provision.AthenzDomain; +import com.yahoo.config.provision.AthenzService; import com.yahoo.config.provision.zone.RoutingMethod; import com.yahoo.config.provision.zone.ZoneId; import com.yahoo.vespa.hosted.controller.ControllerTester; +import com.yahoo.vespa.hosted.controller.RoutingController; import com.yahoo.vespa.hosted.controller.deployment.ApplicationPackageBuilder; import com.yahoo.vespa.hosted.controller.deployment.DeploymentTester; import com.yahoo.vespa.hosted.controller.integration.ZoneApiMock; @@ -126,6 +129,8 @@ public class RoutingApiTest extends ControllerContainerTest { ZoneApiMock.from(eastZone)); // Deploy application var applicationPackage = new ApplicationPackageBuilder() + .athenzIdentity(AthenzDomain.from("domain"), AthenzService.from("service")) + .compileVersion(RoutingController.DIRECT_ROUTING_MIN_VERSION) .region(westZone.region()) .region(eastZone.region()) .endpoint("default", "default", eastZone.region().value(), westZone.region().value()) 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 732ea9bff31..719b2cc47f9 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 @@ -5,6 +5,8 @@ import com.google.common.collect.Sets; import com.yahoo.config.application.api.DeploymentSpec; import com.yahoo.config.application.api.ValidationId; import com.yahoo.config.provision.ApplicationId; +import com.yahoo.config.provision.AthenzDomain; +import com.yahoo.config.provision.AthenzService; import com.yahoo.config.provision.ClusterSpec; import com.yahoo.config.provision.Environment; import com.yahoo.config.provision.HostName; @@ -14,6 +16,7 @@ import com.yahoo.config.provision.zone.RoutingMethod; import com.yahoo.config.provision.zone.ZoneId; import com.yahoo.vespa.hosted.controller.ControllerTester; import com.yahoo.vespa.hosted.controller.Instance; +import com.yahoo.vespa.hosted.controller.RoutingController; import com.yahoo.vespa.hosted.controller.api.application.v4.model.DeployOptions; import com.yahoo.vespa.hosted.controller.api.integration.configserver.LoadBalancer; import com.yahoo.vespa.hosted.controller.api.integration.deployment.JobType; @@ -57,10 +60,9 @@ public class RoutingPoliciesTest { private final ZoneId zone2 = ZoneId.from("prod", "us-central-1"); private final ZoneId zone3 = ZoneId.from("prod", "us-east-3"); - private final ApplicationPackage applicationPackage = new ApplicationPackageBuilder() - .region(zone1.region()) - .region(zone2.region()) - .build(); + private final ApplicationPackage applicationPackage = applicationPackageBuilder().region(zone1.region()) + .region(zone2.region()) + .build(); @Test public void global_routing_policies() { @@ -69,7 +71,7 @@ public class RoutingPoliciesTest { var context2 = tester.newDeploymentContext("tenant1", "app2", "default"); int clustersPerZone = 2; int numberOfDeployments = 2; - var applicationPackage = new ApplicationPackageBuilder() + var applicationPackage = applicationPackageBuilder() .region(zone1.region()) .region(zone2.region()) .endpoint("r0", "c0") @@ -88,7 +90,7 @@ public class RoutingPoliciesTest { tester.policiesOf(context1.instance().id()).size()); // Applications gains a new deployment - ApplicationPackage applicationPackage2 = new ApplicationPackageBuilder() + ApplicationPackage applicationPackage2 = applicationPackageBuilder() .region(zone1.region()) .region(zone2.region()) .region(zone3.region()) @@ -108,7 +110,7 @@ public class RoutingPoliciesTest { // Another application is deployed with a single cluster and global endpoint var endpoint4 = "r0.app2.tenant1.global.vespa.oath.cloud"; tester.provisionLoadBalancers(1, context2.instanceId(), zone1, zone2); - var applicationPackage3 = new ApplicationPackageBuilder() + var applicationPackage3 = applicationPackageBuilder() .region(zone1.region()) .region(zone2.region()) .endpoint("r0", "c0") @@ -117,7 +119,7 @@ public class RoutingPoliciesTest { tester.assertTargets(context2.instanceId(), EndpointId.of("r0"), 0, zone1, zone2); // All endpoints for app1 are removed - ApplicationPackage applicationPackage4 = new ApplicationPackageBuilder() + ApplicationPackage applicationPackage4 = applicationPackageBuilder() .region(zone1.region()) .region(zone2.region()) .region(zone3.region()) @@ -231,7 +233,7 @@ public class RoutingPoliciesTest { var context = tester.newDeploymentContext("tenant1", "app1", "default"); tester.provisionLoadBalancers(1, context.instanceId(), zone1, zone2); - var applicationPackage = new ApplicationPackageBuilder() + var applicationPackage = applicationPackageBuilder() .region(zone1.region().value()) .endpoint("r0", "c0") .build(); @@ -300,7 +302,7 @@ public class RoutingPoliciesTest { // Initial load balancer is provisioned tester.provisionLoadBalancers(1, context.instanceId(), zone1); - var applicationPackage = new ApplicationPackageBuilder() + var applicationPackage = applicationPackageBuilder() .region(zone1.region()) .build(); @@ -341,7 +343,7 @@ public class RoutingPoliciesTest { // Provision load balancers and deploy application tester.provisionLoadBalancers(1, context.instanceId(), zone1, zone2); - var applicationPackage = new ApplicationPackageBuilder() + var applicationPackage = applicationPackageBuilder() .region(zone1.region()) .region(zone2.region()) .endpoint("r0", "c0", zone1.region().value(), zone2.region().value()) @@ -395,7 +397,7 @@ public class RoutingPoliciesTest { assertEquals(changedAt.truncatedTo(ChronoUnit.MILLIS), policy1.status().globalRouting().changedAt()); // Deployment is set out through a new deployment.xml - var applicationPackage2 = new ApplicationPackageBuilder() + var applicationPackage2 = applicationPackageBuilder() .region(zone1.region()) .region(zone2.region(), false) .endpoint("r0", "c0", zone1.region().value(), zone2.region().value()) @@ -406,7 +408,7 @@ public class RoutingPoliciesTest { tester.assertTargets(context.instanceId(), EndpointId.of("r1"), 0, zone1); // ... back in - var applicationPackage3 = new ApplicationPackageBuilder() + var applicationPackage3 = applicationPackageBuilder() .region(zone1.region()) .region(zone2.region()) .endpoint("r0", "c0", zone1.region().value(), zone2.region().value()) @@ -425,7 +427,7 @@ public class RoutingPoliciesTest { var contexts = List.of(context1, context2); // Deploy applications - var applicationPackage = new ApplicationPackageBuilder() + var applicationPackage = applicationPackageBuilder() .region(zone1.region()) .region(zone2.region()) .endpoint("default", "c0", zone1.region().value(), zone2.region().value()) @@ -493,7 +495,7 @@ public class RoutingPoliciesTest { var context = tester.tester.newDeploymentContext(); var endpointId = EndpointId.of("r0"); - var applicationPackage = new ApplicationPackageBuilder() + var applicationPackage = applicationPackageBuilder() .trustDefaultCertificate() .region(sharedRegion) .endpoint(endpointId.id(), "default") @@ -523,7 +525,7 @@ public class RoutingPoliciesTest { // Provision load balancers and deploy application tester.provisionLoadBalancers(1, context.instanceId(), zone1, zone2); - var applicationPackage = new ApplicationPackageBuilder() + var applicationPackage = applicationPackageBuilder() .region(zone1.region()) .region(zone2.region()) .endpoint("r0", "c0", zone1.region().value(), zone2.region().value()) @@ -571,6 +573,13 @@ public class RoutingPoliciesTest { } tester.assertTargets(context.instanceId(), EndpointId.of("r0"), 0, zone1, zone2); } + + /** Returns an application package builder that satisfies requirements for a directly routed endpoint */ + private static ApplicationPackageBuilder applicationPackageBuilder() { + return new ApplicationPackageBuilder() + .athenzIdentity(AthenzDomain.from("domain"), AthenzService.from("service")) + .compileVersion(RoutingController.DIRECT_ROUTING_MIN_VERSION); + } private static List<LoadBalancer> createLoadBalancers(ZoneId zone, ApplicationId application, int count) { List<LoadBalancer> loadBalancers = new ArrayList<>(); diff --git a/flags/src/main/java/com/yahoo/vespa/flags/Flags.java b/flags/src/main/java/com/yahoo/vespa/flags/Flags.java index 7d1da56a5dc..5a5fbb6bc9a 100644 --- a/flags/src/main/java/com/yahoo/vespa/flags/Flags.java +++ b/flags/src/main/java/com/yahoo/vespa/flags/Flags.java @@ -267,6 +267,12 @@ public class Flags { "Takes effect on internal redeploy", APPLICATION_ID); + public static final UnboundBooleanFlag ALLOW_DIRECT_ROUTING = defineFeatureFlag( + "publish-direct-routing-endpoint", false, + "Whether an application should receive a directly routed endpoint in its endpoint list", + "Takes effect immediately", + APPLICATION_ID); + /** WARNING: public for testing: All flags should be defined in {@link Flags}. */ public static UnboundBooleanFlag defineFeatureFlag(String flagId, boolean defaultValue, String description, String modificationEffect, FetchVector.Dimension... dimensions) { |