diff options
author | Martin Polden <mpolden@mpolden.no> | 2019-04-29 10:48:05 +0200 |
---|---|---|
committer | GitHub <noreply@github.com> | 2019-04-29 10:48:05 +0200 |
commit | c9f9f467df69a65fe1a403f58411259e3c0fa823 (patch) | |
tree | c52ac45e60e388b914536573ecab66a89639f23b /controller-server | |
parent | 086cb954dfd88caaa4e7998e4e3d8cd052db7907 (diff) | |
parent | a7d261ebc83e23449398c9f055c48cd0cebd4fb3 (diff) |
Merge pull request #9218 from vespa-engine/mpolden/expose-routing-policy-endpoint
Add endpoints field for endpoints defined by routing policies
Diffstat (limited to 'controller-server')
17 files changed, 387 insertions, 112 deletions
diff --git a/controller-server/src/main/java/com/yahoo/vespa/hosted/controller/application/Endpoint.java b/controller-server/src/main/java/com/yahoo/vespa/hosted/controller/application/Endpoint.java index 14a5d3c7ddf..ce7af03aa7e 100644 --- a/controller-server/src/main/java/com/yahoo/vespa/hosted/controller/application/Endpoint.java +++ b/controller-server/src/main/java/com/yahoo/vespa/hosted/controller/application/Endpoint.java @@ -26,6 +26,7 @@ public class Endpoint { private final Scope scope; private final boolean legacy; private final boolean directRouting; + private final boolean tls; private Endpoint(String name, ApplicationId application, ZoneId zone, SystemName system, Port port, boolean legacy, boolean directRouting) { @@ -37,6 +38,7 @@ public class Endpoint { this.scope = zone == null ? Scope.global : Scope.zone; this.legacy = legacy; this.directRouting = directRouting; + this.tls = port.tls; } /** Returns the URL used to access this */ @@ -67,6 +69,11 @@ public class Endpoint { return directRouting; } + /** Returns whether this endpoint supports TLS connections */ + public boolean tls() { + return tls; + } + @Override public boolean equals(Object o) { if (this == o) return true; diff --git a/controller-server/src/main/java/com/yahoo/vespa/hosted/controller/application/RoutingPolicy.java b/controller-server/src/main/java/com/yahoo/vespa/hosted/controller/application/RoutingPolicy.java index c4b69ce5588..2fc852d79d5 100644 --- a/controller-server/src/main/java/com/yahoo/vespa/hosted/controller/application/RoutingPolicy.java +++ b/controller-server/src/main/java/com/yahoo/vespa/hosted/controller/application/RoutingPolicy.java @@ -23,28 +23,23 @@ import java.util.Set; public class RoutingPolicy { private final ApplicationId owner; + private final ClusterSpec.Id cluster; private final ZoneId zone; - private final HostName alias; private final HostName canonicalName; private final Optional<String> dnsZone; private final Set<RotationName> rotations; /** DO NOT USE. Public for serialization purposes */ - public RoutingPolicy(ApplicationId owner, ZoneId zone, HostName alias, HostName canonicalName, + public RoutingPolicy(ApplicationId owner, ClusterSpec.Id cluster, ZoneId zone, HostName canonicalName, Optional<String> dnsZone, Set<RotationName> rotations) { this.owner = Objects.requireNonNull(owner, "owner must be non-null"); + this.cluster = Objects.requireNonNull(cluster, "cluster must be non-null"); this.zone = Objects.requireNonNull(zone, "zone must be non-null"); - this.alias = Objects.requireNonNull(alias, "alias must be non-null"); this.canonicalName = Objects.requireNonNull(canonicalName, "canonicalName must be non-null"); this.dnsZone = Objects.requireNonNull(dnsZone, "dnsZone must be non-null"); this.rotations = ImmutableSortedSet.copyOf(Objects.requireNonNull(rotations, "rotations must be non-null")); } - public RoutingPolicy(ApplicationId owner, ZoneId zone, ClusterSpec.Id cluster, SystemName system, HostName canonicalName, - Optional<String> dnsZone, Set<RotationName> rotations) { - this(owner, zone, HostName.from(endpointOf(cluster, owner, zone, system).dnsName()), canonicalName, dnsZone, rotations); - } - /** The application owning this */ public ApplicationId owner() { return owner; @@ -55,9 +50,9 @@ public class RoutingPolicy { return zone; } - /** This alias (lhs of a CNAME or ALIAS record) */ - public HostName alias() { - return alias; + /** The cluster this applies to */ + public ClusterSpec.Id cluster() { + return cluster; } /** The canonical name for this (rhs of a CNAME or ALIAS record) */ @@ -75,8 +70,13 @@ public class RoutingPolicy { return rotations; } - /** Endpoints for this routing policy */ - public EndpointList endpointsIn(SystemName system) { + /** Returns the endpoint of this */ + public Endpoint endpointIn(SystemName system) { + return Endpoint.of(owner).target(cluster, zone).on(Port.tls()).directRouting().in(system); + } + + /** Returns rotation endpoints of this */ + public EndpointList rotationEndpointsIn(SystemName system) { return EndpointList.of(rotations.stream().map(rotation -> endpointOf(owner, rotation, system))); } @@ -86,19 +86,21 @@ public class RoutingPolicy { if (o == null || getClass() != o.getClass()) return false; RoutingPolicy policy = (RoutingPolicy) o; return owner.equals(policy.owner) && + cluster.equals(policy.cluster) && zone.equals(policy.zone) && - canonicalName.equals(policy.canonicalName); + canonicalName.equals(policy.canonicalName) && + dnsZone.equals(policy.dnsZone); } @Override public int hashCode() { - return Objects.hash(owner, zone, canonicalName); + return Objects.hash(owner, cluster, zone, canonicalName, dnsZone); } @Override public String toString() { - return String.format("%s -> %s [rotations: %s%s], owned by %s, in %s", alias, canonicalName, rotations, - dnsZone.map(z -> ", DNS zone: " + z).orElse(""), owner.toShortString(), + return String.format("%s [rotations: %s%s], %s owned by %s, in %s", canonicalName, rotations, + dnsZone.map(z -> ", DNS zone: " + z).orElse(""), cluster, owner.toShortString(), zone.value()); } @@ -107,9 +109,4 @@ public class RoutingPolicy { return Endpoint.of(application).target(rotation).on(Port.tls()).directRouting().in(system); } - /** Returns the endpoint of given cluster */ - public static Endpoint endpointOf(ClusterSpec.Id cluster, ApplicationId application, ZoneId zone, SystemName system) { - return Endpoint.of(application).target(cluster, zone).on(Port.tls()).directRouting().in(system); - } - } diff --git a/controller-server/src/main/java/com/yahoo/vespa/hosted/controller/maintenance/RoutingPolicyMaintainer.java b/controller-server/src/main/java/com/yahoo/vespa/hosted/controller/maintenance/RoutingPolicyMaintainer.java index 417a1944ad3..03d894f9a17 100644 --- a/controller-server/src/main/java/com/yahoo/vespa/hosted/controller/maintenance/RoutingPolicyMaintainer.java +++ b/controller-server/src/main/java/com/yahoo/vespa/hosted/controller/maintenance/RoutingPolicyMaintainer.java @@ -137,11 +137,10 @@ public class RoutingPolicyMaintainer extends Maintainer { /** Register DNS alias for given load balancer */ private RoutingPolicy registerCname(ApplicationId application, ZoneId zone, LoadBalancer loadBalancer) { - RoutingPolicy routingPolicy = new RoutingPolicy(application, zone, - loadBalancer.cluster(), controller().system(), + RoutingPolicy routingPolicy = new RoutingPolicy(application, loadBalancer.cluster(), zone, loadBalancer.hostname(), loadBalancer.dnsZone(), loadBalancer.rotations()); - RecordName name = RecordName.from(routingPolicy.alias().value()); + RecordName name = RecordName.from(routingPolicy.endpointIn(controller().system()).dnsName()); RecordData data = RecordData.fqdn(loadBalancer.hostname().value()); List<Record> existingRecords = nameService.findRecords(Record.Type.CNAME, name); if (existingRecords.size() > 1) { @@ -170,11 +169,12 @@ public class RoutingPolicyMaintainer extends Maintainer { // Remove any active load balancers removalCandidates.removeIf(policy -> activeLoadBalancers.contains(policy.canonicalName())); for (RoutingPolicy policy : removalCandidates) { + String dnsName = policy.endpointIn(controller().system()).dnsName(); try { - List<Record> records = nameService.findRecords(Record.Type.CNAME, RecordName.from(policy.alias().value())); + List<Record> records = nameService.findRecords(Record.Type.CNAME, RecordName.from(dnsName)); nameService.removeRecords(records); } catch (Exception e) { - log.log(LogLevel.WARNING, "Failed to remove record '" + policy.alias() + + log.log(LogLevel.WARNING, "Failed to remove record '" + dnsName + "'. Retrying in " + maintenanceInterval()); } } diff --git a/controller-server/src/main/java/com/yahoo/vespa/hosted/controller/persistence/RoutingPolicySerializer.java b/controller-server/src/main/java/com/yahoo/vespa/hosted/controller/persistence/RoutingPolicySerializer.java index 722cde68c65..7c4f9a66fd3 100644 --- a/controller-server/src/main/java/com/yahoo/vespa/hosted/controller/persistence/RoutingPolicySerializer.java +++ b/controller-server/src/main/java/com/yahoo/vespa/hosted/controller/persistence/RoutingPolicySerializer.java @@ -2,6 +2,7 @@ package com.yahoo.vespa.hosted.controller.persistence; import com.yahoo.config.provision.ApplicationId; +import com.yahoo.config.provision.ClusterSpec; import com.yahoo.config.provision.HostName; import com.yahoo.config.provision.RotationName; import com.yahoo.slime.ArrayTraverser; @@ -21,11 +22,12 @@ import java.util.function.Function; * Serializer and deserializer for a {@link RoutingPolicy}. * * @author mortent + * @author mpolden */ public class RoutingPolicySerializer { private static final String routingPoliciesField = "routingPolicies"; - private static final String aliasField = "alias"; + private static final String clusterField = "cluster"; private static final String canonicalNameField = "canonicalName"; private static final String zoneField = "zone"; private static final String dnsZoneField = "dnsZone"; @@ -37,7 +39,7 @@ public class RoutingPolicySerializer { Cursor policyArray = root.setArray(routingPoliciesField); routingPolicies.forEach(policy -> { Cursor policyObject = policyArray.addObject(); - policyObject.setString(aliasField, policy.alias().value()); + policyObject.setString(clusterField, policy.cluster().value()); policyObject.setString(zoneField, policy.zone().value()); policyObject.setString(canonicalNameField, policy.canonicalName().value()); policy.dnsZone().ifPresent(dnsZone -> policyObject.setString(dnsZoneField, dnsZone)); @@ -57,8 +59,8 @@ public class RoutingPolicySerializer { Set<RotationName> rotations = new LinkedHashSet<>(); inspect.field(rotationsField).traverse((ArrayTraverser) (j, rotation) -> rotations.add(RotationName.from(rotation.asString()))); policies.add(new RoutingPolicy(owner, + clusterId(inspect.field(clusterField)), ZoneId.from(inspect.field(zoneField).asString()), - HostName.from(inspect.field(aliasField).asString()), HostName.from(inspect.field(canonicalNameField).asString()), optionalField(inspect.field(dnsZoneField), Function.identity()), rotations)); @@ -66,6 +68,11 @@ public class RoutingPolicySerializer { return Collections.unmodifiableSet(policies); } + // TODO: Remove and inline after Vespa 7.43 + private static ClusterSpec.Id clusterId(Inspector field) { + return optionalField(field, ClusterSpec.Id::from).orElseGet(() -> new ClusterSpec.Id("default")); + } + private static <T> Optional<T> optionalField(Inspector field, Function<String, T> fieldMapper) { return Optional.of(field).filter(Inspector::valid).map(Inspector::asString).map(fieldMapper); } 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 74206d05009..1b9bf28f395 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 @@ -508,7 +508,7 @@ public class ApplicationApiHandler extends LoggingRequestHandler { // Per-cluster rotations Set<RoutingPolicy> routingPolicies = controller.applications().routingPolicies(application.id()); for (RoutingPolicy policy : routingPolicies) { - policy.endpointsIn(controller.system()).asList().stream() + policy.rotationEndpointsIn(controller.system()).asList().stream() .map(Endpoint::url) .map(URI::toString) .forEach(globalRotationsArray::addString); @@ -584,13 +584,22 @@ public class ApplicationApiHandler extends LoggingRequestHandler { } private void toSlime(Cursor response, DeploymentId deploymentId, Deployment deployment, HttpRequest request) { - response.setString("tenant", deploymentId.applicationId().tenant().value()); response.setString("application", deploymentId.applicationId().application().value()); response.setString("instance", deploymentId.applicationId().instance().value()); // pointless response.setString("environment", deploymentId.zoneId().environment().value()); response.setString("region", deploymentId.zoneId().region().value()); + // Add endpoint(s) defined by routing policies + var endpointArray = response.setArray("endpoints"); + for (var policy : controller.applications().routingPolicies(deploymentId.applicationId())) { + Cursor endpointObject = endpointArray.addObject(); + Endpoint endpoint = policy.endpointIn(controller.system()); + endpointObject.setString("cluster", policy.cluster().value()); + endpointObject.setBool("tls", endpoint.tls()); + endpointObject.setString("url", endpoint.url().toString()); + } + // serviceUrls contains zone/cluster-specific endpoints for this deployment. The name of these endpoints may // contain the cluster name (if non-default) and since the controller has no knowledge of clusters, we have to // ask the routing layer here diff --git a/controller-server/src/test/java/com/yahoo/vespa/hosted/controller/maintenance/RoutingPolicyMaintainerTest.java b/controller-server/src/test/java/com/yahoo/vespa/hosted/controller/maintenance/RoutingPolicyMaintainerTest.java index 0541a0b05f5..b0f64eee532 100644 --- a/controller-server/src/test/java/com/yahoo/vespa/hosted/controller/maintenance/RoutingPolicyMaintainerTest.java +++ b/controller-server/src/test/java/com/yahoo/vespa/hosted/controller/maintenance/RoutingPolicyMaintainerTest.java @@ -72,7 +72,7 @@ public class RoutingPolicyMaintainerTest { assertEquals("lb-0--tenant1:app1:default--prod.us-central-1.", records2.get().get(0).data().asString()); assertEquals("lb-0--tenant1:app1:default--prod.us-west-1.", records2.get().get(1).data().asString()); assertEquals(2, tester.controller().applications().routingPolicies(app1.id()).iterator().next() - .endpointsIn(SystemName.main).asList().size()); + .rotationEndpointsIn(SystemName.main).asList().size()); // Applications gains a new deployment ApplicationPackage updatedApplicationPackage = new ApplicationPackageBuilder() diff --git a/controller-server/src/test/java/com/yahoo/vespa/hosted/controller/persistence/RoutingPolicySerializerTest.java b/controller-server/src/test/java/com/yahoo/vespa/hosted/controller/persistence/RoutingPolicySerializerTest.java index 4fe465ce01e..4a4fd39ccb7 100644 --- a/controller-server/src/test/java/com/yahoo/vespa/hosted/controller/persistence/RoutingPolicySerializerTest.java +++ b/controller-server/src/test/java/com/yahoo/vespa/hosted/controller/persistence/RoutingPolicySerializerTest.java @@ -3,9 +3,11 @@ package com.yahoo.vespa.hosted.controller.persistence; import com.google.common.collect.ImmutableSet; import com.yahoo.config.provision.ApplicationId; +import com.yahoo.config.provision.ClusterSpec; import com.yahoo.config.provision.HostName; import com.yahoo.config.provision.RotationName; import com.yahoo.config.provision.zone.ZoneId; +import com.yahoo.vespa.config.SlimeUtils; import com.yahoo.vespa.hosted.controller.application.RoutingPolicy; import org.junit.Test; @@ -19,20 +21,21 @@ import static org.junit.Assert.assertEquals; */ public class RoutingPolicySerializerTest { + private final RoutingPolicySerializer serializer = new RoutingPolicySerializer(); + @Test public void test_serialization() { - RoutingPolicySerializer serializer = new RoutingPolicySerializer(); ApplicationId owner = ApplicationId.defaultId(); Set<RotationName> rotations = Set.of(RotationName.from("r1"), RotationName.from("r2")); Set<RoutingPolicy> loadBalancers = ImmutableSet.of(new RoutingPolicy(owner, + ClusterSpec.Id.from("my-cluster1"), ZoneId.from("prod", "us-north-1"), - HostName.from("my-pretty-alias"), HostName.from("long-and-ugly-name"), Optional.of("zone1"), rotations), new RoutingPolicy(owner, + ClusterSpec.Id.from("my-cluster2"), ZoneId.from("prod", "us-north-2"), - HostName.from("my-pretty-alias-2"), HostName.from("long-and-ugly-name-2"), Optional.empty(), rotations)); @@ -40,4 +43,30 @@ public class RoutingPolicySerializerTest { assertEquals(loadBalancers, serialized); } + @Test + public void test_legacy_serialization() { // TODO: Remove after 7.43 has been released + String json = "{\n" + + " \"routingPolicies\": [\n" + + " {\n" + + " \"alias\": \"my-pretty-alias\",\n" + + " \"zone\": \"prod.us-north-1\",\n" + + " \"canonicalName\": \"long-and-ugly-name\",\n" + + " \"dnsZone\": \"zone1\",\n" + + " \"rotations\": [\n" + + " \"r1\",\n" + + " \"r2\"\n" + + " ]\n" + + " }\n" + + " ]\n" + + "}"; + ApplicationId owner = ApplicationId.defaultId(); + Set<RoutingPolicy> expected = Set.of(new RoutingPolicy(owner, + ClusterSpec.Id.from("default"), + ZoneId.from("prod", "us-north-1"), + HostName.from("long-and-ugly-name"), + Optional.of("zone1"), + Set.of(RotationName.from("r1"), RotationName.from("r2")))); + assertEquals(expected, serializer.fromSlime(owner, SlimeUtils.jsonToSlime(json))); + } + } diff --git a/controller-server/src/test/java/com/yahoo/vespa/hosted/controller/restapi/ContainerControllerTester.java b/controller-server/src/test/java/com/yahoo/vespa/hosted/controller/restapi/ContainerControllerTester.java index d9cdea2ea7b..c851cb18e8c 100644 --- a/controller-server/src/test/java/com/yahoo/vespa/hosted/controller/restapi/ContainerControllerTester.java +++ b/controller-server/src/test/java/com/yahoo/vespa/hosted/controller/restapi/ContainerControllerTester.java @@ -4,7 +4,9 @@ package com.yahoo.vespa.hosted.controller.restapi; import com.yahoo.application.container.JDisc; import com.yahoo.application.container.handler.Request; import com.yahoo.config.provision.ApplicationId; +import com.yahoo.config.provision.Environment; import com.yahoo.config.provision.TenantName; +import com.yahoo.config.provision.zone.ZoneId; import com.yahoo.vespa.athenz.api.AthenzDomain; import com.yahoo.vespa.athenz.api.AthenzPrincipal; import com.yahoo.vespa.athenz.api.AthenzUser; @@ -15,23 +17,23 @@ import com.yahoo.vespa.hosted.controller.api.application.v4.model.DeployOptions; import com.yahoo.vespa.hosted.controller.api.identifiers.Property; import com.yahoo.vespa.hosted.controller.api.identifiers.PropertyId; import com.yahoo.vespa.hosted.controller.api.identifiers.ScrewdriverId; -import com.yahoo.vespa.hosted.controller.athenz.ApplicationAction; -import com.yahoo.vespa.hosted.controller.athenz.HostedAthenzIdentities; import com.yahoo.vespa.hosted.controller.api.integration.deployment.JobType; import com.yahoo.vespa.hosted.controller.api.integration.stubs.MockBuildService; -import com.yahoo.config.provision.zone.ZoneId; import com.yahoo.vespa.hosted.controller.application.ApplicationPackage; import com.yahoo.vespa.hosted.controller.application.DeploymentJobs; +import com.yahoo.vespa.hosted.controller.athenz.ApplicationAction; +import com.yahoo.vespa.hosted.controller.athenz.HostedAthenzIdentities; import com.yahoo.vespa.hosted.controller.athenz.mock.AthenzClientFactoryMock; import com.yahoo.vespa.hosted.controller.athenz.mock.AthenzDbMock; import com.yahoo.vespa.hosted.controller.deployment.BuildJob; +import com.yahoo.vespa.hosted.controller.deployment.DeploymentSteps; import com.yahoo.vespa.hosted.controller.integration.ArtifactRepositoryMock; import com.yahoo.vespa.hosted.controller.maintenance.JobControl; import com.yahoo.vespa.hosted.controller.maintenance.Upgrader; -import com.yahoo.vespa.hosted.controller.security.AthenzCredentials; -import com.yahoo.vespa.hosted.controller.security.AthenzTenantSpec; import com.yahoo.vespa.hosted.controller.persistence.CuratorDb; import com.yahoo.vespa.hosted.controller.persistence.MockCuratorDb; +import com.yahoo.vespa.hosted.controller.security.AthenzCredentials; +import com.yahoo.vespa.hosted.controller.security.AthenzTenantSpec; import java.io.File; import java.time.Duration; @@ -94,6 +96,28 @@ public class ContainerControllerTester { return application; } + public void deployCompletely(Application application, ApplicationPackage applicationPackage, long projectId, + boolean failStaging) { + jobCompletion(JobType.component).application(application) + .projectId(projectId) + .uploadArtifact(applicationPackage) + .submit(); + DeploymentSteps steps = controller().applications().deploymentTrigger().steps(applicationPackage.deploymentSpec()); + boolean succeeding = true; + for (var job : steps.jobs()) { + if (!succeeding) return; + var zone = job.zone(controller().system()); + deploy(application, applicationPackage, zone); + if (failStaging && zone.environment() == Environment.staging) { + succeeding = false; + } + if (zone.environment().isTest()) { + controller().applications().deactivate(application.id(), zone); + } + jobCompletion(job).application(application).success(succeeding).projectId(projectId).submit(); + } + } + /** Notify the controller about a job completing */ public BuildJob jobCompletion(JobType job) { return new BuildJob(this::notifyJobCompletion, artifactRepository()).type(job); diff --git a/controller-server/src/test/java/com/yahoo/vespa/hosted/controller/restapi/ContainerTester.java b/controller-server/src/test/java/com/yahoo/vespa/hosted/controller/restapi/ContainerTester.java index 11ac250d4e0..ef86ffa125f 100644 --- a/controller-server/src/test/java/com/yahoo/vespa/hosted/controller/restapi/ContainerTester.java +++ b/controller-server/src/test/java/com/yahoo/vespa/hosted/controller/restapi/ContainerTester.java @@ -6,11 +6,11 @@ import com.yahoo.application.container.handler.Request; import com.yahoo.application.container.handler.Response; import com.yahoo.component.ComponentSpecification; import com.yahoo.component.Version; +import com.yahoo.config.provision.zone.ZoneId; import com.yahoo.container.http.filter.FilterChainRepository; import com.yahoo.jdisc.http.filter.SecurityRequestFilter; import com.yahoo.jdisc.http.filter.SecurityRequestFilterChain; import com.yahoo.vespa.hosted.controller.Controller; -import com.yahoo.config.provision.zone.ZoneId; import com.yahoo.vespa.hosted.controller.application.SystemApplication; import com.yahoo.vespa.hosted.controller.integration.ConfigServerMock; import com.yahoo.vespa.hosted.controller.versions.VersionStatus; 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 d3f0f423089..a7a28591d62 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 @@ -11,6 +11,7 @@ import com.yahoo.config.provision.HostName; import com.yahoo.config.provision.RegionName; import com.yahoo.config.provision.RotationName; import com.yahoo.config.provision.TenantName; +import com.yahoo.config.provision.zone.ZoneId; import com.yahoo.slime.Cursor; import com.yahoo.slime.Slime; import com.yahoo.vespa.athenz.api.AthenzDomain; @@ -34,7 +35,6 @@ import com.yahoo.vespa.hosted.controller.api.integration.organization.Contact; import com.yahoo.vespa.hosted.controller.api.integration.organization.IssueId; import com.yahoo.vespa.hosted.controller.api.integration.organization.MockContactRetriever; import com.yahoo.vespa.hosted.controller.api.integration.organization.User; -import com.yahoo.config.provision.zone.ZoneId; import com.yahoo.vespa.hosted.controller.application.ApplicationPackage; import com.yahoo.vespa.hosted.controller.application.Change; import com.yahoo.vespa.hosted.controller.application.ClusterInfo; @@ -1344,10 +1344,16 @@ public class ApplicationApiTest extends ControllerContainerTest { } @Test - public void applicationWithPerClusterGlobalRotation() { + public void applicationWithRoutingPolicy() { Application app = controllerTester.createApplication(); - RoutingPolicy policy = new RoutingPolicy(app.id(), ZoneId.from(Environment.prod, RegionName.from("us-west-1")), - ClusterSpec.Id.from("default"), controllerTester.controller().system(), + ApplicationPackage applicationPackage = new ApplicationPackageBuilder() + .environment(Environment.prod) + .region("us-west-1") + .build(); + controllerTester.deployCompletely(app, applicationPackage, 1, false); + RoutingPolicy policy = new RoutingPolicy(app.id(), + ClusterSpec.Id.from("default"), + ZoneId.from(Environment.prod, RegionName.from("us-west-1")), HostName.from("lb-0-canonical-name"), Optional.of("dns-zone-1"), Set.of(RotationName.from("c0"))); tester.controller().curator().writeRoutingPolicies(app.id(), Set.of(policy)); @@ -1355,7 +1361,12 @@ public class ApplicationApiTest extends ControllerContainerTest { // GET application tester.assertResponse(request("/application/v4/tenant/tenant1/application/application1", GET) .userIdentity(USER_ID), - new File("application-cluster-global-rotation.json")); + new File("application-with-routing-policy.json")); + + // GET deployment + tester.assertResponse(request("/application/v4/tenant/tenant1/application/application1/environment/prod/region/us-west-1/instance/default", GET) + .userIdentity(USER_ID), + new File("deployment-with-routing-policy.json")); } private void notifyCompletion(DeploymentJobs.JobReport report, ContainerControllerTester tester) { diff --git a/controller-server/src/test/java/com/yahoo/vespa/hosted/controller/restapi/application/responses/application-cluster-global-rotation.json b/controller-server/src/test/java/com/yahoo/vespa/hosted/controller/restapi/application/responses/application-cluster-global-rotation.json deleted file mode 100644 index baaf0cd038d..00000000000 --- a/controller-server/src/test/java/com/yahoo/vespa/hosted/controller/restapi/application/responses/application-cluster-global-rotation.json +++ /dev/null @@ -1,19 +0,0 @@ -{ - "tenant": "tenant1", - "application": "application1", - "instance": "default", - "deployments": "http://localhost:8080/application/v4/tenant/tenant1/application/application1/instance/default/job/", - "deployedInternally": false, - "deploymentJobs": [], - "changeBlockers": [], - "compileVersion": "(ignore)", - "globalRotations": [ - "https://c0.application1.tenant1.global.vespa.oath.cloud/" - ], - "instances": [], - "metrics": { - "queryServiceQuality": 0.0, - "writeServiceQuality": 0.0 - }, - "activity": {} -} diff --git a/controller-server/src/test/java/com/yahoo/vespa/hosted/controller/restapi/application/responses/application-with-routing-policy.json b/controller-server/src/test/java/com/yahoo/vespa/hosted/controller/restapi/application/responses/application-with-routing-policy.json new file mode 100644 index 00000000000..627afbf2674 --- /dev/null +++ b/controller-server/src/test/java/com/yahoo/vespa/hosted/controller/restapi/application/responses/application-with-routing-policy.json @@ -0,0 +1,203 @@ +{ + "tenant": "tenant1", + "application": "application1", + "instance": "default", + "deployments": "http://localhost:8080/application/v4/tenant/tenant1/application/application1/instance/default/job/", + "source": { + "gitRepository": "repository1", + "gitBranch": "master", + "gitCommit": "commit1" + }, + "projectId": 1, + "deployedInternally": false, + "deploymentJobs": [ + { + "type": "component", + "success": true, + "lastCompleted": { + "id": 42, + "version": "(ignore)", + "revision": { + "hash": "1.0.42-commit1", + "source": { + "gitRepository": "repository1", + "gitBranch": "master", + "gitCommit": "commit1" + } + }, + "reason": "Application commit", + "at": "(ignore)" + }, + "lastSuccess": { + "id": 42, + "version": "(ignore)", + "revision": { + "hash": "1.0.42-commit1", + "source": { + "gitRepository": "repository1", + "gitBranch": "master", + "gitCommit": "commit1" + } + }, + "reason": "Application commit", + "at": "(ignore)" + } + }, + { + "type": "system-test", + "success": true, + "lastTriggered": { + "id": -1, + "version": "(ignore)", + "revision": { + "hash": "1.0.42-commit1", + "source": { + "gitRepository": "repository1", + "gitBranch": "master", + "gitCommit": "commit1" + } + }, + "reason": "Testing last changes outside prod", + "at": "(ignore)" + }, + "lastCompleted": { + "id": 42, + "version": "(ignore)", + "revision": { + "hash": "1.0.42-commit1", + "source": { + "gitRepository": "repository1", + "gitBranch": "master", + "gitCommit": "commit1" + } + }, + "reason": "Testing last changes outside prod", + "at": "(ignore)" + }, + "lastSuccess": { + "id": 42, + "version": "(ignore)", + "revision": { + "hash": "1.0.42-commit1", + "source": { + "gitRepository": "repository1", + "gitBranch": "master", + "gitCommit": "commit1" + } + }, + "reason": "Testing last changes outside prod", + "at": "(ignore)" + } + }, + { + "type": "staging-test", + "success": true, + "lastTriggered": { + "id": -1, + "version": "(ignore)", + "revision": { + "hash": "1.0.42-commit1", + "source": { + "gitRepository": "repository1", + "gitBranch": "master", + "gitCommit": "commit1" + } + }, + "reason": "Testing deployment for production-us-west-1 (platform (ignore), application 1.0.42-commit1)", + "at": "(ignore)" + }, + "lastCompleted": { + "id": 42, + "version": "(ignore)", + "revision": { + "hash": "1.0.42-commit1", + "source": { + "gitRepository": "repository1", + "gitBranch": "master", + "gitCommit": "commit1" + } + }, + "reason": "Testing deployment for production-us-west-1 (platform (ignore), application 1.0.42-commit1)", + "at": "(ignore)" + }, + "lastSuccess": { + "id": 42, + "version": "(ignore)", + "revision": { + "hash": "1.0.42-commit1", + "source": { + "gitRepository": "repository1", + "gitBranch": "master", + "gitCommit": "commit1" + } + }, + "reason": "Testing deployment for production-us-west-1 (platform (ignore), application 1.0.42-commit1)", + "at": "(ignore)" + } + }, + { + "type": "production-us-west-1", + "success": true, + "lastTriggered": { + "id": -1, + "version": "(ignore)", + "revision": { + "hash": "1.0.42-commit1", + "source": { + "gitRepository": "repository1", + "gitBranch": "master", + "gitCommit": "commit1" + } + }, + "reason": "New change available", + "at": "(ignore)" + }, + "lastCompleted": { + "id": 42, + "version": "(ignore)", + "revision": { + "hash": "1.0.42-commit1", + "source": { + "gitRepository": "repository1", + "gitBranch": "master", + "gitCommit": "commit1" + } + }, + "reason": "New change available", + "at": "(ignore)" + }, + "lastSuccess": { + "id": 42, + "version": "(ignore)", + "revision": { + "hash": "1.0.42-commit1", + "source": { + "gitRepository": "repository1", + "gitBranch": "master", + "gitCommit": "commit1" + } + }, + "reason": "New change available", + "at": "(ignore)" + } + } + ], + "changeBlockers": [], + "compileVersion": "(ignore)", + "globalRotations": [ + "https://c0.application1.tenant1.global.vespa.oath.cloud/" + ], + "instances": [ + { + "environment": "prod", + "region": "us-west-1", + "instance": "default", + "url": "http://localhost:8080/application/v4/tenant/tenant1/application/application1/environment/prod/region/us-west-1/instance/default" + } + ], + "metrics": { + "queryServiceQuality": 0.0, + "writeServiceQuality": 0.0 + }, + "activity": {} +} diff --git a/controller-server/src/test/java/com/yahoo/vespa/hosted/controller/restapi/application/responses/deployment-with-routing-policy.json b/controller-server/src/test/java/com/yahoo/vespa/hosted/controller/restapi/application/responses/deployment-with-routing-policy.json new file mode 100644 index 00000000000..519c9b1c842 --- /dev/null +++ b/controller-server/src/test/java/com/yahoo/vespa/hosted/controller/restapi/application/responses/deployment-with-routing-policy.json @@ -0,0 +1,44 @@ +{ + "tenant": "tenant1", + "application": "application1", + "instance": "default", + "environment": "prod", + "region": "us-west-1", + "endpoints": [ + { + "cluster": "default", + "tls": true, + "url": "https://application1.tenant1.us-west-1.vespa.oath.cloud/" + } + ], + "serviceUrls": [ + "http://old-endpoint.vespa.yahooapis.com:4080", + "http://qrs-endpoint.vespa.yahooapis.com:4080", + "http://feeding-endpoint.vespa.yahooapis.com:4080", + "http://global-endpoint.vespa.yahooapis.com:4080", + "http://alias-endpoint.vespa.yahooapis.com:4080" + ], + "nodes": "http://localhost:8080/zone/v2/prod/us-west-1/nodes/v2/node/%3F&recursive=true&application=tenant1.application1.default", + "yamasUrl": "http://monitoring-system.test/?environment=prod®ion=us-west-1&application=tenant1.application1", + "version": "(ignore)", + "revision": "1.0.42-commit1", + "deployTimeEpochMs": "(ignore)", + "screwdriverId": "1", + "gitRepository": "repository1", + "gitBranch": "master", + "gitCommit": "commit1", + "activity": {}, + "cost": { + "tco": 0, + "waste": 0, + "utilization": 0.0, + "cluster": {} + }, + "metrics": { + "queriesPerSecond": 0.0, + "writesPerSecond": 0.0, + "documentCount": 0.0, + "queryLatencyMillis": 0.0, + "writeLatencyMillis": 0.0 + } +} diff --git a/controller-server/src/test/java/com/yahoo/vespa/hosted/controller/restapi/application/responses/deployment.json b/controller-server/src/test/java/com/yahoo/vespa/hosted/controller/restapi/application/responses/deployment.json index af21260676c..6caac3bd532 100644 --- a/controller-server/src/test/java/com/yahoo/vespa/hosted/controller/restapi/application/responses/deployment.json +++ b/controller-server/src/test/java/com/yahoo/vespa/hosted/controller/restapi/application/responses/deployment.json @@ -4,6 +4,7 @@ "instance": "default", "environment": "prod", "region": "us-central-1", + "endpoints": [], "serviceUrls": [ "http://old-endpoint.vespa.yahooapis.com:4080", "http://qrs-endpoint.vespa.yahooapis.com:4080", diff --git a/controller-server/src/test/java/com/yahoo/vespa/hosted/controller/restapi/application/responses/dev-us-west-1.json b/controller-server/src/test/java/com/yahoo/vespa/hosted/controller/restapi/application/responses/dev-us-west-1.json index 54e94c4521e..67c71ee3880 100644 --- a/controller-server/src/test/java/com/yahoo/vespa/hosted/controller/restapi/application/responses/dev-us-west-1.json +++ b/controller-server/src/test/java/com/yahoo/vespa/hosted/controller/restapi/application/responses/dev-us-west-1.json @@ -4,6 +4,7 @@ "instance": "default", "environment": "dev", "region": "us-west-1", + "endpoints": [], "serviceUrls": [ "http://old-endpoint.vespa.yahooapis.com:4080", "http://qrs-endpoint.vespa.yahooapis.com:4080", diff --git a/controller-server/src/test/java/com/yahoo/vespa/hosted/controller/restapi/application/responses/prod-us-central-1.json b/controller-server/src/test/java/com/yahoo/vespa/hosted/controller/restapi/application/responses/prod-us-central-1.json index cfefe629b9a..9b08fccf883 100644 --- a/controller-server/src/test/java/com/yahoo/vespa/hosted/controller/restapi/application/responses/prod-us-central-1.json +++ b/controller-server/src/test/java/com/yahoo/vespa/hosted/controller/restapi/application/responses/prod-us-central-1.json @@ -7,6 +7,7 @@ "instance": "default", "environment": "prod", "region": "us-central-1", + "endpoints": [], "serviceUrls": [ "http://old-endpoint.vespa.yahooapis.com:4080", "http://qrs-endpoint.vespa.yahooapis.com:4080", diff --git a/controller-server/src/test/java/com/yahoo/vespa/hosted/controller/restapi/deployment/DeploymentApiTest.java b/controller-server/src/test/java/com/yahoo/vespa/hosted/controller/restapi/deployment/DeploymentApiTest.java index 575427c9222..73977d7c2fa 100644 --- a/controller-server/src/test/java/com/yahoo/vespa/hosted/controller/restapi/deployment/DeploymentApiTest.java +++ b/controller-server/src/test/java/com/yahoo/vespa/hosted/controller/restapi/deployment/DeploymentApiTest.java @@ -5,18 +5,15 @@ import com.google.common.collect.ImmutableSet; import com.yahoo.component.Version; import com.yahoo.config.provision.Environment; import com.yahoo.config.provision.HostName; -import com.yahoo.config.provision.RegionName; +import com.yahoo.config.provision.zone.ZoneId; import com.yahoo.vespa.hosted.controller.Application; import com.yahoo.vespa.hosted.controller.Controller; -import com.yahoo.vespa.hosted.controller.api.integration.deployment.JobType; -import com.yahoo.config.provision.zone.ZoneId; import com.yahoo.vespa.hosted.controller.application.ApplicationPackage; import com.yahoo.vespa.hosted.controller.deployment.ApplicationPackageBuilder; import com.yahoo.vespa.hosted.controller.restapi.ContainerControllerTester; import com.yahoo.vespa.hosted.controller.restapi.ControllerContainerTest; import com.yahoo.vespa.hosted.controller.versions.VersionStatus; import com.yahoo.vespa.hosted.controller.versions.VespaVersion; -import org.junit.Before; import org.junit.Test; import java.io.File; @@ -31,13 +28,6 @@ public class DeploymentApiTest extends ControllerContainerTest { private final static String responseFiles = "src/test/java/com/yahoo/vespa/hosted/controller/restapi/deployment/responses/"; - private ContainerControllerTester tester; - - @Before - public void before() { - tester = new ContainerControllerTester(container, responseFiles); - } - @Test public void testDeploymentApi() { ContainerControllerTester tester = new ContainerControllerTester(container, responseFiles); @@ -55,11 +45,11 @@ public class DeploymentApiTest extends ControllerContainerTest { "application2"); Application applicationWithoutDeployment = tester.createApplication("domain3", "tenant3", "application3"); - deployCompletely(failingApplication, applicationPackage, 1L, true); - deployCompletely(productionApplication, applicationPackage, 2L, true); + tester.deployCompletely(failingApplication, applicationPackage, 1L, false); + tester.deployCompletely(productionApplication, applicationPackage, 2L, false); // Deploy once so that job information is stored, then remove the deployment - deployCompletely(applicationWithoutDeployment, applicationPackage, 3L, true); + tester.deployCompletely(applicationWithoutDeployment, applicationPackage, 3L, false); tester.controller().applications().deactivate(applicationWithoutDeployment.id(), ZoneId.from("prod", "us-west-1")); // New version released @@ -70,8 +60,8 @@ public class DeploymentApiTest extends ControllerContainerTest { tester.upgrader().maintain(); tester.controller().applications().deploymentTrigger().triggerReadyJobs(); tester.controller().applications().deploymentTrigger().triggerReadyJobs(); - deployCompletely(failingApplication, applicationPackage, 1L, false); - deployCompletely(productionApplication, applicationPackage, 2L, true); + tester.deployCompletely(failingApplication, applicationPackage, 1L, true); + tester.deployCompletely(productionApplication, applicationPackage, 2L, false); tester.controller().updateVersionStatus(censorConfigServers(VersionStatus.compute(tester.controller()), tester.controller())); @@ -98,34 +88,4 @@ public class DeploymentApiTest extends ControllerContainerTest { return new VersionStatus(censored); } - private void deployCompletely(Application application, ApplicationPackage applicationPackage, long projectId, - boolean success) { - tester.jobCompletion(JobType.component) - .application(application) - .projectId(projectId) - .uploadArtifact(applicationPackage) - .submit(); - tester.deploy(application, applicationPackage, ZoneId.from(Environment.test, RegionName.from("us-east-1")) - ); - tester.jobCompletion(JobType.systemTest) - .application(application) - .projectId(projectId) - .submit(); - tester.deploy(application, applicationPackage, ZoneId.from(Environment.staging, RegionName.from("us-east-3")) - ); - tester.jobCompletion(JobType.stagingTest) - .application(application) - .projectId(projectId) - .success(success) - .submit(); - if (success) { - tester.deploy(application, applicationPackage, ZoneId.from(Environment.prod, - RegionName.from("us-west-1"))); - tester.jobCompletion(JobType.productionUsWest1) - .application(application) - .projectId(projectId) - .submit(); - } - } - } |