summaryrefslogtreecommitdiffstats
path: root/controller-server/src/test/java
diff options
context:
space:
mode:
Diffstat (limited to 'controller-server/src/test/java')
-rw-r--r--controller-server/src/test/java/com/yahoo/vespa/hosted/controller/ControllerTest.java187
-rw-r--r--controller-server/src/test/java/com/yahoo/vespa/hosted/controller/application/EndpointTest.java80
-rw-r--r--controller-server/src/test/java/com/yahoo/vespa/hosted/controller/application/pkg/ApplicationPackageTest.java22
-rw-r--r--controller-server/src/test/java/com/yahoo/vespa/hosted/controller/archive/CuratorArchiveBucketDbTest.java13
-rw-r--r--controller-server/src/test/java/com/yahoo/vespa/hosted/controller/deployment/ApplicationPackageBuilder.java18
-rw-r--r--controller-server/src/test/java/com/yahoo/vespa/hosted/controller/deployment/DeploymentContext.java23
-rw-r--r--controller-server/src/test/java/com/yahoo/vespa/hosted/controller/deployment/DeploymentTriggerTest.java672
-rw-r--r--controller-server/src/test/java/com/yahoo/vespa/hosted/controller/deployment/InternalStepRunnerTest.java47
-rw-r--r--controller-server/src/test/java/com/yahoo/vespa/hosted/controller/integration/ServiceRegistryMock.java20
-rw-r--r--controller-server/src/test/java/com/yahoo/vespa/hosted/controller/integration/ZoneRegistryMock.java51
-rw-r--r--controller-server/src/test/java/com/yahoo/vespa/hosted/controller/maintenance/ArchiveAccessMaintainerTest.java9
-rw-r--r--controller-server/src/test/java/com/yahoo/vespa/hosted/controller/maintenance/ArchiveUriUpdaterTest.java3
-rw-r--r--controller-server/src/test/java/com/yahoo/vespa/hosted/controller/maintenance/DeploymentIssueReporterTest.java17
-rw-r--r--controller-server/src/test/java/com/yahoo/vespa/hosted/controller/maintenance/MetricsReporterTest.java2
-rw-r--r--controller-server/src/test/java/com/yahoo/vespa/hosted/controller/maintenance/OutstandingChangeDeployerTest.java49
-rw-r--r--controller-server/src/test/java/com/yahoo/vespa/hosted/controller/maintenance/UpgraderTest.java21
-rw-r--r--controller-server/src/test/java/com/yahoo/vespa/hosted/controller/persistence/ApplicationSerializerTest.java20
-rw-r--r--controller-server/src/test/java/com/yahoo/vespa/hosted/controller/persistence/RunSerializerTest.java3
-rw-r--r--controller-server/src/test/java/com/yahoo/vespa/hosted/controller/persistence/testdata/run-status.json1
-rw-r--r--controller-server/src/test/java/com/yahoo/vespa/hosted/controller/restapi/ControllerContainerCloudTest.java10
-rw-r--r--controller-server/src/test/java/com/yahoo/vespa/hosted/controller/restapi/application/ApplicationApiCloudTest.java4
-rw-r--r--controller-server/src/test/java/com/yahoo/vespa/hosted/controller/restapi/application/ApplicationApiTest.java31
-rw-r--r--controller-server/src/test/java/com/yahoo/vespa/hosted/controller/restapi/application/JobControllerApiHandlerHelperTest.java2
-rw-r--r--controller-server/src/test/java/com/yahoo/vespa/hosted/controller/restapi/application/MultipartParserTest.java4
-rw-r--r--controller-server/src/test/java/com/yahoo/vespa/hosted/controller/restapi/application/responses/deployment-cloud.json1
-rw-r--r--controller-server/src/test/java/com/yahoo/vespa/hosted/controller/restapi/application/responses/deployment-overview-2.json35
-rw-r--r--controller-server/src/test/java/com/yahoo/vespa/hosted/controller/restapi/application/responses/deployment-overview.json52
-rw-r--r--controller-server/src/test/java/com/yahoo/vespa/hosted/controller/restapi/application/responses/deployment-with-routing-policy-legacy.json72
-rw-r--r--controller-server/src/test/java/com/yahoo/vespa/hosted/controller/restapi/application/responses/deployment-with-routing-policy.json8
-rw-r--r--controller-server/src/test/java/com/yahoo/vespa/hosted/controller/restapi/application/responses/deployment.json8
-rw-r--r--controller-server/src/test/java/com/yahoo/vespa/hosted/controller/restapi/application/responses/dev-us-east-1-log-second-part.json2
-rw-r--r--controller-server/src/test/java/com/yahoo/vespa/hosted/controller/restapi/application/responses/dev-us-east-1.json4
-rw-r--r--controller-server/src/test/java/com/yahoo/vespa/hosted/controller/restapi/application/responses/prod-us-central-1.json10
-rw-r--r--controller-server/src/test/java/com/yahoo/vespa/hosted/controller/restapi/application/responses/staging-test-log.json16
-rw-r--r--controller-server/src/test/java/com/yahoo/vespa/hosted/controller/restapi/application/responses/system-test-details.json90
-rw-r--r--controller-server/src/test/java/com/yahoo/vespa/hosted/controller/restapi/application/responses/system-test-log.json90
-rw-r--r--controller-server/src/test/java/com/yahoo/vespa/hosted/controller/restapi/application/responses/test-config-dev.json8
-rw-r--r--controller-server/src/test/java/com/yahoo/vespa/hosted/controller/restapi/application/responses/test-config.json4
-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/filter/ControllerAuthorizationFilterTest.java13
-rw-r--r--controller-server/src/test/java/com/yahoo/vespa/hosted/controller/restapi/routing/RoutingApiTest.java5
-rw-r--r--controller-server/src/test/java/com/yahoo/vespa/hosted/controller/restapi/routing/responses/endpoint/endpoints.json10
-rw-r--r--controller-server/src/test/java/com/yahoo/vespa/hosted/controller/restapi/routing/responses/recursion/application.json4
-rw-r--r--controller-server/src/test/java/com/yahoo/vespa/hosted/controller/restapi/routing/responses/recursion/environment.json26
-rw-r--r--controller-server/src/test/java/com/yahoo/vespa/hosted/controller/restapi/routing/responses/recursion/tenant.json8
-rw-r--r--controller-server/src/test/java/com/yahoo/vespa/hosted/controller/restapi/routing/responses/rotation/deployment-status-in.json2
-rw-r--r--controller-server/src/test/java/com/yahoo/vespa/hosted/controller/restapi/routing/responses/rotation/deployment-status-initial.json2
-rw-r--r--controller-server/src/test/java/com/yahoo/vespa/hosted/controller/restapi/routing/responses/rotation/deployment-status-out.json2
-rw-r--r--controller-server/src/test/java/com/yahoo/vespa/hosted/controller/restapi/routing/responses/rotation/zone-status-in.json2
-rw-r--r--controller-server/src/test/java/com/yahoo/vespa/hosted/controller/restapi/routing/responses/rotation/zone-status-initial.json2
-rw-r--r--controller-server/src/test/java/com/yahoo/vespa/hosted/controller/restapi/routing/responses/rotation/zone-status-out.json2
-rw-r--r--controller-server/src/test/java/com/yahoo/vespa/hosted/controller/restapi/user/UserApiTest.java7
-rw-r--r--controller-server/src/test/java/com/yahoo/vespa/hosted/controller/restapi/user/responses/tenant-info-after-created.json8
-rw-r--r--controller-server/src/test/java/com/yahoo/vespa/hosted/controller/restapi/user/responses/tenant-with-keys.json1
-rw-r--r--controller-server/src/test/java/com/yahoo/vespa/hosted/controller/restapi/user/responses/tenant-with-secrets.json1
-rw-r--r--controller-server/src/test/java/com/yahoo/vespa/hosted/controller/routing/rotation/RotationRepositoryTest.java24
56 files changed, 1252 insertions, 579 deletions
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 1215ddbc2ad..63c0193ba7f 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
@@ -46,13 +46,13 @@ import org.junit.Test;
import java.time.Duration;
import java.time.Instant;
import java.util.Collection;
+import java.util.Comparator;
import java.util.List;
import java.util.Map;
import java.util.Optional;
import java.util.OptionalInt;
import java.util.Set;
import java.util.function.Function;
-import java.util.function.Supplier;
import java.util.stream.Collectors;
import java.util.stream.Stream;
@@ -237,14 +237,12 @@ public class ControllerTest {
ZoneId usWest = ZoneId.from("prod.us-west-1");
ZoneId usCentral = ZoneId.from("prod.us-central-1");
ApplicationPackage applicationPackage = new ApplicationPackageBuilder()
- .athenzIdentity(AthenzDomain.from("domain"), AthenzService.from("service"))
.instances("beta,default")
.endpoint("default", "foo")
.region(usWest.region())
.region(usCentral.region()) // Two deployments should result in each DNS alias being registered once
.build();
tester.controllerTester().zoneRegistry().setRoutingMethod(List.of(ZoneApiMock.from(usWest), ZoneApiMock.from(usCentral)),
- RoutingMethod.shared,
RoutingMethod.sharedLayer4);
betaContext.submit(applicationPackage).deploy();
@@ -253,12 +251,6 @@ public class ControllerTest {
assertFalse(betaDeployments.isEmpty());
Set<ContainerEndpoint> containerEndpoints = Set.of(new ContainerEndpoint("foo",
"global",
- List.of("beta--app1--tenant1.global.vespa.oath.cloud",
- "rotation-id-01"),
- OptionalInt.empty(),
- RoutingMethod.shared),
- new ContainerEndpoint("foo",
- "global",
List.of("beta.app1.tenant1.global.vespa.oath.cloud",
"rotation-id-01"),
OptionalInt.empty(),
@@ -277,12 +269,6 @@ public class ControllerTest {
assertFalse(defaultDeployments.isEmpty());
Set<ContainerEndpoint> containerEndpoints = Set.of(new ContainerEndpoint("foo",
"global",
- List.of("app1--tenant1.global.vespa.oath.cloud",
- "rotation-id-02"),
- OptionalInt.empty(),
- RoutingMethod.shared),
- new ContainerEndpoint("foo",
- "global",
List.of("app1.tenant1.global.vespa.oath.cloud",
"rotation-id-02"),
OptionalInt.empty(),
@@ -294,8 +280,8 @@ public class ControllerTest {
defaultContext.flushDnsUpdates();
}
- Map<String, String> rotationCnames = Map.of("beta--app1--tenant1.global.vespa.oath.cloud", "rotation-fqdn-01.",
- "app1--tenant1.global.vespa.oath.cloud", "rotation-fqdn-02.");
+ Map<String, String> rotationCnames = Map.of("beta.app1.tenant1.global.vespa.oath.cloud", "rotation-fqdn-01.",
+ "app1.tenant1.global.vespa.oath.cloud", "rotation-fqdn-02.");
rotationCnames.forEach((cname, data) -> {
var record = tester.controllerTester().findCname(cname);
assertTrue(record.isPresent());
@@ -303,10 +289,8 @@ public class ControllerTest {
assertEquals(data, record.get().data().asString());
});
- Map<ApplicationId, Set<String>> globalDnsNamesByInstance = Map.of(betaContext.instanceId(), Set.of("beta--app1--tenant1.global.vespa.oath.cloud",
- "beta.app1.tenant1.global.vespa.oath.cloud"),
- defaultContext.instanceId(), Set.of("app1--tenant1.global.vespa.oath.cloud",
- "app1.tenant1.global.vespa.oath.cloud"));
+ Map<ApplicationId, Set<String>> globalDnsNamesByInstance = Map.of(betaContext.instanceId(), Set.of("beta.app1.tenant1.global.vespa.oath.cloud"),
+ defaultContext.instanceId(), Set.of("app1.tenant1.global.vespa.oath.cloud"));
globalDnsNamesByInstance.forEach((instance, dnsNames) -> {
Set<String> actualDnsNames = tester.controller().routing().readDeclaredEndpointsOf(instance)
@@ -333,35 +317,22 @@ public class ControllerTest {
for (Deployment deployment : deployments) {
assertEquals("Rotation names are passed to config server in " + deployment.zone(),
Set.of("rotation-id-01",
- "app1--tenant1.global.vespa.oath.cloud",
- "app1.tenant1.global.vespa.yahooapis.com",
- "app1--tenant1.global.vespa.yahooapis.com"),
+ "app1.tenant1.global.vespa.oath.cloud"),
tester.configServer().containerEndpointNames(context.deploymentIdIn(deployment.zone())));
}
context.flushDnsUpdates();
- assertEquals(3, tester.controllerTester().nameService().records().size());
-
- Optional<Record> record = tester.controllerTester().findCname("app1--tenant1.global.vespa.yahooapis.com");
- assertTrue(record.isPresent());
- assertEquals("app1--tenant1.global.vespa.yahooapis.com", record.get().name().asString());
- assertEquals("rotation-fqdn-01.", record.get().data().asString());
+ assertEquals(1, tester.controllerTester().nameService().records().size());
- record = tester.controllerTester().findCname("app1--tenant1.global.vespa.oath.cloud");
+ Optional<Record> record = tester.controllerTester().findCname("app1.tenant1.global.vespa.oath.cloud");
assertTrue(record.isPresent());
- assertEquals("app1--tenant1.global.vespa.oath.cloud", record.get().name().asString());
- assertEquals("rotation-fqdn-01.", record.get().data().asString());
-
- record = tester.controllerTester().findCname("app1.tenant1.global.vespa.yahooapis.com");
- assertTrue(record.isPresent());
- assertEquals("app1.tenant1.global.vespa.yahooapis.com", record.get().name().asString());
+ assertEquals("app1.tenant1.global.vespa.oath.cloud", record.get().name().asString());
assertEquals("rotation-fqdn-01.", record.get().data().asString());
List<String> globalDnsNames = tester.controller().routing().readDeclaredEndpointsOf(context.instanceId())
.scope(Endpoint.Scope.global)
+ .sortedBy(Comparator.comparing(Endpoint::dnsName))
.mapToList(Endpoint::dnsName);
- assertEquals(List.of("app1--tenant1.global.vespa.oath.cloud",
- "app1.tenant1.global.vespa.yahooapis.com",
- "app1--tenant1.global.vespa.yahooapis.com"),
+ assertEquals(List.of("app1.tenant1.global.vespa.oath.cloud"),
globalDnsNames);
}
@@ -382,11 +353,11 @@ public class ControllerTest {
assertFalse(deployments.isEmpty());
var notWest = Set.of(
- "rotation-id-01", "foobar--app1--tenant1.global.vespa.oath.cloud",
- "rotation-id-02", "app1--tenant1.global.vespa.oath.cloud",
- "rotation-id-03", "all--app1--tenant1.global.vespa.oath.cloud"
+ "rotation-id-01", "foobar.app1.tenant1.global.vespa.oath.cloud",
+ "rotation-id-02", "app1.tenant1.global.vespa.oath.cloud",
+ "rotation-id-03", "all.app1.tenant1.global.vespa.oath.cloud"
);
- var west = Sets.union(notWest, Set.of("rotation-id-04", "west--app1--tenant1.global.vespa.oath.cloud"));
+ var west = Sets.union(notWest, Set.of("rotation-id-04", "west.app1.tenant1.global.vespa.oath.cloud"));
for (Deployment deployment : deployments) {
assertEquals("Rotation names are passed to config server in " + deployment.zone(),
@@ -397,24 +368,24 @@ public class ControllerTest {
assertEquals(4, tester.controllerTester().nameService().records().size());
- var record1 = tester.controllerTester().findCname("app1--tenant1.global.vespa.oath.cloud");
+ var record1 = tester.controllerTester().findCname("app1.tenant1.global.vespa.oath.cloud");
assertTrue(record1.isPresent());
- assertEquals("app1--tenant1.global.vespa.oath.cloud", record1.get().name().asString());
+ assertEquals("app1.tenant1.global.vespa.oath.cloud", record1.get().name().asString());
assertEquals("rotation-fqdn-02.", record1.get().data().asString());
- var record2 = tester.controllerTester().findCname("foobar--app1--tenant1.global.vespa.oath.cloud");
+ var record2 = tester.controllerTester().findCname("foobar.app1.tenant1.global.vespa.oath.cloud");
assertTrue(record2.isPresent());
- assertEquals("foobar--app1--tenant1.global.vespa.oath.cloud", record2.get().name().asString());
+ assertEquals("foobar.app1.tenant1.global.vespa.oath.cloud", record2.get().name().asString());
assertEquals("rotation-fqdn-01.", record2.get().data().asString());
- var record3 = tester.controllerTester().findCname("all--app1--tenant1.global.vespa.oath.cloud");
+ var record3 = tester.controllerTester().findCname("all.app1.tenant1.global.vespa.oath.cloud");
assertTrue(record3.isPresent());
- assertEquals("all--app1--tenant1.global.vespa.oath.cloud", record3.get().name().asString());
+ assertEquals("all.app1.tenant1.global.vespa.oath.cloud", record3.get().name().asString());
assertEquals("rotation-fqdn-03.", record3.get().data().asString());
- var record4 = tester.controllerTester().findCname("west--app1--tenant1.global.vespa.oath.cloud");
+ var record4 = tester.controllerTester().findCname("west.app1.tenant1.global.vespa.oath.cloud");
assertTrue(record4.isPresent());
- assertEquals("west--app1--tenant1.global.vespa.oath.cloud", record4.get().name().asString());
+ assertEquals("west.app1.tenant1.global.vespa.oath.cloud", record4.get().name().asString());
assertEquals("rotation-fqdn-04.", record4.get().data().asString());
}
@@ -437,7 +408,7 @@ public class ControllerTest {
for (var zone : List.of(west, central)) {
assertEquals(
"Zone " + zone + " is a member of global endpoint",
- Set.of("rotation-id-01", "app1--tenant1.global.vespa.oath.cloud"),
+ Set.of("rotation-id-01", "app1.tenant1.global.vespa.oath.cloud"),
tester.configServer().containerEndpointNames(context.deploymentIdIn(zone))
);
}
@@ -455,13 +426,13 @@ public class ControllerTest {
for (var zone : List.of(west, central)) {
assertEquals(
"Zone " + zone + " is a member of global endpoint",
- Set.of("rotation-id-01", "app1--tenant1.global.vespa.oath.cloud"),
+ Set.of("rotation-id-01", "app1.tenant1.global.vespa.oath.cloud"),
tester.configServer().containerEndpointNames(context.deploymentIdIn(zone))
);
}
assertEquals(
"Zone " + east + " is a member of global endpoint",
- Set.of("rotation-id-02", "east--app1--tenant1.global.vespa.oath.cloud"),
+ Set.of("rotation-id-02", "east.app1.tenant1.global.vespa.oath.cloud"),
tester.configServer().containerEndpointNames(context.deploymentIdIn(east))
);
@@ -478,9 +449,9 @@ public class ControllerTest {
assertEquals(
"Zone " + zone + " is a member of global endpoint",
zone.equals(east)
- ? Set.of("rotation-id-01", "app1--tenant1.global.vespa.oath.cloud",
- "rotation-id-02", "east--app1--tenant1.global.vespa.oath.cloud")
- : Set.of("rotation-id-01", "app1--tenant1.global.vespa.oath.cloud"),
+ ? Set.of("rotation-id-01", "app1.tenant1.global.vespa.oath.cloud",
+ "rotation-id-02", "east.app1.tenant1.global.vespa.oath.cloud")
+ : Set.of("rotation-id-01", "app1.tenant1.global.vespa.oath.cloud"),
tester.configServer().containerEndpointNames(context.deploymentIdIn(zone))
);
}
@@ -563,6 +534,7 @@ public class ControllerTest {
@Test
public void testDnsUpdatesWithChangeInRotationAssignment() {
// Application 1 is deployed and deleted
+ String dnsName1 = "app1.tenant1.global.vespa.oath.cloud";
{
var context = tester.newDeploymentContext("tenant1", "app1", "default");
ApplicationPackage applicationPackage = new ApplicationPackageBuilder()
@@ -573,11 +545,10 @@ public class ControllerTest {
context.submit(applicationPackage).deploy();
assertEquals(1, tester.controllerTester().nameService().records().size());
-
{
- Optional<Record> record = tester.controllerTester().findCname("app1--tenant1.global.vespa.oath.cloud");
+ Optional<Record> record = tester.controllerTester().findCname(dnsName1);
assertTrue(record.isPresent());
- assertEquals("app1--tenant1.global.vespa.oath.cloud", record.get().name().asString());
+ assertEquals(dnsName1, record.get().name().asString());
assertEquals("rotation-fqdn-01.", record.get().data().asString());
}
@@ -596,17 +567,13 @@ public class ControllerTest {
}
context.flushDnsUpdates();
- // Records are removed
- List<String> removed = List.of("app1--tenant1.global.vespa.yahooapis.com",
- "app1--tenant1.global.vespa.oath.cloud",
- "app1.tenant1.global.vespa.yahooapis.com");
- for (var name : removed) {
- Optional<Record> record = tester.controllerTester().findCname(name);
- assertTrue(name + " is removed", record.isEmpty());
- }
+ // Record is removed
+ Optional<Record> record = tester.controllerTester().findCname(dnsName1);
+ assertTrue(dnsName1 + " is removed", record.isEmpty());
}
// Application 2 is deployed and assigned same rotation as application 1 had before deletion
+ String dnsName2 = "app2.tenant2.global.vespa.oath.cloud";
{
var context = tester.newDeploymentContext("tenant2", "app2", "default");
ApplicationPackage applicationPackage = new ApplicationPackageBuilder()
@@ -617,9 +584,9 @@ public class ControllerTest {
context.submit(applicationPackage).deploy();
assertEquals(1, tester.controllerTester().nameService().records().size());
- var record = tester.controllerTester().findCname("app2--tenant2.global.vespa.oath.cloud");
+ var record = tester.controllerTester().findCname(dnsName2);
assertTrue(record.isPresent());
- assertEquals("app2--tenant2.global.vespa.oath.cloud", record.get().name().asString());
+ assertEquals(dnsName2, record.get().name().asString());
assertEquals("rotation-fqdn-01.", record.get().data().asString());
}
@@ -637,11 +604,11 @@ public class ControllerTest {
// DNS records are created for the newly assigned rotation
assertEquals(2, tester.controllerTester().nameService().records().size());
- var record1 = tester.controllerTester().findCname("app1--tenant1.global.vespa.oath.cloud");
+ var record1 = tester.controllerTester().findCname(dnsName1);
assertTrue(record1.isPresent());
assertEquals("rotation-fqdn-02.", record1.get().data().asString());
- var record2 = tester.controllerTester().findCname("app2--tenant2.global.vespa.oath.cloud");
+ var record2 = tester.controllerTester().findCname(dnsName2);
assertTrue(record2.isPresent());
assertEquals("rotation-fqdn-01.", record2.get().data().asString());
}
@@ -722,7 +689,7 @@ public class ControllerTest {
var context = tester.newDeploymentContext();
ZoneId zone = ZoneId.from("dev", "us-east-1");
tester.controllerTester().zoneRegistry()
- .setRoutingMethod(ZoneApiMock.from(zone), RoutingMethod.shared, RoutingMethod.sharedLayer4);
+ .setRoutingMethod(ZoneApiMock.from(zone), RoutingMethod.sharedLayer4);
// Deploy
context.runJob(zone, applicationPackage);
@@ -738,7 +705,7 @@ public class ControllerTest {
.stream()
.map(Endpoint::routingMethod)
.collect(Collectors.toSet());
- assertEquals(routingMethods, Set.of(RoutingMethod.shared, RoutingMethod.sharedLayer4));
+ assertEquals(routingMethods, Set.of(RoutingMethod.sharedLayer4));
// Deployment has stored application meta.
assertNotNull(tester.controllerTester().serviceRegistry().applicationStore()
@@ -778,12 +745,11 @@ public class ControllerTest {
public void testDeletingApplicationThatHasAlreadyBeenDeleted() {
var context = tester.newDeploymentContext();
ApplicationPackage applicationPackage = new ApplicationPackageBuilder()
- .region("us-east-3")
.region("us-west-1")
.build();
ZoneId zone = ZoneId.from(Environment.prod, RegionName.from("us-west-1"));
- context.runJob(zone, applicationPackage);
+ context.submit(applicationPackage).runJob(zone, applicationPackage);
tester.controller().applications().deactivate(context.instanceId(), zone);
tester.controller().applications().deactivate(context.instanceId(), zone);
}
@@ -914,12 +880,10 @@ public class ControllerTest {
.region(zone2.region())
.build();
- // Zone 1 supports shared and sharedLayer4
- tester.controllerTester().zoneRegistry().setRoutingMethod(ZoneApiMock.from(zone1), RoutingMethod.shared,
- RoutingMethod.sharedLayer4);
+ // Zone 1 supports sharedLayer4
+ tester.controllerTester().zoneRegistry().setRoutingMethod(ZoneApiMock.from(zone1), RoutingMethod.sharedLayer4);
// Zone 2 supports shared and exclusive
- tester.controllerTester().zoneRegistry().setRoutingMethod(ZoneApiMock.from(zone2), RoutingMethod.shared,
- RoutingMethod.exclusive);
+ tester.controllerTester().zoneRegistry().setRoutingMethod(ZoneApiMock.from(zone2), RoutingMethod.exclusive);
context.submit(applicationPackage).deploy();
var expectedRecords = List.of(
@@ -935,20 +899,10 @@ public class ControllerTest {
new LatencyAliasTarget(HostName.from("application.tenant.us-east-3-w.vespa.oath.cloud"),
"dns-zone-1", ZoneId.from("prod.us-east-3")).pack()),
- // The 'default' global endpoint, pointing to both zones with shared routing, via rotation
- new Record(Record.Type.CNAME,
- RecordName.from("application--tenant.global.vespa.oath.cloud"),
- RecordData.from("rotation-fqdn-01.")),
-
// The zone-scoped endpoint pointing to zone 2 with exclusive routing
new Record(Record.Type.CNAME,
RecordName.from("application.tenant.us-east-3.vespa.oath.cloud"),
- RecordData.from("lb-0--tenant:application:default--prod.us-east-3.")),
-
- // The 'east' global endpoint, pointing to zone 2 with shared routing, via rotation
- new Record(Record.Type.CNAME,
- RecordName.from("east--application--tenant.global.vespa.oath.cloud"),
- RecordData.from("rotation-fqdn-02.")));
+ RecordData.from("lb-0--tenant:application:default--prod.us-east-3.")));
assertEquals(expectedRecords, List.copyOf(tester.controllerTester().nameService().records()));
}
@@ -988,53 +942,6 @@ public class ControllerTest {
}
@Test
- public void testDeploymentWithSharedAndDirectRouting() {
- var context = tester.newDeploymentContext();
- var zone1 = ZoneId.from("prod", "us-west-1");
- var zone2 = ZoneId.from("prod", "us-east-3");
- var applicationPackageBuilder = new ApplicationPackageBuilder()
- .region(zone1.region())
- .region(zone2.region());
- tester.controllerTester().zoneRegistry()
- .setRoutingMethod(ZoneApiMock.from(zone1), RoutingMethod.shared, RoutingMethod.sharedLayer4)
- .setRoutingMethod(ZoneApiMock.from(zone2), RoutingMethod.shared, RoutingMethod.sharedLayer4);
- Supplier<Set<RoutingMethod>> routingMethods = () -> tester.controller().routing().readEndpointsOf(context.deploymentIdIn(zone1))
- .asList()
- .stream()
- .map(Endpoint::routingMethod)
- .collect(Collectors.toSet());
-
- // Without satisfying requirements
- context.submit(applicationPackageBuilder.build()).deploy();
- assertEquals(Set.of(RoutingMethod.shared), routingMethods.get());
-
- // Package satisfying all requirements is submitted, but not deployed yet
- applicationPackageBuilder = applicationPackageBuilder.athenzIdentity(AthenzDomain.from("domain"), AthenzService.from("service"));
- var context2 = context.submit(applicationPackageBuilder.build());
- assertEquals("Direct routing endpoint is available after submission and before deploy",
- Set.of(RoutingMethod.shared, RoutingMethod.sharedLayer4), routingMethods.get());
- context2.deploy();
-
- // Global endpoint is added and includes directly routed endpoint name
- applicationPackageBuilder = applicationPackageBuilder.endpoint("default", "default");
- context2.submit(applicationPackageBuilder.build()).deploy();
- for (var zone : List.of(zone1, zone2)) {
- assertEquals(Set.of("rotation-id-01",
- "application.tenant.global.vespa.oath.cloud",
- "application--tenant.global.vespa.oath.cloud"),
- tester.configServer().containerEndpointNames(context.deploymentIdIn(zone)));
- }
- List<String> zoneDnsNames = tester.controller().routing().readEndpointsOf(context.deploymentIdIn(zone1))
- .scope(Endpoint.Scope.zone)
- .mapToList(Endpoint::dnsName);
- assertEquals(List.of("application--tenant.us-west-1.vespa.oath.cloud",
- "application.tenant.us-west-1.prod.vespa.yahooapis.com",
- "application--tenant.us-west-1.prod.vespa.yahooapis.com",
- "application.tenant.us-west-1.vespa.oath.cloud"),
- zoneDnsNames);
- }
-
- @Test
public void testChangeEndpointCluster() {
var context = tester.newDeploymentContext();
var west = ZoneId.from("prod", "us-west-1");
diff --git a/controller-server/src/test/java/com/yahoo/vespa/hosted/controller/application/EndpointTest.java b/controller-server/src/test/java/com/yahoo/vespa/hosted/controller/application/EndpointTest.java
index e50c32d0e5d..35cca0e1f1f 100644
--- a/controller-server/src/test/java/com/yahoo/vespa/hosted/controller/application/EndpointTest.java
+++ b/controller-server/src/test/java/com/yahoo/vespa/hosted/controller/application/EndpointTest.java
@@ -33,26 +33,6 @@ public class EndpointTest {
EndpointId endpointId = EndpointId.defaultId();
Map<String, Endpoint> tests = Map.of(
- // Legacy endpoint
- "http://a1.t1.global.vespa.yahooapis.com:4080/",
- Endpoint.of(instance1).target(endpointId, cluster, List.of(deployment1)).on(Port.plain(4080)).legacy().in(SystemName.main),
-
- // Legacy endpoint with TLS
- "https://a1--t1.global.vespa.yahooapis.com:4443/",
- Endpoint.of(instance1).target(endpointId, cluster, List.of(deployment1)).on(Port.tls(4443)).legacy().in(SystemName.main),
-
- // Main endpoint
- "https://a1--t1.global.vespa.oath.cloud:4443/",
- Endpoint.of(instance1).target(endpointId, cluster, List.of(deployment1)).on(Port.tls(4443)).in(SystemName.main),
-
- // Main endpoint in CD
- "https://cd--a1--t1.global.vespa.oath.cloud:4443/",
- Endpoint.of(instance1).target(endpointId, cluster, List.of(deployment1)).on(Port.tls(4443)).in(SystemName.cd),
-
- // Main endpoint in CD
- "https://cd--i2--a2--t2.global.vespa.oath.cloud:4443/",
- Endpoint.of(instance2).target(endpointId, cluster, List.of(deployment2)).on(Port.tls(4443)).in(SystemName.cd),
-
// Main endpoint with direct routing and default TLS port
"https://a1.t1.global.vespa.oath.cloud/",
Endpoint.of(instance1).target(endpointId, cluster, List.of(deployment1)).on(Port.tls()).routingMethod(RoutingMethod.exclusive).in(SystemName.main),
@@ -99,26 +79,6 @@ public class EndpointTest {
EndpointId endpointId = EndpointId.defaultId();
Map<String, Endpoint> tests = Map.of(
- // Legacy endpoint
- "http://a1.t1.global.vespa.yahooapis.com:4080/",
- Endpoint.of(instance1).target(endpointId, cluster, List.of(deployment1)).on(Port.plain(4080)).legacy().in(SystemName.main),
-
- // Legacy endpoint with TLS
- "https://a1--t1.global.vespa.yahooapis.com:4443/",
- Endpoint.of(instance1).target(endpointId, cluster, List.of(deployment1)).on(Port.tls(4443)).legacy().in(SystemName.main),
-
- // Main endpoint
- "https://a1--t1.global.vespa.oath.cloud:4443/",
- Endpoint.of(instance1).target(endpointId, cluster, List.of(deployment1)).on(Port.tls(4443)).in(SystemName.main),
-
- // Main endpoint in CD
- "https://cd--i2--a2--t2.global.vespa.oath.cloud:4443/",
- Endpoint.of(instance2).target(endpointId, cluster, List.of(deployment2)).on(Port.tls(4443)).in(SystemName.cd),
-
- // Main endpoint in CD
- "https://cd--a1--t1.global.vespa.oath.cloud:4443/",
- Endpoint.of(instance1).target(endpointId, cluster, List.of(deployment1)).on(Port.tls(4443)).in(SystemName.cd),
-
// Main endpoint with direct routing and default TLS port
"https://a1.t1.global.vespa.oath.cloud/",
Endpoint.of(instance1).target(endpointId, cluster, List.of(deployment1)).on(Port.tls()).routingMethod(RoutingMethod.exclusive).in(SystemName.main),
@@ -161,33 +121,25 @@ public class EndpointTest {
var testZone = new DeploymentId(instance1, ZoneId.from("test", "us-north-2"));
Map<String, Endpoint> tests = Map.of(
- // Legacy endpoint (always contains environment)
- "http://a1.t1.us-north-1.prod.vespa.yahooapis.com:4080/",
- Endpoint.of(instance1).target(cluster, prodZone).on(Port.plain(4080)).legacy().in(SystemName.main),
-
- // Secure legacy endpoint
- "https://a1--t1.us-north-1.prod.vespa.yahooapis.com:4443/",
- Endpoint.of(instance1).target(cluster, prodZone).on(Port.tls(4443)).legacy().in(SystemName.main),
-
// Prod endpoint in main
- "https://a1--t1.us-north-1.vespa.oath.cloud:4443/",
- Endpoint.of(instance1).target(cluster, prodZone).on(Port.tls(4443)).in(SystemName.main),
+ "https://a1.t1.us-north-1.vespa.oath.cloud/",
+ Endpoint.of(instance1).target(cluster, prodZone).on(Port.tls()).in(SystemName.main),
// Prod endpoint in CD
- "https://cd--a1--t1.us-north-1.vespa.oath.cloud:4443/",
- Endpoint.of(instance1).target(cluster, prodZone).on(Port.tls(4443)).in(SystemName.cd),
+ "https://cd.a1.t1.us-north-1.vespa.oath.cloud/",
+ Endpoint.of(instance1).target(cluster, prodZone).on(Port.tls()).in(SystemName.cd),
// Test endpoint in main
- "https://a1--t1.us-north-2.test.vespa.oath.cloud:4443/",
- Endpoint.of(instance1).target(cluster, testZone).on(Port.tls(4443)).in(SystemName.main),
+ "https://a1.t1.us-north-2.test.vespa.oath.cloud/",
+ Endpoint.of(instance1).target(cluster, testZone).on(Port.tls()).in(SystemName.main),
// Non-default cluster in main
- "https://c1--a1--t1.us-north-1.vespa.oath.cloud/",
+ "https://c1.a1.t1.us-north-1.vespa.oath.cloud/",
Endpoint.of(instance1).target(ClusterSpec.Id.from("c1"), prodZone).on(Port.tls()).in(SystemName.main),
// Non-default instance in main
- "https://i2--a2--t2.us-north-1.vespa.oath.cloud:4443/",
- Endpoint.of(instance2).target(cluster, prodZone2).on(Port.tls(4443)).in(SystemName.main),
+ "https://i2.a2.t2.us-north-1.vespa.oath.cloud/",
+ Endpoint.of(instance2).target(cluster, prodZone2).on(Port.tls()).in(SystemName.main),
// Non-default cluster in public
"https://c1.a1.t1.us-north-1.z.vespa-app.cloud/",
@@ -195,11 +147,7 @@ public class EndpointTest {
// Non-default cluster and instance in public
"https://c2.i2.a2.t2.us-north-1.z.vespa-app.cloud/",
- Endpoint.of(instance2).target(ClusterSpec.Id.from("c2"), prodZone2).on(Port.tls()).routingMethod(RoutingMethod.exclusive).in(SystemName.Public),
-
- // Endpoint in main using shared layer 4
- "https://a1.t1.us-north-1.vespa.oath.cloud/",
- Endpoint.of(instance1).target(cluster, prodZone).on(Port.tls()).routingMethod(RoutingMethod.sharedLayer4).in(SystemName.main)
+ Endpoint.of(instance2).target(ClusterSpec.Id.from("c2"), prodZone2).on(Port.tls()).routingMethod(RoutingMethod.exclusive).in(SystemName.Public)
);
tests.forEach((expected, endpoint) -> assertEquals(expected, endpoint.url().toString()));
@@ -365,11 +313,11 @@ public class EndpointTest {
var tests1 = Map.of(
// With default cluster
"a1.t1.us-north-1.prod",
- Endpoint.of(instance1).target(EndpointId.defaultId(), ClusterSpec.Id.from("default"), List.of(zone)).on(Port.tls(4443)).in(SystemName.main),
+ Endpoint.of(instance1).target(EndpointId.defaultId(), ClusterSpec.Id.from("default"), List.of(zone)).on(Port.tls()).in(SystemName.main),
// With non-default cluster
"c1.a1.t1.us-north-1.prod",
- Endpoint.of(instance1).target(EndpointId.of("ignored1"), ClusterSpec.Id.from("c1"), List.of(zone)).on(Port.tls(4443)).in(SystemName.main),
+ Endpoint.of(instance1).target(EndpointId.of("ignored1"), ClusterSpec.Id.from("c1"), List.of(zone)).on(Port.tls()).in(SystemName.main),
// With application endpoint
"c2.a1.t1.us-north-1.prod",
@@ -381,11 +329,11 @@ public class EndpointTest {
var tests2 = Map.of(
// With non-default instance and default cluster
"i2.a2.t2.us-north-1.prod",
- Endpoint.of(instance2).target(EndpointId.defaultId(), ClusterSpec.Id.from("default"), List.of(zone2)).on(Port.tls(4443)).in(SystemName.main),
+ Endpoint.of(instance2).target(EndpointId.defaultId(), ClusterSpec.Id.from("default"), List.of(zone2)).on(Port.tls()).in(SystemName.main),
// With non-default instance and cluster
"c2.i2.a2.t2.us-north-1.prod",
- Endpoint.of(instance2).target(EndpointId.of("ignored2"), ClusterSpec.Id.from("c2"), List.of(zone2)).on(Port.tls(4443)).in(SystemName.main)
+ Endpoint.of(instance2).target(EndpointId.of("ignored2"), ClusterSpec.Id.from("c2"), List.of(zone2)).on(Port.tls()).in(SystemName.main)
);
tests1.forEach((expected, endpoint) -> assertEquals(expected, endpoint.upstreamName(zone)));
tests2.forEach((expected, endpoint) -> assertEquals(expected, endpoint.upstreamName(zone2)));
diff --git a/controller-server/src/test/java/com/yahoo/vespa/hosted/controller/application/pkg/ApplicationPackageTest.java b/controller-server/src/test/java/com/yahoo/vespa/hosted/controller/application/pkg/ApplicationPackageTest.java
index 2ee03457046..cf0b46dfba2 100644
--- a/controller-server/src/test/java/com/yahoo/vespa/hosted/controller/application/pkg/ApplicationPackageTest.java
+++ b/controller-server/src/test/java/com/yahoo/vespa/hosted/controller/application/pkg/ApplicationPackageTest.java
@@ -7,6 +7,8 @@ import org.junit.Assert;
import org.junit.Test;
import java.io.ByteArrayInputStream;
+import java.nio.file.Files;
+import java.nio.file.Path;
import java.time.Instant;
import java.util.List;
import java.util.Map;
@@ -14,6 +16,7 @@ import java.util.stream.Collectors;
import static java.nio.charset.StandardCharsets.UTF_8;
import static org.junit.Assert.assertEquals;
+import static org.junit.Assert.assertNotEquals;
import static org.junit.Assert.assertTrue;
/**
@@ -108,6 +111,21 @@ public class ApplicationPackageTest {
}
}
+ @Test
+ public void testBundleHashesAreSameWithDifferentDeploymentXml() throws Exception {
+ var originalPackage = getApplicationZip("original.zip");
+ var changedDeploymentXml = getApplicationZip("changed-deployment-xml.zip");
+ var changedServices = getApplicationZip("changed-services-xml.zip");
+
+ // services.xml is changed -> different bundle hash
+ assertNotEquals(originalPackage.bundleHash(), changedServices.bundleHash());
+ assertNotEquals(originalPackage.hash(), changedServices.hash());
+
+ // deployment.xml is changed -> same bundle hash
+ assertEquals(originalPackage.bundleHash(), changedDeploymentXml.bundleHash());
+ assertNotEquals(originalPackage.hash(), changedDeploymentXml.hash());
+ }
+
private static Map<String, String> unzip(byte[] zip) {
return new ZipStreamReader(new ByteArrayInputStream(zip), __ -> true, 1 << 10, true)
.entries().stream()
@@ -115,4 +133,8 @@ public class ApplicationPackageTest {
entry -> new String(entry.contentOrThrow(), UTF_8)));
}
+ private ApplicationPackage getApplicationZip(String path) throws Exception {
+ return new ApplicationPackage(Files.readAllBytes(Path.of("src/test/resources/application-packages/" + path)), true);
+ }
+
}
diff --git a/controller-server/src/test/java/com/yahoo/vespa/hosted/controller/archive/CuratorArchiveBucketDbTest.java b/controller-server/src/test/java/com/yahoo/vespa/hosted/controller/archive/CuratorArchiveBucketDbTest.java
index d6ec01a2d57..1a052b6a578 100644
--- a/controller-server/src/test/java/com/yahoo/vespa/hosted/controller/archive/CuratorArchiveBucketDbTest.java
+++ b/controller-server/src/test/java/com/yahoo/vespa/hosted/controller/archive/CuratorArchiveBucketDbTest.java
@@ -16,7 +16,7 @@ import java.util.stream.Collectors;
import java.util.stream.IntStream;
import java.util.stream.Stream;
-import static org.junit.Assert.*;
+import static org.junit.Assert.assertEquals;
public class CuratorArchiveBucketDbTest {
@@ -29,19 +29,22 @@ public class CuratorArchiveBucketDbTest {
Set.of(new ArchiveBucket("existingBucket", "keyArn").withTenant(TenantName.defaultName())));
// Finds existing bucket in db
- assertEquals(Optional.of(URI.create("s3://existingBucket/default/")), bucketDb.archiveUriFor(ZoneId.defaultId(), TenantName.defaultName()));
+ assertEquals(Optional.of(URI.create("s3://existingBucket/default/")), bucketDb.archiveUriFor(ZoneId.defaultId(), TenantName.defaultName(), true));
// Assigns to existing bucket while there is space
IntStream.range(0, 29).forEach(i ->
assertEquals(
Optional.of(URI.create("s3://existingBucket/tenant" + i + "/")), bucketDb
- .archiveUriFor(ZoneId.defaultId(), TenantName.from("tenant" + i))));
+ .archiveUriFor(ZoneId.defaultId(), TenantName.from("tenant" + i), true)));
// Creates new bucket when existing buckets are full
- assertEquals(Optional.of(URI.create("s3://bucketName/lastDrop/")), bucketDb.archiveUriFor(ZoneId.defaultId(), TenantName.from("lastDrop")));
+ assertEquals(Optional.of(URI.create("s3://bucketName/lastDrop/")), bucketDb.archiveUriFor(ZoneId.defaultId(), TenantName.from("lastDrop"), true));
// Creates new bucket when there are no existing buckets in zone
- assertEquals(Optional.of(URI.create("s3://bucketName/firstInZone/")), bucketDb.archiveUriFor(ZoneId.from("prod.us-east-3"), TenantName.from("firstInZone")));
+ assertEquals(Optional.of(URI.create("s3://bucketName/firstInZone/")), bucketDb.archiveUriFor(ZoneId.from("prod.us-east-3"), TenantName.from("firstInZone"), true));
+
+ // Does not create bucket if not required
+ assertEquals(Optional.empty(), bucketDb.archiveUriFor(ZoneId.from("prod.us-east-3"), TenantName.from("newTenant"), false));
// Lists all buckets by zone
Set<TenantName> existingBucketTenants = Streams.concat(Stream.of(TenantName.defaultName()), IntStream.range(0, 29).mapToObj(i -> TenantName.from("tenant" + i))).collect(Collectors.toUnmodifiableSet());
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 91a12d3b465..bc5a70b1fa0 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
@@ -57,9 +57,10 @@ public class ApplicationPackageBuilder {
private OptionalInt majorVersion = OptionalInt.empty();
private String instances = "default";
private String upgradePolicy = null;
+ private String upgradeRevision = "latest";
private String upgradeRollout = null;
private String globalServiceId = null;
- private String athenzIdentityAttributes = null;
+ private String athenzIdentityAttributes = "athenz-domain='domain' athenz-service='service'";
private String searchDefinition = "search test { }";
private boolean explicitSystemTest = false;
private boolean explicitStagingTest = false;
@@ -80,6 +81,11 @@ public class ApplicationPackageBuilder {
return this;
}
+ public ApplicationPackageBuilder upgradeRevision(String upgradeRevision) {
+ this.upgradeRevision = upgradeRevision;
+ return this;
+ }
+
public ApplicationPackageBuilder upgradeRollout(String upgradeRollout) {
this.upgradeRollout = upgradeRollout;
return this;
@@ -195,7 +201,12 @@ public class ApplicationPackageBuilder {
public ApplicationPackageBuilder athenzIdentity(AthenzDomain domain, AthenzService service) {
this.athenzIdentityAttributes = Text.format("athenz-domain='%s' athenz-service='%s'", domain.value(),
- service.value());
+ service.value());
+ return this;
+ }
+
+ public ApplicationPackageBuilder withoutAthenzIdentity() {
+ this.athenzIdentityAttributes = null;
return this;
}
@@ -248,9 +259,10 @@ public class ApplicationPackageBuilder {
}
xml.append(">\n");
xml.append(" <instance id='").append(instances).append("'>\n");
- if (upgradePolicy != null || upgradeRollout != null) {
+ if (upgradePolicy != null || upgradeRevision != null || upgradeRollout != null) {
xml.append(" <upgrade ");
if (upgradePolicy != null) xml.append("policy='").append(upgradePolicy).append("' ");
+ if (upgradeRevision != null) xml.append("revision='").append(upgradeRevision).append("' ");
if (upgradeRollout != null) xml.append("rollout='").append(upgradeRollout).append("' ");
xml.append("/>\n");
}
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 699721b128c..9c5f7e3376a 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
@@ -164,14 +164,13 @@ public class DeploymentContext {
}
- /** Completely deploy the latest change */
+ /** Completely deploy the current change */
public DeploymentContext deploy() {
Application application = application();
assertTrue("Application package submitted", application.latestVersion().isPresent());
assertFalse("Submission is not already deployed", application.instances().values().stream()
.anyMatch(instance -> instance.deployments().values().stream()
.anyMatch(deployment -> deployment.applicationVersion().equals(lastSubmission))));
- assertEquals(application.latestVersion(), instance().change().application());
completeRollout(application.deploymentSpec().instances().size() > 1);
for (var instance : application().instances().values()) {
assertFalse(instance.change().hasTargets());
@@ -334,20 +333,20 @@ public class DeploymentContext {
/** Runs and returns all remaining jobs for the application, at most once, and asserts the current change is rolled out. */
public DeploymentContext completeRollout(boolean multiInstance) {
triggerJobs();
- Map<ApplicationId, Set<JobType>> jobsByInstance = new HashMap<>();
+ Map<ApplicationId, Map<JobType, Versions>> jobsByInstance = new HashMap<>();
List<Run> activeRuns;
while ( ! (activeRuns = this.jobs.active(applicationId)).isEmpty())
for (Run run : activeRuns) {
- Set<JobType> jobs = jobsByInstance.computeIfAbsent(run.id().application(), k -> new HashSet<>());
- if (jobs.add(run.id().type())) {
- runJob(run.id().type(), run.id().application());
- if (multiInstance) {
- tester.outstandingChangeDeployer().run();
- }
- triggerJobs();
- } else {
- throw new AssertionError("Job '" + run.id() + "' was run twice");
+ Map<JobType, Versions> jobs = jobsByInstance.computeIfAbsent(run.id().application(), k -> new HashMap<>());
+ Versions previous = jobs.put(run.id().type(), run.versions());
+ if (run.versions().equals(previous)) {
+ throw new AssertionError("Job '" + run.id() + "' was run twice on same versions");
}
+ runJob(run.id().type(), run.id().application());
+ if (multiInstance) {
+ tester.outstandingChangeDeployer().run();
+ }
+ triggerJobs();
}
assertFalse("Change should have no targets, but was " + instance().change(), instance().change().hasTargets());
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 102dfde16ec..67fa2f87794 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
@@ -107,6 +107,40 @@ public class DeploymentTriggerTest {
}
@Test
+ public void separateRevisionMakesApplicationChangeWaitForPreviousToComplete() {
+ DeploymentContext app = tester.newDeploymentContext();
+ ApplicationPackage applicationPackage = new ApplicationPackageBuilder()
+ .upgradeRevision(null) // separate by default, but we override this in test builder
+ .region("us-east-3")
+ .test("us-east-3")
+ .build();
+
+ app.submit(applicationPackage).runJob(systemTest).runJob(stagingTest).runJob(productionUsEast3);
+ Optional<ApplicationVersion> v0 = app.lastSubmission();
+
+ app.submit(applicationPackage);
+ Optional<ApplicationVersion> v1 = app.lastSubmission();
+ assertEquals(v0, app.instance().change().application());
+
+ // Eager tests still run before new revision rolls out.
+ app.runJob(systemTest).runJob(stagingTest);
+
+ // v0 rolls out completely.
+ app.runJob(testUsEast3);
+ assertEquals(Optional.empty(), app.instance().change().application());
+
+ // v1 starts rolling when v0 is done.
+ tester.outstandingChangeDeployer().run();
+ assertEquals(v1, app.instance().change().application());
+
+ // v1 fails, so v2 starts immediately.
+ app.runJob(productionUsEast3).failDeployment(testUsEast3);
+ app.submit(applicationPackage);
+ Optional<ApplicationVersion> v2 = app.lastSubmission();
+ assertEquals(v2, app.instance().change().application());
+ }
+
+ @Test
public void leadingUpgradeAllowsApplicationChangeWhileUpgrading() {
var applicationPackage = new ApplicationPackageBuilder().region("us-east-3")
.upgradeRollout("leading")
@@ -155,9 +189,10 @@ public class DeploymentTriggerTest {
tester.controllerTester().upgradeSystem(new Version("8.9"));
tester.upgrader().maintain();
app.runJob(systemTest).runJob(stagingTest);
+ tester.clock().advance(Duration.ofMinutes(1));
tester.triggerJobs();
- // Jobs are not aborted when the new submission remains outstanding.
+ // Upgrade is allowed to proceed ahead of revision change, and is not aborted.
app.submit();
app.runJob(systemTest).runJob(stagingTest);
tester.triggerJobs();
@@ -347,17 +382,15 @@ public class DeploymentTriggerTest {
// Application on (6.1, 1.0.1)
Version v1 = Version.fromString("6.1");
- // Application is mid-upgrade when block window begins, and has an outstanding change.
+ // Application is mid-upgrade when block window begins, and gets an outstanding change.
Version v2 = Version.fromString("6.2");
tester.controllerTester().upgradeSystem(v2);
tester.upgrader().maintain();
- app.submit(applicationPackage);
-
app.runJob(stagingTest).runJob(systemTest);
// Entering block window will keep the outstanding change in place.
tester.clock().advance(Duration.ofHours(1));
- tester.outstandingChangeDeployer().run();
+ app.submit(applicationPackage);
app.runJob(productionUsWest1);
assertEquals(1, app.instanceJobs().get(productionUsWest1).lastSuccess().get().versions().targetApplication().buildNumber().getAsLong());
assertEquals(2, app.deploymentStatus().outstandingChange(app.instance().name()).application().get().buildNumber().getAsLong());
@@ -465,18 +498,45 @@ public class DeploymentTriggerTest {
}
@Test
- public void settingANoOpChangeIsANoOp() {
+ public void downgradingApplicationVersionWorks() {
var app = tester.newDeploymentContext().submit().deploy();
ApplicationVersion appVersion0 = app.lastSubmission().get();
+ assertEquals(Optional.of(appVersion0), app.instance().latestDeployed());
+
app.submit().deploy();
ApplicationVersion appVersion1 = app.lastSubmission().get();
+ assertEquals(Optional.of(appVersion1), app.instance().latestDeployed());
- // Triggering a roll-out of an already deployed application is a no-op.
- assertEquals(Change.empty(), app.instance().change());
+ // Downgrading application version.
tester.deploymentTrigger().forceChange(app.instanceId(), Change.of(appVersion0));
+ assertEquals(Change.of(appVersion0), app.instance().change());
+ app.runJob(stagingTest)
+ .runJob(productionUsCentral1)
+ .runJob(productionUsEast3)
+ .runJob(productionUsWest1);
+ assertEquals(Change.empty(), app.instance().change());
+ assertEquals(appVersion0, app.instance().deployments().get(productionUsEast3.zone(tester.controller().system())).applicationVersion());
+ assertEquals(Optional.of(appVersion0), app.instance().latestDeployed());
+ }
+
+ @Test
+ public void settingANoOpChangeIsANoOp() {
+ var app = tester.newDeploymentContext().submit();
+ assertEquals(Optional.empty(), app.instance().latestDeployed());
+
+ app.deploy();
+ ApplicationVersion appVersion0 = app.lastSubmission().get();
+ assertEquals(Optional.of(appVersion0), app.instance().latestDeployed());
+
+ app.submit().deploy();
+ ApplicationVersion appVersion1 = app.lastSubmission().get();
+ assertEquals(Optional.of(appVersion1), app.instance().latestDeployed());
+
+ // Triggering a roll-out of an already deployed application is a no-op.
assertEquals(Change.empty(), app.instance().change());
tester.deploymentTrigger().forceChange(app.instanceId(), Change.of(appVersion1));
assertEquals(Change.empty(), app.instance().change());
+ assertEquals(Optional.of(appVersion1), app.instance().latestDeployed());
}
@Test
@@ -538,19 +598,23 @@ public class DeploymentTriggerTest {
// Change has a higher application version than what is deployed -- deployment should trigger.
app1.timeOutUpgrade(productionUsCentral1);
- assertEquals(version2, app1.instance().deployments().get(productionUsCentral1.zone(main)).version());
+ assertEquals(version2, app1.deployment(productionUsCentral1.zone(main)).version());
assertEquals(revision2, app1.deployment(productionUsCentral1.zone(main)).applicationVersion());
// Change is again strictly dominated, and us-central-1 is skipped, even though it is still failing.
- tester.clock().advance(Duration.ofHours(2).plus(Duration.ofSeconds(1))); // Enough time for retry
+ tester.clock().advance(Duration.ofHours(3)); // Enough time for retry
tester.triggerJobs();
// Failing job is not retried as change has been deployed
app1.assertNotRunning(productionUsCentral1);
// Last job has a different deployment target, so tests need to run again.
- app1.runJob(systemTest).runJob(stagingTest).runJob(productionEuWest1);
- assertFalse(app1.instance().change().hasTargets());
- assertFalse(app1.instanceJobs().get(productionUsCentral1).isSuccess());
+ app1.runJob(systemTest)
+ .runJob(stagingTest) // Eager test of outstanding change, assuming upgrade in west succeeds.
+ .runJob(productionEuWest1) // Upgrade completes, and revision is the only change.
+ .runJob(productionUsCentral1) // With only revision change, central should run to cover a previous failure.
+ .runJob(productionEuWest1); // Finally, west changes revision.
+ assertEquals(Change.empty(), app1.instance().change());
+ assertEquals(Optional.of(RunStatus.success), app1.instanceJobs().get(productionUsCentral1).lastStatus());
}
@Test
@@ -792,6 +856,115 @@ public class DeploymentTriggerTest {
}
@Test
+ public void testMultipleInstancesWithDifferentChanges() {
+ DeploymentContext i1 = tester.newDeploymentContext("t", "a", "i1");
+ DeploymentContext i2 = tester.newDeploymentContext("t", "a", "i2");
+ DeploymentContext i3 = tester.newDeploymentContext("t", "a", "i3");
+ DeploymentContext i4 = tester.newDeploymentContext("t", "a", "i4");
+ ApplicationPackage applicationPackage = ApplicationPackageBuilder
+ .fromDeploymentXml("<deployment version='1'>\n" +
+ " <upgrade revision='separate' />\n" +
+ " <parallel>\n" +
+ " <instance id='i1'>\n" +
+ " <prod>\n" +
+ " <region>us-east-3</region>\n" +
+ " <delay hours='6' />\n" +
+ " </prod>\n" +
+ " </instance>\n" +
+ " <instance id='i2'>\n" +
+ " <prod>\n" +
+ " <region>us-east-3</region>\n" +
+ " </prod>\n" +
+ " </instance>\n" +
+ " </parallel>\n" +
+ " <instance id='i3'>\n" +
+ " <prod>\n" +
+ " <region>us-east-3</region>\n" +
+ " <delay hours='18' />\n" +
+ " <test>us-east-3</test>\n" +
+ " </prod>\n" +
+ " </instance>\n" +
+ " <instance id='i4'>\n" +
+ " <test />\n" +
+ " <staging />\n" +
+ " <prod>\n" +
+ " <region>us-east-3</region>\n" +
+ " </prod>\n" +
+ " </instance>\n" +
+ "</deployment>\n");
+
+ // Package is submitted, and change propagated to the two first instances.
+ i1.submit(applicationPackage);
+ Optional<ApplicationVersion> v0 = i1.lastSubmission();
+ tester.outstandingChangeDeployer().run();
+ assertEquals(v0, i1.instance().change().application());
+ assertEquals(v0, i2.instance().change().application());
+ assertEquals(Optional.empty(), i3.instance().change().application());
+ assertEquals(Optional.empty(), i4.instance().change().application());
+
+ // Tests run in i4, as they're declared there, and i1 and i2 get to work
+ i4.runJob(systemTest).runJob(stagingTest);
+ i1.runJob(productionUsEast3);
+ i2.runJob(productionUsEast3);
+
+ // Since the post-deployment delay of i1 is incomplete, i3 doesn't yet get the change.
+ tester.outstandingChangeDeployer().run();
+ assertEquals(v0, i1.instance().latestDeployed());
+ assertEquals(v0, i2.instance().latestDeployed());
+ assertEquals(Optional.empty(), i1.instance().change().application());
+ assertEquals(Optional.empty(), i2.instance().change().application());
+ assertEquals(Optional.empty(), i3.instance().change().application());
+ assertEquals(Optional.empty(), i4.instance().change().application());
+
+ // When the delay is done, i3 gets the change.
+ tester.clock().advance(Duration.ofHours(6));
+ tester.outstandingChangeDeployer().run();
+ assertEquals(Optional.empty(), i1.instance().change().application());
+ assertEquals(Optional.empty(), i2.instance().change().application());
+ assertEquals(v0, i3.instance().change().application());
+ assertEquals(Optional.empty(), i4.instance().change().application());
+
+ // v0 begins roll-out in i3, and v1 is submitted and rolls out in i1 and i2 some time later
+ i3.runJob(productionUsEast3); // v0
+ tester.clock().advance(Duration.ofHours(12));
+ i1.submit(applicationPackage);
+ Optional<ApplicationVersion> v1 = i1.lastSubmission();
+ i4.runJob(systemTest).runJob(stagingTest);
+ i1.runJob(productionUsEast3); // v1
+ i2.runJob(productionUsEast3); // v1
+ assertEquals(v1, i1.instance().latestDeployed());
+ assertEquals(v1, i2.instance().latestDeployed());
+ assertEquals(Optional.empty(), i1.instance().change().application());
+ assertEquals(Optional.empty(), i2.instance().change().application());
+ assertEquals(v0, i3.instance().change().application());
+ assertEquals(Optional.empty(), i4.instance().change().application());
+
+ // After some time, v2 also starts rolling out to i1 and i2, but does not complete in i2
+ tester.clock().advance(Duration.ofHours(3));
+ i1.submit(applicationPackage);
+ Optional<ApplicationVersion> v2 = i1.lastSubmission();
+ i4.runJob(systemTest).runJob(stagingTest);
+ i1.runJob(productionUsEast3); // v2
+ tester.clock().advance(Duration.ofHours(3));
+
+ // v1 is all done in i1 and i2, but does not yet roll out in i3; v2 is not completely rolled out there yet.
+ tester.outstandingChangeDeployer().run();
+ assertEquals(v0, i3.instance().change().application());
+
+ // i3 completes v0, which rolls out to i4; v1 is ready for i3, but v2 is not.
+ i3.runJob(testUsEast3);
+ assertEquals(Optional.empty(), i3.instance().change().application());
+ tester.outstandingChangeDeployer().run();
+ assertEquals(v2, i1.instance().latestDeployed());
+ assertEquals(v1, i2.instance().latestDeployed());
+ assertEquals(v0, i3.instance().latestDeployed());
+ assertEquals(Optional.empty(), i1.instance().change().application());
+ assertEquals(v2, i2.instance().change().application());
+ assertEquals(v1, i3.instance().change().application());
+ assertEquals(v0, i4.instance().change().application());
+ }
+
+ @Test
public void testMultipleInstances() {
ApplicationPackage applicationPackage = new ApplicationPackageBuilder()
.instances("instance1,instance2")
@@ -998,48 +1171,65 @@ public class DeploymentTriggerTest {
assertEquals(Change.empty(), app2.instance().change());
assertEquals(Change.empty(), app3.instance().change());
- // Upgrade instance 1; a failure in any instance allows an application change to accompany the upgrade.
+ // Upgrade instance 1; upgrade rolls out first, with revision following.
// The new platform won't roll out to the conservative instance until the normal one is upgraded.
- app2.failDeployment(systemTest);
app1.submit(applicationPackage);
assertEquals(Change.of(version).with(app1.application().latestVersion().get()), app1.instance().change());
+ // Upgrade platform.
app2.runJob(systemTest);
- app1.jobAborted(stagingTest)
- .runJob(stagingTest)
+ app1.runJob(stagingTest)
.runJob(productionUsWest1)
.runJob(productionUsEast3);
- app1.runJob(stagingTest); // Tests with only the outstanding application change.
- app2.runJob(systemTest); // Tests with only the outstanding application change.
+ // Upgrade revision
+ tester.clock().advance(Duration.ofSeconds(1)); // Ensure we see revision as rolling after upgrade.
+ app2.runJob(systemTest); // R
+ app1.runJob(stagingTest) // R
+ .runJob(productionUsWest1); // R
+ // productionUsEast3 won't change revision before its production test has completed for the upgrade, which is one of the last jobs!
tester.clock().advance(Duration.ofHours(2));
app1.runJob(productionEuWest1);
tester.clock().advance(Duration.ofHours(1));
app1.runJob(productionAwsUsEast1a);
- tester.triggerJobs();
app1.runJob(testAwsUsEast1a);
+ tester.clock().advance(Duration.ofSeconds(1));
+ app1.runJob(productionAwsUsEast1a); // R
+ app1.runJob(testAwsUsEast1a); // R
app1.runJob(productionApNortheast2);
app1.runJob(productionApNortheast1);
tester.clock().advance(Duration.ofHours(1));
app1.runJob(testApNortheast1);
app1.runJob(testApNortheast2);
+ app1.runJob(productionApNortheast2); // R
+ app1.runJob(productionApNortheast1); // R
app1.runJob(testUsEast3);
app1.runJob(productionApSoutheast1);
+ tester.clock().advance(Duration.ofSeconds(1));
+ app1.runJob(productionUsEast3); // R
+ tester.clock().advance(Duration.ofHours(2));
+ app1.runJob(productionEuWest1); // R
+ tester.clock().advance(Duration.ofMinutes(330));
+ app1.runJob(testApNortheast1); // R
+ app1.runJob(testApNortheast2); // R
+ app1.runJob(testUsEast3); // R
+ app1.runJob(productionApSoutheast1); // R
+
+ app1.runJob(stagingTest); // Tests with only the outstanding application change.
+ app2.runJob(systemTest); // Tests with only the outstanding application change.
// Confidence rises to high, for the new version, and instance 2 starts to upgrade.
tester.controllerTester().computeVersionStatus();
tester.upgrader().maintain();
tester.outstandingChangeDeployer().run();
tester.triggerJobs();
- assertEquals(2, tester.jobs().active().size());
+ assertEquals(tester.jobs().active().toString(), 1, tester.jobs().active().size());
assertEquals(Change.empty(), app1.instance().change());
assertEquals(Change.of(version), app2.instance().change());
assertEquals(Change.empty(), app3.instance().change());
- app1.runJob(stagingTest); // Never completed successfully with just the upgrade.
- app2.runJob(systemTest) // Never completed successfully with just the upgrade.
- .runJob(productionEuWest1)
+ app2.runJob(productionEuWest1)
.failDeployment(testEuWest1);
- // Instance 2 failed the last job, and now exist block window, letting application change roll out with the upgrade.
+ // Instance 2 failed the last job, and now exits block window, letting application change roll out with the upgrade.
tester.clock().advance(Duration.ofDays(1)); // Leave block window for revisions.
tester.upgrader().maintain();
tester.outstandingChangeDeployer().run();
@@ -1054,18 +1244,19 @@ public class DeploymentTriggerTest {
assertEquals(Change.empty(), app2.instance().change());
assertEquals(Change.empty(), app3.instance().change());
- // Two first instances upgraded and with new revision — last instance gets change from whatever maintainer runs first.
+ // Two first instances upgraded and with new revision — last instance gets both changes as well.
tester.upgrader().maintain();
tester.outstandingChangeDeployer().run();
- assertEquals(Change.of(version), app3.instance().change());
+ assertEquals(Change.of(version).with(app1.lastSubmission().get()), app3.instance().change());
tester.deploymentTrigger().cancelChange(app3.instanceId(), ALL);
tester.outstandingChangeDeployer().run();
tester.upgrader().maintain();
- assertEquals(Change.of(app1.application().latestVersion().get()), app3.instance().change());
+ assertEquals(Change.of(app1.lastSubmission().get()), app3.instance().change());
app3.runJob(productionEuWest1);
tester.upgrader().maintain();
+ app1.runJob(stagingTest);
app3.runJob(productionEuWest1);
tester.triggerJobs();
assertEquals(List.of(), tester.jobs().active());
@@ -1073,22 +1264,410 @@ public class DeploymentTriggerTest {
}
@Test
- public void testChangeCompletion() {
- var app = tester.newDeploymentContext().submit().deploy();
- var version = new Version("7.1");
- tester.controllerTester().upgradeSystem(version);
+ public void testRevisionJoinsUpgradeWithSeparateRollout() {
+ var appPackage = new ApplicationPackageBuilder().region("us-central-1")
+ .region("us-east-3")
+ .region("us-west-1")
+ .upgradeRollout("separate")
+ .build();
+ var app = tester.newDeploymentContext().submit(appPackage).deploy();
+
+ // Platform rolls through first production zone.
+ var version0 = tester.controller().readSystemVersion();
+ var version1 = new Version("7.1");
+ tester.controllerTester().upgradeSystem(version1);
tester.upgrader().maintain();
app.runJob(systemTest).runJob(stagingTest).runJob(productionUsCentral1);
+ tester.clock().advance(Duration.ofMinutes(1));
- app.submit();
- tester.triggerJobs();
+ // Revision starts rolling, but stays behind.
+ var revision0 = app.lastSubmission();
+ app.submit(appPackage);
+ var revision1 = app.lastSubmission();
+ assertEquals(Change.of(version1).with(revision1.get()), app.instance().change());
+ app.runJob(systemTest).runJob(stagingTest).runJob(productionUsCentral1);
+
+ // Upgrade got here first, so attempts to proceed alone, but the upgrade fails.
+ app.triggerJobs();
+ assertEquals(new Versions(version1, revision0.get(), Optional.of(version0), revision0),
+ tester.jobs().last(app.instanceId(), productionUsEast3).get().versions());
+ app.timeOutConvergence(productionUsEast3);
+
+ // Revision is allowed to join.
+ app.triggerJobs();
+ assertEquals(new Versions(version1, revision1.get(), Optional.of(version1), revision0),
+ tester.jobs().last(app.instanceId(), productionUsEast3).get().versions());
+ app.runJob(productionUsEast3);
+
+ // Platform and revision now proceed together.
+ app.runJob(stagingTest);
+ app.triggerJobs();
+ assertEquals(new Versions(version1, revision1.get(), Optional.of(version0), revision0),
+ tester.jobs().last(app.instanceId(), productionUsWest1).get().versions());
+ app.runJob(productionUsWest1);
+ assertEquals(Change.empty(), app.instance().change());
+ }
+
+ @Test
+ public void testProductionTestBlockingDeploymentWithSeparateRollout() {
+ var appPackage = new ApplicationPackageBuilder().region("us-east-3")
+ .region("us-west-1")
+ .delay(Duration.ofHours(1))
+ .test("us-east-3")
+ .upgradeRollout("separate")
+ .build();
+ var app = tester.newDeploymentContext().submit(appPackage)
+ .runJob(systemTest).runJob(stagingTest)
+ .runJob(productionUsEast3).runJob(productionUsWest1);
+ tester.clock().advance(Duration.ofHours(1));
+ app.runJob(testUsEast3);
+ assertEquals(Change.empty(), app.instance().change());
+
+ // Platform rolls through first production zone.
+ var version0 = tester.controller().readSystemVersion();
+ var version1 = new Version("7.1");
+ tester.controllerTester().upgradeSystem(version1);
+ tester.upgrader().maintain();
+ app.runJob(systemTest).runJob(stagingTest).runJob(productionUsEast3);
+
+ // Revision starts rolling, but waits for production test to verify the upgrade.
+ var revision0 = app.lastSubmission();
+ app.submit(appPackage);
+ var revision1 = app.lastSubmission();
+ assertEquals(Change.of(version1).with(revision1.get()), app.instance().change());
+ app.runJob(systemTest).runJob(stagingTest).triggerJobs();
+ app.assertRunning(productionUsWest1);
+ app.assertNotRunning(productionUsEast3);
+
+ // Upgrade got here first, so attempts to proceed alone, but the upgrade fails.
+ app.triggerJobs();
+ assertEquals(new Versions(version1, revision0.get(), Optional.of(version0), revision0),
+ tester.jobs().last(app.instanceId(), productionUsWest1).get().versions());
+ app.timeOutConvergence(productionUsWest1).triggerJobs();
+
+ // Upgrade now fails between us-east-3 deployment and test, so test is abandoned, and revision unblocked.
+ app.assertRunning(productionUsEast3);
+ assertEquals(new Versions(version1, revision1.get(), Optional.of(version1), revision0),
+ tester.jobs().last(app.instanceId(), productionUsEast3).get().versions());
+ app.runJob(productionUsEast3).triggerJobs()
+ .jobAborted(productionUsWest1).runJob(productionUsWest1);
+ tester.clock().advance(Duration.ofHours(1));
+ app.runJob(testUsEast3);
+ assertEquals(Change.empty(), app.instance().change());
+ }
+
+ @Test
+ public void testProductionTestNotBlockingDeploymentWithSimultaneousRollout() {
+ var appPackage = new ApplicationPackageBuilder().region("us-east-3")
+ .region("us-central-1")
+ .region("us-west-1")
+ .delay(Duration.ofHours(1))
+ .test("us-east-3")
+ .test("us-west-1")
+ .upgradeRollout("simultaneous")
+ .build();
+ var app = tester.newDeploymentContext().submit(appPackage)
+ .runJob(systemTest).runJob(stagingTest)
+ .runJob(productionUsEast3).runJob(productionUsCentral1).runJob(productionUsWest1);
+ tester.clock().advance(Duration.ofHours(1));
+ app.runJob(testUsEast3).runJob(testUsWest1);
+ assertEquals(Change.empty(), app.instance().change());
+
+ // Platform rolls through first production zone.
+ var version0 = tester.controller().readSystemVersion();
+ var version1 = new Version("7.1");
+ tester.controllerTester().upgradeSystem(version1);
+ tester.upgrader().maintain();
+ app.runJob(systemTest).runJob(stagingTest).runJob(productionUsEast3);
+
+ // Revision starts rolling, and causes production test to abort when it reaches deployment.
+ var revision0 = app.lastSubmission();
+ app.submit(appPackage);
+ var revision1 = app.lastSubmission();
+ assertEquals(Change.of(version1).with(revision1.get()), app.instance().change());
+ app.runJob(systemTest).runJob(stagingTest).triggerJobs();
+ app.assertRunning(productionUsCentral1);
+ app.assertRunning(productionUsEast3);
+
+ // Revision deploys to first prod zone.
+ app.triggerJobs();
+ assertEquals(new Versions(version1, revision1.get(), Optional.of(version1), revision0),
+ tester.jobs().last(app.instanceId(), productionUsEast3).get().versions());
+ tester.clock().advance(Duration.ofSeconds(1));
+ app.runJob(productionUsEast3);
+
+ // Revision catches up in second prod zone.
+ app.runJob(systemTest).runJob(stagingTest).runJob(stagingTest).triggerJobs();
+ app.jobAborted(productionUsCentral1).triggerJobs();
+ assertEquals(new Versions(version1, revision1.get(), Optional.of(version0), revision0),
+ tester.jobs().last(app.instanceId(), productionUsCentral1).get().versions());
+ app.runJob(productionUsCentral1).triggerJobs();
+
+ // Revision proceeds alone in third prod zone, making test targets different for the two prod tests.
+ assertEquals(new Versions(version0, revision1.get(), Optional.of(version0), revision0),
+ tester.jobs().last(app.instanceId(), productionUsWest1).get().versions());
+ app.runJob(productionUsWest1);
+ app.triggerJobs();
+ app.assertNotRunning(testUsEast3);
+ tester.clock().advance(Duration.ofHours(1));
+
+ // Test lets revision proceed alone, and us-west-1 is blocked until tested.
+ app.runJob(testUsEast3).triggerJobs();
+ app.assertNotRunning(productionUsWest1);
+ app.runJob(testUsWest1).runJob(productionUsWest1).runJob(testUsWest1); // Test for us-east-3 is not re-run.
+ assertEquals(Change.empty(), app.instance().change());
+ }
+
+ @Test
+ public void testVeryLengthyPipelineRevisions() {
+ String lengthyDeploymentSpec =
+ "<deployment version='1.0'>\n" +
+ " <instance id='alpha'>\n" +
+ " <test />\n" +
+ " <staging />\n" +
+ " <upgrade revision='latest' />\n" +
+ " <prod>\n" +
+ " <region>us-east-3</region>\n" +
+ " <test>us-east-3</test>\n" +
+ " </prod>\n" +
+ " </instance>\n" +
+ " <instance id='beta'>\n" +
+ " <upgrade revision='separate' />\n" +
+ " <prod>\n" +
+ " <region>us-east-3</region>\n" +
+ " <test>us-east-3</test>\n" +
+ " </prod>\n" +
+ " </instance>\n" +
+ " <instance id='gamma'>\n" +
+ " <upgrade revision='separate' />\n" + // TODO: change to new, even stricter policy.
+ " <prod>\n" +
+ " <region>us-east-3</region>\n" +
+ " <test>us-east-3</test>\n" +
+ " </prod>\n" +
+ " </instance>\n" +
+ "</deployment>\n";
+ var appPackage = ApplicationPackageBuilder.fromDeploymentXml(lengthyDeploymentSpec);
+ var alpha = tester.newDeploymentContext("t", "a", "alpha");
+ var beta = tester.newDeploymentContext("t", "a", "beta");
+ var gamma = tester.newDeploymentContext("t", "a", "gamma");
+ alpha.submit(appPackage).deploy();
+
+ // revision2 is submitted, and rolls through alpha.
+ var revision1 = alpha.lastSubmission();
+ alpha.submit(appPackage);
+ var revision2 = alpha.lastSubmission();
+
+ alpha.runJob(systemTest).runJob(stagingTest)
+ .runJob(productionUsEast3).runJob(testUsEast3);
+ assertEquals(Optional.empty(), alpha.instance().change().application());
+
+ // revision3 is submitted when revision2 is half-way.
tester.outstandingChangeDeployer().run();
- assertEquals(Change.of(version), app.instance().change());
+ beta.runJob(productionUsEast3);
+ alpha.submit(appPackage);
+ var revision3 = alpha.lastSubmission();
+ beta.runJob(testUsEast3);
+ assertEquals(Optional.empty(), beta.instance().change().application());
- app.runJob(productionUsEast3).runJob(productionUsWest1);
- tester.triggerJobs();
+ // revision3 is the target for alpha, beta is done, version1 is the target for gamma.
+ tester.outstandingChangeDeployer().run();
+ assertEquals(revision3, alpha.instance().change().application());
+ assertEquals(Optional.empty(), beta.instance().change().application());
+ assertEquals(revision2, gamma.instance().change().application());
+
+ // revision3 rolls to beta, then a couple of new revisions are submitted to alpha, and the latter is the new target.
+ alpha.runJob(systemTest).runJob(stagingTest)
+ .runJob(productionUsEast3).runJob(testUsEast3);
+ tester.outstandingChangeDeployer().run();
+ assertEquals(Optional.empty(), alpha.instance().change().application());
+ assertEquals(revision3, beta.instance().change().application());
+
+ // revision5 supersedes revision4
+ alpha.submit(appPackage);
+ var revision4 = alpha.lastSubmission();
+ alpha.runJob(systemTest).runJob(stagingTest)
+ .runJob(productionUsEast3);
+ alpha.submit(appPackage);
+ var revision5 = alpha.lastSubmission();
+ alpha.runJob(systemTest).runJob(stagingTest)
+ .runJob(productionUsEast3).runJob(testUsEast3);
tester.outstandingChangeDeployer().run();
- assertEquals(Change.of(app.lastSubmission().get()), app.instance().change());
+ assertEquals(Optional.empty(), alpha.instance().change().application());
+ assertEquals(revision3, beta.instance().change().application());
+
+ // revision6 rolls through alpha, and becomes the next target for beta
+ alpha.submit(appPackage);
+ var revision6 = alpha.lastSubmission();
+ alpha.runJob(systemTest).runJob(stagingTest)
+ .runJob(productionUsEast3)
+ .runJob(testUsEast3);
+ beta.runJob(productionUsEast3).runJob(testUsEast3);
+ tester.outstandingChangeDeployer().run();
+ assertEquals(Optional.empty(), alpha.instance().change().application());
+ assertEquals(revision6, beta.instance().change().application());
+
+ // revision6 rolls through beta, but revision3 is the next target for the strictest revision policy, in gamma
+ alpha.jobAborted(stagingTest).runJob(stagingTest);
+ beta.runJob(productionUsEast3).runJob(testUsEast3);
+ gamma.runJob(productionUsEast3).runJob(testUsEast3);
+ tester.outstandingChangeDeployer().run();
+ assertEquals(Optional.empty(), alpha.instance().change().application());
+ assertEquals(Optional.empty(), beta.instance().change().application());
+ // TODO: assertEquals(revision3, gamma.instance().change().application());
+ }
+
+ @Test
+ public void testVeryLengthyPipelineUpgrade() {
+ String lengthyDeploymentSpec =
+ "<deployment version='1.0'>\n" +
+ " <instance id='alpha'>\n" +
+ " <test />\n" +
+ " <staging />\n" +
+ " <upgrade rollout='simultaneous' />\n" +
+ " <prod>\n" +
+ " <region>us-east-3</region>\n" +
+ " <test>us-east-3</test>\n" +
+ " </prod>\n" +
+ " </instance>\n" +
+ " <instance id='beta'>\n" +
+ " <upgrade rollout='simultaneous' />\n" +
+ " <prod>\n" +
+ " <region>us-east-3</region>\n" +
+ " <test>us-east-3</test>\n" +
+ " </prod>\n" +
+ " </instance>\n" +
+ " <instance id='gamma'>\n" +
+ " <upgrade rollout='separate' />\n" +
+ " <prod>\n" +
+ " <region>us-east-3</region>\n" +
+ " <test>us-east-3</test>\n" +
+ " </prod>\n" +
+ " </instance>\n" +
+ "</deployment>\n";
+ var appPackage = ApplicationPackageBuilder.fromDeploymentXml(lengthyDeploymentSpec);
+ var alpha = tester.newDeploymentContext("t", "a", "alpha");
+ var beta = tester.newDeploymentContext("t", "a", "beta");
+ var gamma = tester.newDeploymentContext("t", "a", "gamma");
+ alpha.submit(appPackage).deploy();
+
+ // A version releases, but when the first upgrade has gotten through alpha, beta, and gamma, a newer version has high confidence.
+ var version0 = tester.controller().readSystemVersion();
+ var version1 = new Version("7.1");
+ var version2 = new Version("7.2");
+ tester.controllerTester().upgradeSystem(version1);
+
+ tester.upgrader().maintain();
+ alpha.runJob(systemTest).runJob(stagingTest)
+ .runJob(productionUsEast3).runJob(testUsEast3);
+ assertEquals(Change.empty(), alpha.instance().change());
+
+ tester.upgrader().maintain();
+ beta.runJob(productionUsEast3);
+ tester.controllerTester().upgradeSystem(version2);
+ beta.runJob(testUsEast3);
+ assertEquals(Change.empty(), beta.instance().change());
+
+ tester.upgrader().maintain();
+ assertEquals(Change.of(version2), alpha.instance().change());
+ assertEquals(Change.empty(), beta.instance().change());
+ assertEquals(Change.of(version1), gamma.instance().change());
+ }
+
+ @Test
+ public void testRevisionJoinsUpgradeWithLeadingRollout() {
+ var appPackage = new ApplicationPackageBuilder().region("us-central-1")
+ .region("us-east-3")
+ .region("us-west-1")
+ .upgradeRollout("leading")
+ .build();
+ var app = tester.newDeploymentContext().submit(appPackage).deploy();
+
+ // Platform rolls through first production zone.
+ var version0 = tester.controller().readSystemVersion();
+ var version1 = new Version("7.1");
+ tester.controllerTester().upgradeSystem(version1);
+ tester.upgrader().maintain();
+ app.runJob(systemTest).runJob(stagingTest).runJob(productionUsCentral1);
+ tester.clock().advance(Duration.ofMinutes(1));
+
+ // Revision starts rolling, and catches up.
+ var revision0 = app.lastSubmission();
+ app.submit(appPackage);
+ var revision1 = app.lastSubmission();
+ assertEquals(Change.of(version1).with(revision1.get()), app.instance().change());
+ app.runJob(systemTest).runJob(stagingTest).runJob(productionUsCentral1);
+
+ // Upgrade got here first, and has triggered, but is now obsolete.
+ app.triggerJobs();
+ assertEquals(new Versions(version1, revision0.get(), Optional.of(version0), revision0),
+ tester.jobs().last(app.instanceId(), productionUsEast3).get().versions());
+ assertEquals(RunStatus.running, tester.jobs().last(app.instanceId(), productionUsEast3).get().status());
+
+ // Once staging tests verify the joint upgrade, the job is replaced with that.
+ app.runJob(stagingTest);
+ app.triggerJobs();
+ app.jobAborted(productionUsEast3).runJob(productionUsEast3);
+ assertEquals(new Versions(version1, revision1.get(), Optional.of(version0), revision0),
+ tester.jobs().last(app.instanceId(), productionUsEast3).get().versions());
+
+ // Platform and revision now proceed together.
+ app.triggerJobs();
+ assertEquals(new Versions(version1, revision1.get(), Optional.of(version0), revision0),
+ tester.jobs().last(app.instanceId(), productionUsWest1).get().versions());
+ app.runJob(productionUsWest1);
+ assertEquals(Change.empty(), app.instance().change());
+ }
+
+ @Test
+ public void testRevisionPassesUpgradeWithSimultaneousRollout() {
+ var appPackage = new ApplicationPackageBuilder().region("us-central-1")
+ .region("us-east-3")
+ .region("us-west-1")
+ .upgradeRollout("simultaneous")
+ .build();
+ var app = tester.newDeploymentContext().submit(appPackage).deploy();
+
+ // Platform rolls through first production zone.
+ var version0 = tester.controller().readSystemVersion();
+ var version1 = new Version("7.1");
+ tester.controllerTester().upgradeSystem(version1);
+ tester.upgrader().maintain();
+ app.runJob(systemTest).runJob(stagingTest).runJob(productionUsCentral1);
+ tester.clock().advance(Duration.ofMinutes(1));
+
+ // Revision starts rolling, and catches up.
+ var revision0 = app.lastSubmission();
+ app.submit(appPackage);
+ var revision1 = app.lastSubmission();
+ assertEquals(Change.of(version1).with(revision1.get()), app.instance().change());
+ app.runJob(systemTest).runJob(stagingTest).runJob(productionUsCentral1);
+
+ // Upgrade got here first, and has triggered, but is now obsolete.
+ app.triggerJobs();
+ app.assertRunning(productionUsEast3);
+ assertEquals(new Versions(version1, revision0.get(), Optional.of(version0), revision0),
+ tester.jobs().last(app.instanceId(), productionUsEast3).get().versions());
+ assertEquals(RunStatus.running, tester.jobs().last(app.instanceId(), productionUsEast3).get().status());
+
+ // Once staging tests verify the joint upgrade, the job is replaced with that.
+ app.runJob(systemTest).runJob(stagingTest).runJob(stagingTest);
+ app.triggerJobs();
+ app.jobAborted(productionUsEast3).runJob(productionUsEast3);
+ assertEquals(new Versions(version1, revision1.get(), Optional.of(version0), revision0),
+ tester.jobs().last(app.instanceId(), productionUsEast3).get().versions());
+
+ // Revision now proceeds alone.
+ app.triggerJobs();
+ assertEquals(new Versions(version0, revision1.get(), Optional.of(version0), revision0),
+ tester.jobs().last(app.instanceId(), productionUsWest1).get().versions());
+ app.runJob(productionUsWest1);
+
+ // Upgrade follows.
+ app.triggerJobs();
+ assertEquals(new Versions(version1, revision1.get(), Optional.of(version0), revision1),
+ tester.jobs().last(app.instanceId(), productionUsWest1).get().versions());
+ app.runJob(productionUsWest1);
+ assertEquals(Change.empty(), app.instance().change());
}
@Test
@@ -1102,7 +1681,7 @@ public class DeploymentTriggerTest {
ZoneId.from("prod.cd-aws-us-east-1a"));
tester.controllerTester()
.setZones(zones, SystemName.cd)
- .setRoutingMethod(zones, RoutingMethod.shared);
+ .setRoutingMethod(zones, RoutingMethod.sharedLayer4);
tester.controllerTester().upgradeSystem(Version.fromString("6.1"));
tester.controllerTester().computeVersionStatus();
var app = tester.newDeploymentContext();
@@ -1114,9 +1693,10 @@ public class DeploymentTriggerTest {
tester.controller().applications().deploymentTrigger().forceTrigger(app.instanceId(), productionCdUsEast1, "user", false);
app.runJob(productionCdUsEast1)
.abortJob(stagingTest) // Complete failing run.
- .runJob(stagingTest)
+ .runJob(stagingTest) // Run staging-test for production zone with no prior deployment.
.runJob(productionCdAwsUsEast1a);
+ // Manually deploy to east again, then upgrade the system.
app.runJob(productionCdUsEast1, cdPackage);
var version = new Version("7.1");
tester.controllerTester().upgradeSystem(version);
@@ -1124,16 +1704,16 @@ public class DeploymentTriggerTest {
// System and staging tests both require unknown versions, and are broken.
tester.controller().applications().deploymentTrigger().forceTrigger(app.instanceId(), productionCdUsEast1, "user", false);
app.runJob(productionCdUsEast1)
- .jobAborted(systemTest)
+ .abortJob(systemTest)
.jobAborted(stagingTest)
- .runJob(systemTest)
- .runJob(stagingTest)
+ .runJob(systemTest) // Run test for aws zone again.
+ .runJob(stagingTest) // Run test for aws zone again.
.runJob(productionCdAwsUsEast1a);
+ // Deploy manually again, then submit new package.
app.runJob(productionCdUsEast1, cdPackage);
app.submit(cdPackage);
- app.jobAborted(systemTest)
- .runJob(systemTest);
+ app.runJob(systemTest);
// Staging test requires unknown initial version, and is broken.
tester.controller().applications().deploymentTrigger().forceTrigger(app.instanceId(), productionCdUsEast1, "user", false);
app.runJob(productionCdUsEast1)
@@ -1145,7 +1725,7 @@ public class DeploymentTriggerTest {
@Test
public void testsInSeparateInstance() {
String deploymentSpec =
- "<deployment version='1.0'>\n" +
+ "<deployment version='1.0' athenz-domain='domain' athenz-service='service'>\n" +
" <instance id='canary'>\n" +
" <upgrade policy='canary' />\n" +
" <test />\n" +
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 061cc69fc26..d9b10ec933c 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
@@ -28,6 +28,7 @@ import com.yahoo.vespa.hosted.controller.application.SystemApplication;
import com.yahoo.vespa.hosted.controller.application.pkg.ApplicationPackage;
import com.yahoo.vespa.hosted.controller.config.ControllerConfig;
import com.yahoo.vespa.hosted.controller.integration.ZoneApiMock;
+import com.yahoo.vespa.hosted.controller.maintenance.JobRunner;
import org.junit.Before;
import org.junit.Test;
@@ -53,6 +54,9 @@ import static com.yahoo.vespa.hosted.controller.deployment.DeploymentContext.app
import static com.yahoo.vespa.hosted.controller.deployment.DeploymentTester.instanceId;
import static com.yahoo.vespa.hosted.controller.deployment.RunStatus.deploymentFailed;
import static com.yahoo.vespa.hosted.controller.deployment.RunStatus.installationFailed;
+import static com.yahoo.vespa.hosted.controller.deployment.RunStatus.reset;
+import static com.yahoo.vespa.hosted.controller.deployment.RunStatus.running;
+import static com.yahoo.vespa.hosted.controller.deployment.RunStatus.success;
import static com.yahoo.vespa.hosted.controller.deployment.Step.Status.failed;
import static com.yahoo.vespa.hosted.controller.deployment.Step.Status.succeeded;
import static com.yahoo.vespa.hosted.controller.deployment.Step.Status.unfinished;
@@ -336,6 +340,47 @@ public class InternalStepRunnerTest {
}
@Test
+ public void testCanBeReset() {
+ RunId id = app.startSystemTestTests();
+ tester.cloud().add(new LogEntry(0, Instant.ofEpochMilli(123), info, "Not enough data!"));
+ tester.cloud().set(TesterCloud.Status.INCONCLUSIVE);
+
+ long lastId1 = tester.jobs().details(id).get().lastId().getAsLong();
+ Instant instant1 = tester.clock().instant();
+ tester.runner().run();
+ assertEquals(unfinished, tester.jobs().run(id).get().stepStatuses().get(Step.endTests));
+ assertEquals(running, tester.jobs().run(id).get().status());
+ tester.cloud().clearLog();
+
+ // Test sleeps for a while.
+ tester.runner().run();
+ assertEquals(unfinished, tester.jobs().run(id).get().stepStatuses().get(Step.deployTester));
+ tester.clock().advance(Duration.ofSeconds(899));
+ tester.runner().run();
+ assertEquals(unfinished, tester.jobs().run(id).get().stepStatuses().get(Step.deployTester));
+
+ tester.clock().advance(JobRunner.jobTimeout);
+ var testZone = JobType.systemTest.zone(tester.controller().system());
+ tester.runner().run();
+ app.flushDnsUpdates();
+ tester.configServer().convergeServices(app.instanceId(), testZone);
+ tester.configServer().convergeServices(app.testerId().id(), testZone);
+ tester.runner().run();
+ assertEquals(unfinished, tester.jobs().run(id).get().stepStatuses().get(Step.endTests));
+ assertTrue(tester.jobs().run(id).get().steps().get(Step.endTests).startTime().isPresent());
+
+ tester.cloud().set(TesterCloud.Status.SUCCESS);
+ long lastId2 = tester.jobs().details(id).get().lastId().getAsLong();
+ tester.runner().run();
+ assertEquals(success, tester.jobs().run(id).get().status());
+
+ assertTestLogEntries(id, Step.endTests,
+ new LogEntry(lastId1 + 1, Instant.ofEpochMilli(123), info, "Not enough data!"),
+ new LogEntry(lastId1 + 2, instant1, info, "Tests were inconclusive, and will run again in 15 minutes."),
+ new LogEntry(lastId2 + 1, tester.clock().instant(), info, "Tests completed successfully."));
+ }
+
+ @Test
public void deployToDev() {
ZoneId zone = JobType.devUsEast1.zone(system());
tester.jobs().deploy(app.instanceId(), JobType.devUsEast1, Optional.empty(), applicationPackage());
@@ -482,7 +527,7 @@ public class InternalStepRunnerTest {
tester.clock().advance(InternalStepRunner.Timeouts.of(system()).testerCertificate().plus(Duration.ofSeconds(1)));
tester.runner().run();
- assertEquals(RunStatus.aborted, tester.jobs().run(id).get().status());
+ assertEquals(RunStatus.error, tester.jobs().run(id).get().status());
}
private void assertTestLogEntries(RunId id, Step step, LogEntry... entries) {
diff --git a/controller-server/src/test/java/com/yahoo/vespa/hosted/controller/integration/ServiceRegistryMock.java b/controller-server/src/test/java/com/yahoo/vespa/hosted/controller/integration/ServiceRegistryMock.java
index b81b3ae5d66..74c06d7ca1a 100644
--- a/controller-server/src/test/java/com/yahoo/vespa/hosted/controller/integration/ServiceRegistryMock.java
+++ b/controller-server/src/test/java/com/yahoo/vespa/hosted/controller/integration/ServiceRegistryMock.java
@@ -11,15 +11,15 @@ import com.yahoo.vespa.hosted.controller.api.integration.archive.ArchiveService;
import com.yahoo.vespa.hosted.controller.api.integration.archive.MockArchiveService;
import com.yahoo.vespa.hosted.controller.api.integration.athenz.AccessControlService;
import com.yahoo.vespa.hosted.controller.api.integration.athenz.MockAccessControlService;
-import com.yahoo.vespa.hosted.controller.api.integration.aws.MockRoleService;
-import com.yahoo.vespa.hosted.controller.api.integration.aws.RoleService;
import com.yahoo.vespa.hosted.controller.api.integration.aws.MockCloudEventFetcher;
import com.yahoo.vespa.hosted.controller.api.integration.aws.MockResourceTagger;
+import com.yahoo.vespa.hosted.controller.api.integration.aws.MockRoleService;
import com.yahoo.vespa.hosted.controller.api.integration.aws.ResourceTagger;
+import com.yahoo.vespa.hosted.controller.api.integration.aws.RoleService;
import com.yahoo.vespa.hosted.controller.api.integration.billing.BillingController;
import com.yahoo.vespa.hosted.controller.api.integration.billing.BillingDatabaseClient;
-import com.yahoo.vespa.hosted.controller.api.integration.billing.MockBillingController;
import com.yahoo.vespa.hosted.controller.api.integration.billing.BillingDatabaseClientMock;
+import com.yahoo.vespa.hosted.controller.api.integration.billing.MockBillingController;
import com.yahoo.vespa.hosted.controller.api.integration.billing.PlanRegistry;
import com.yahoo.vespa.hosted.controller.api.integration.billing.PlanRegistryMock;
import com.yahoo.vespa.hosted.controller.api.integration.certificates.EndpointCertificateMock;
@@ -32,10 +32,8 @@ import com.yahoo.vespa.hosted.controller.api.integration.horizon.MockHorizonClie
import com.yahoo.vespa.hosted.controller.api.integration.organization.MockContactRetriever;
import com.yahoo.vespa.hosted.controller.api.integration.organization.MockIssueHandler;
import com.yahoo.vespa.hosted.controller.api.integration.resource.CostReportConsumerMock;
-import com.yahoo.vespa.hosted.controller.api.integration.resource.ResourceDatabaseClientMock;
import com.yahoo.vespa.hosted.controller.api.integration.resource.ResourceDatabaseClient;
-import com.yahoo.vespa.hosted.controller.api.integration.routing.GlobalRoutingService;
-import com.yahoo.vespa.hosted.controller.api.integration.routing.MemoryGlobalRoutingService;
+import com.yahoo.vespa.hosted.controller.api.integration.resource.ResourceDatabaseClientMock;
import com.yahoo.vespa.hosted.controller.api.integration.secrets.NoopTenantSecretService;
import com.yahoo.vespa.hosted.controller.api.integration.stubs.DummyOwnershipIssues;
import com.yahoo.vespa.hosted.controller.api.integration.stubs.DummySystemMonitor;
@@ -59,7 +57,6 @@ public class ServiceRegistryMock extends AbstractComponent implements ServiceReg
private final ZoneRegistryMock zoneRegistryMock;
private final ConfigServerMock configServerMock;
private final MemoryNameService memoryNameService = new MemoryNameService();
- private final MemoryGlobalRoutingService memoryGlobalRoutingService = new MemoryGlobalRoutingService();
private final MockMailer mockMailer = new MockMailer();
private final EndpointCertificateMock endpointCertificateMock = new EndpointCertificateMock();
private final EndpointCertificateValidatorMock endpointCertificateValidatorMock = new EndpointCertificateValidatorMock();
@@ -116,11 +113,6 @@ public class ServiceRegistryMock extends AbstractComponent implements ServiceReg
}
@Override
- public GlobalRoutingService globalRoutingService() {
- return memoryGlobalRoutingService;
- }
-
- @Override
public MockMailer mailer() {
return mockMailer;
}
@@ -279,10 +271,6 @@ public class ServiceRegistryMock extends AbstractComponent implements ServiceReg
return configServerMock;
}
- public MemoryGlobalRoutingService globalRoutingServiceMock() {
- return memoryGlobalRoutingService;
- }
-
public MockContactRetriever contactRetrieverMock() {
return mockContactRetriever;
}
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 23ab91aaf8c..a4c30cca29e 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
@@ -52,26 +52,28 @@ public class ZoneRegistryMock extends AbstractComponent implements ZoneRegistry
*/
public ZoneRegistryMock(SystemName system) {
this.system = system;
- this.zones = system.isPublic() ?
- List.of(ZoneApiMock.fromId("test.aws-us-east-1c"),
- ZoneApiMock.fromId("staging.aws-us-east-1c"),
- ZoneApiMock.fromId("prod.aws-us-east-1c"),
- ZoneApiMock.fromId("prod.aws-eu-west-1a")) :
- List.of(ZoneApiMock.fromId("test.us-east-1"),
- ZoneApiMock.fromId("staging.us-east-3"),
- 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.fromId("prod.ap-northeast-1"),
- ZoneApiMock.fromId("prod.ap-northeast-2"),
- ZoneApiMock.fromId("prod.ap-southeast-1"),
- ZoneApiMock.fromId("prod.us-east-3"),
- ZoneApiMock.fromId("prod.us-west-1"),
- ZoneApiMock.fromId("prod.us-central-1"),
- ZoneApiMock.fromId("prod.eu-west-1"));
- // All zones use a shared routing method by default
- setRoutingMethod(this.zones, system.isPublic() ? RoutingMethod.exclusive : RoutingMethod.shared);
+ if (system.isPublic()) {
+ this.zones = List.of(ZoneApiMock.fromId("test.aws-us-east-1c"),
+ ZoneApiMock.fromId("staging.aws-us-east-1c"),
+ ZoneApiMock.fromId("prod.aws-us-east-1c"),
+ ZoneApiMock.fromId("prod.aws-eu-west-1a"));
+ setRoutingMethod(this.zones, RoutingMethod.exclusive);
+ } else {
+ this.zones = List.of(ZoneApiMock.fromId("test.us-east-1"),
+ ZoneApiMock.fromId("staging.us-east-3"),
+ 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.fromId("prod.ap-northeast-1"),
+ ZoneApiMock.fromId("prod.ap-northeast-2"),
+ ZoneApiMock.fromId("prod.ap-southeast-1"),
+ ZoneApiMock.fromId("prod.us-east-3"),
+ ZoneApiMock.fromId("prod.us-west-1"),
+ ZoneApiMock.fromId("prod.us-central-1"),
+ ZoneApiMock.fromId("prod.eu-west-1"));
+ setRoutingMethod(this.zones, RoutingMethod.sharedLayer4);
+ }
}
public ZoneRegistryMock setDeploymentTimeToLive(ZoneId zone, Duration duration) {
@@ -117,18 +119,15 @@ public class ZoneRegistryMock extends AbstractComponent implements ZoneRegistry
}
public ZoneRegistryMock setRoutingMethod(ZoneApi zone, RoutingMethod... routingMethods) {
- return setRoutingMethod(zone, List.of(routingMethods));
+ return setRoutingMethod(zone, Set.of(routingMethods));
}
public ZoneRegistryMock setRoutingMethod(List<? extends ZoneApi> zones, RoutingMethod... routingMethods) {
- zones.forEach(zone -> setRoutingMethod(zone, List.of(routingMethods)));
+ zones.forEach(zone -> setRoutingMethod(zone, Set.of(routingMethods)));
return this;
}
- public ZoneRegistryMock setRoutingMethod(ZoneApi zone, List<RoutingMethod> routingMethods) {
- if (routingMethods.stream().distinct().count() != routingMethods.size()) {
- throw new IllegalArgumentException("Routing methods must be distinct");
- }
+ private ZoneRegistryMock setRoutingMethod(ZoneApi zone, Set<RoutingMethod> routingMethods) {
this.zoneRoutingMethods.put(zone, List.copyOf(routingMethods));
return this;
}
diff --git a/controller-server/src/test/java/com/yahoo/vespa/hosted/controller/maintenance/ArchiveAccessMaintainerTest.java b/controller-server/src/test/java/com/yahoo/vespa/hosted/controller/maintenance/ArchiveAccessMaintainerTest.java
index d6e43c07ec8..df2b462914e 100644
--- a/controller-server/src/test/java/com/yahoo/vespa/hosted/controller/maintenance/ArchiveAccessMaintainerTest.java
+++ b/controller-server/src/test/java/com/yahoo/vespa/hosted/controller/maintenance/ArchiveAccessMaintainerTest.java
@@ -15,6 +15,7 @@ import org.junit.Test;
import java.time.Duration;
import java.util.Map;
import java.util.Optional;
+import java.util.Set;
import java.util.stream.Collectors;
import static org.junit.Assert.assertEquals;
@@ -35,14 +36,16 @@ public class ArchiveAccessMaintainerTest {
createTenantWithAccessRole(tester, "tenant2", tenant2role);
ZoneId testZone = ZoneId.from("prod.aws-us-east-1c");
- tester.controller().archiveBucketDb().archiveUriFor(testZone, tenant1);
+ tester.controller().archiveBucketDb().archiveUriFor(testZone, tenant1, true);
var testBucket = new ArchiveBucket("bucketName", "keyArn").withTenant(tenant1);
MockArchiveService archiveService = (MockArchiveService) tester.controller().serviceRegistry().archiveService();
- assertNull(archiveService.authorizedIamRoles.get(testBucket));
+ assertNull(archiveService.authorizedIamRolesForBucket.get(testBucket));
+ assertNull(archiveService.authorizedIamRolesForKey.get(testBucket.keyArn()));
MockMetric metric = new MockMetric();
new ArchiveAccessMaintainer(tester.controller(), metric, Duration.ofMinutes(10)).maintain();
- assertEquals(Map.of(tenant1, tenant1role), archiveService.authorizedIamRoles.get(testBucket));
+ assertEquals(Map.of(tenant1, tenant1role), archiveService.authorizedIamRolesForBucket.get(testBucket));
+ assertEquals(Set.of(tenant1role), archiveService.authorizedIamRolesForKey.get(testBucket.keyArn()));
var expected = Map.of("archive.bucketCount",
tester.controller().zoneRegistry().zones().all().ids().stream()
diff --git a/controller-server/src/test/java/com/yahoo/vespa/hosted/controller/maintenance/ArchiveUriUpdaterTest.java b/controller-server/src/test/java/com/yahoo/vespa/hosted/controller/maintenance/ArchiveUriUpdaterTest.java
index 451991f9604..0a2f5d9a236 100644
--- a/controller-server/src/test/java/com/yahoo/vespa/hosted/controller/maintenance/ArchiveUriUpdaterTest.java
+++ b/controller-server/src/test/java/com/yahoo/vespa/hosted/controller/maintenance/ArchiveUriUpdaterTest.java
@@ -43,6 +43,9 @@ public class ArchiveUriUpdaterTest {
// Initially we should not set any archive URIs as the archive service does not return any
updater.maintain();
assertArchiveUris(Map.of(), zone);
+ // but the controller zone is always present
+ assertArchiveUris(Map.of(TenantName.from("hosted-vespa"), "s3://bucketName/hosted-vespa/"),
+ ZoneId.from("prod", "controller"));
// Archive service now has URI for tenant1, but tenant1 is not deployed in zone
setBucketNameInService(Map.of(tenant1, "uri-1"), zone);
diff --git a/controller-server/src/test/java/com/yahoo/vespa/hosted/controller/maintenance/DeploymentIssueReporterTest.java b/controller-server/src/test/java/com/yahoo/vespa/hosted/controller/maintenance/DeploymentIssueReporterTest.java
index 0e365ffd135..7c4203d253c 100644
--- a/controller-server/src/test/java/com/yahoo/vespa/hosted/controller/maintenance/DeploymentIssueReporterTest.java
+++ b/controller-server/src/test/java/com/yahoo/vespa/hosted/controller/maintenance/DeploymentIssueReporterTest.java
@@ -56,6 +56,22 @@ public class DeploymentIssueReporterTest {
}
@Test
+ public void nonProductionAppGetsNoIssues() {
+ tester.controllerTester().upgradeSystem(Version.fromString("6.2"));
+ var app = tester.newDeploymentContext("application", "tenant", "default");
+ Contact contact = tester.controllerTester().serviceRegistry().contactRetrieverMock().contact();
+ tester.controller().tenants().lockOrThrow(app.instanceId().tenant(), LockedTenant.Athenz.class, tenant ->
+ tester.controller().tenants().store(tenant.with(contact)));
+
+ // app submits a package with no production deployments, and shall not receive issues.
+ app.submit(new ApplicationPackageBuilder().systemTest().stagingTest().build()).runJob(systemTest).failDeployment(stagingTest);
+
+ // Advance to where deployment issues should be detected.
+ tester.clock().advance(maxFailureAge.plus(Duration.ofDays(1)));
+ assertFalse("No issues are produced for app.", issues.isOpenFor(app.application().id()));
+ }
+
+ @Test
public void testDeploymentFailureReporting() {
tester.controllerTester().upgradeSystem(Version.fromString("6.2"));
@@ -72,6 +88,7 @@ public class DeploymentIssueReporterTest {
tester.controller().tenants().lockOrThrow(app3.instanceId().tenant(), LockedTenant.Athenz.class, tenant ->
tester.controller().tenants().store(tenant.with(contact)));
+
// NOTE: All maintenance should be idempotent within a small enough time interval, so maintain is called twice in succession throughout.
// app 1 fails staging tests.
diff --git a/controller-server/src/test/java/com/yahoo/vespa/hosted/controller/maintenance/MetricsReporterTest.java b/controller-server/src/test/java/com/yahoo/vespa/hosted/controller/maintenance/MetricsReporterTest.java
index d97f1d58043..455e802e87b 100644
--- a/controller-server/src/test/java/com/yahoo/vespa/hosted/controller/maintenance/MetricsReporterTest.java
+++ b/controller-server/src/test/java/com/yahoo/vespa/hosted/controller/maintenance/MetricsReporterTest.java
@@ -283,7 +283,7 @@ public class MetricsReporterTest {
context.submit(applicationPackage).deploy();
reporter.maintain();
- assertEquals("Deployment queues name services requests", 6, metrics.getMetric(MetricsReporter.NAME_SERVICE_REQUESTS_QUEUED).intValue());
+ assertEquals("Deployment queues name services requests", 2, metrics.getMetric(MetricsReporter.NAME_SERVICE_REQUESTS_QUEUED).intValue());
context.flushDnsUpdates();
reporter.maintain();
diff --git a/controller-server/src/test/java/com/yahoo/vespa/hosted/controller/maintenance/OutstandingChangeDeployerTest.java b/controller-server/src/test/java/com/yahoo/vespa/hosted/controller/maintenance/OutstandingChangeDeployerTest.java
index 8e90cfc69f3..acaa8b24d9d 100644
--- a/controller-server/src/test/java/com/yahoo/vespa/hosted/controller/maintenance/OutstandingChangeDeployerTest.java
+++ b/controller-server/src/test/java/com/yahoo/vespa/hosted/controller/maintenance/OutstandingChangeDeployerTest.java
@@ -2,6 +2,7 @@
package com.yahoo.vespa.hosted.controller.maintenance;
import com.yahoo.component.Version;
+import com.yahoo.vespa.hosted.controller.api.integration.deployment.ApplicationVersion;
import com.yahoo.vespa.hosted.controller.api.integration.deployment.JobType;
import com.yahoo.vespa.hosted.controller.api.integration.deployment.SourceRevision;
import com.yahoo.vespa.hosted.controller.application.pkg.ApplicationPackage;
@@ -30,42 +31,34 @@ public class OutstandingChangeDeployerTest {
OutstandingChangeDeployer deployer = new OutstandingChangeDeployer(tester.controller(), Duration.ofMinutes(10));
ApplicationPackage applicationPackage = new ApplicationPackageBuilder()
.region("us-west-1")
+ .upgradeRevision("separate")
.build();
- var app1 = tester.newDeploymentContext("tenant", "app1", "default").submit(applicationPackage).deploy();
+ var app = tester.newDeploymentContext().submit(applicationPackage).deploy();
Version version = new Version(6, 2);
- tester.deploymentTrigger().triggerChange(app1.instanceId(), Change.of(version));
- tester.deploymentTrigger().triggerReadyJobs();
+ tester.deploymentTrigger().triggerChange(app.instanceId(), Change.of(version));
+ assertEquals(Change.of(version), app.instance().change());
+ assertFalse(app.deploymentStatus().outstandingChange(app.instance().name()).hasTargets());
- assertEquals(Change.of(version), app1.instance().change());
- assertFalse(app1.deploymentStatus().outstandingChange(app1.instance().name()).hasTargets());
+ app.submit(applicationPackage);
+ Optional<ApplicationVersion> revision = app.lastSubmission();
+ assertFalse(app.deploymentStatus().outstandingChange(app.instance().name()).hasTargets());
+ assertEquals(Change.of(version).with(revision.get()), app.instance().change());
- assertEquals(1, app1.application().latestVersion().get().buildNumber().getAsLong());
- app1.submit(applicationPackage, Optional.of(new SourceRevision("repository1", "master", "cafed00d")));
+ app.submit(applicationPackage);
+ Optional<ApplicationVersion> outstanding = app.lastSubmission();
+ assertTrue(app.deploymentStatus().outstandingChange(app.instance().name()).hasTargets());
+ assertEquals(Change.of(version).with(revision.get()), app.instance().change());
- assertTrue(app1.deploymentStatus().outstandingChange(app1.instance().name()).hasTargets());
- assertEquals("1.0.2-cafed00d", app1.deploymentStatus().outstandingChange(app1.instance().name()).application().get().id());
- app1.assertRunning(JobType.systemTest);
- app1.assertRunning(JobType.stagingTest);
- assertEquals(2, tester.jobs().active().size());
+ tester.outstandingChangeDeployer().run();
+ assertTrue(app.deploymentStatus().outstandingChange(app.instance().name()).hasTargets());
+ assertEquals(Change.of(version).with(revision.get()), app.instance().change());
- deployer.maintain();
- tester.triggerJobs();
- assertEquals("No effect as job is in progress", 2, tester.jobs().active().size());
- assertEquals("1.0.2-cafed00d", app1.deploymentStatus().outstandingChange(app1.instance().name()).application().get().id());
-
- app1.runJob(JobType.systemTest).runJob(JobType.stagingTest).runJob(JobType.productionUsWest1)
- .runJob(JobType.stagingTest).runJob(JobType.systemTest);
- assertEquals("Upgrade done", 0, tester.jobs().active().size());
-
- deployer.maintain();
- tester.triggerJobs();
- assertEquals("1.0.2-cafed00d", app1.instance().change().application().get().id());
- List<Run> runs = tester.jobs().active();
- assertEquals(1, runs.size());
- app1.assertRunning(JobType.productionUsWest1);
- assertFalse(app1.deploymentStatus().outstandingChange(app1.instance().name()).hasTargets());
+ app.deploy();
+ tester.outstandingChangeDeployer().run();
+ assertFalse(app.deploymentStatus().outstandingChange(app.instance().name()).hasTargets());
+ assertEquals(Change.of(outstanding.get()), app.instance().change());
}
}
diff --git a/controller-server/src/test/java/com/yahoo/vespa/hosted/controller/maintenance/UpgraderTest.java b/controller-server/src/test/java/com/yahoo/vespa/hosted/controller/maintenance/UpgraderTest.java
index f9a976fcadc..265dedec8d0 100644
--- a/controller-server/src/test/java/com/yahoo/vespa/hosted/controller/maintenance/UpgraderTest.java
+++ b/controller-server/src/test/java/com/yahoo/vespa/hosted/controller/maintenance/UpgraderTest.java
@@ -35,6 +35,7 @@ import static com.yahoo.vespa.hosted.controller.api.integration.deployment.JobTy
import static com.yahoo.vespa.hosted.controller.api.integration.deployment.JobType.systemTest;
import static com.yahoo.vespa.hosted.controller.deployment.DeploymentTrigger.ChangesToCancel.ALL;
import static com.yahoo.vespa.hosted.controller.deployment.DeploymentTrigger.ChangesToCancel.PIN;
+import static com.yahoo.vespa.hosted.controller.deployment.DeploymentTrigger.ChangesToCancel.PLATFORM;
import static org.junit.Assert.assertEquals;
import static org.junit.Assert.assertFalse;
import static org.junit.Assert.assertTrue;
@@ -167,7 +168,6 @@ public class UpgraderTest {
// --- Failing application is repaired by changing the application, causing confidence to move above 'high' threshold
// Deploy application change
default0.submit(applicationPackage("default"));
- default0.triggerJobs().jobAborted(stagingTest);
default0.deploy();
tester.controllerTester().computeVersionStatus();
@@ -534,7 +534,7 @@ public class UpgraderTest {
}
@Test
- public void testBlockVersionChangeHalfwayThoughThenNewRevision() {
+ public void testBlockVersionChangeHalfwayThroughThenNewRevision() {
// Friday, 16:00
tester.at(Instant.parse("2017-09-29T16:00:00.00Z"));
@@ -542,7 +542,7 @@ public class UpgraderTest {
tester.controllerTester().upgradeSystem(version);
ApplicationPackage applicationPackage = new ApplicationPackageBuilder()
- // Block upgrades on weekends and ouside working hours
+ // Block upgrades on weekends and outside working hours
.blockChange(false, true, "mon-fri", "00-09,17-23", "UTC")
.blockChange(false, true, "sat-sun", "00-23", "UTC")
.region("us-west-1")
@@ -570,19 +570,20 @@ public class UpgraderTest {
// A new revision is submitted and starts rolling out.
app.submit(applicationPackage);
- // production-us-central-1 isn't triggered, as the revision + platform is the new change to roll out.
+ // production-us-central-1 is re-triggered with upgrade until revision catches up.
tester.triggerJobs();
- assertEquals(2, tester.jobs().active().size());
+ assertEquals(3, tester.jobs().active().size());
app.runJob(systemTest).runJob(stagingTest).runJob(productionUsWest1);
// us-central-1 has an older version, and needs a new staging test to begin.
- app.runJob(stagingTest);
+ app.runJob(stagingTest).triggerJobs().jobAborted(productionUsCentral1); // Retry will include revision.
tester.triggerJobs(); // Triggers us-central-1 before platform upgrade is cancelled.
- // A new version is also released, cancelling the upgrade, since it is failing on a now outdated version.
+ // A new version is also released, and someone cancels the upgrade, suspecting it is faulty.
tester.clock().advance(Duration.ofHours(17));
version = Version.fromString("6.4");
tester.controllerTester().upgradeSystem(version);
tester.upgrader().maintain();
+ tester.deploymentTrigger().cancelChange(app.instanceId(), PLATFORM);
// us-central-1 succeeds upgrade to 6.3, with the revision, but us-east-3 wants to proceed with only the revision change.
app.runJob(productionUsCentral1);
@@ -799,8 +800,10 @@ public class UpgraderTest {
app.instance().change().application().get().id().equals(applicationVersion));
// Deployment completes
- app.runJob(systemTest).runJob(stagingTest).runJob(productionUsWest1).runJob(productionUsEast3);
- assertTrue("All jobs consumed", tester.jobs().active().isEmpty());
+ app.runJob(systemTest).runJob(stagingTest)
+ .runJob(productionUsWest1)
+ .runJob(productionUsEast3);
+ assertEquals("All jobs consumed", List.of(), tester.jobs().active());
for (Deployment deployment : app.instance().deployments().values()) {
assertEquals(version, deployment.version());
diff --git a/controller-server/src/test/java/com/yahoo/vespa/hosted/controller/persistence/ApplicationSerializerTest.java b/controller-server/src/test/java/com/yahoo/vespa/hosted/controller/persistence/ApplicationSerializerTest.java
index b33f8f6f7e7..e509a199c82 100644
--- a/controller-server/src/test/java/com/yahoo/vespa/hosted/controller/persistence/ApplicationSerializerTest.java
+++ b/controller-server/src/test/java/com/yahoo/vespa/hosted/controller/persistence/ApplicationSerializerTest.java
@@ -42,6 +42,8 @@ import java.util.OptionalDouble;
import java.util.OptionalInt;
import java.util.OptionalLong;
import java.util.Set;
+import java.util.SortedSet;
+import java.util.TreeSet;
import static org.junit.Assert.assertEquals;
@@ -89,12 +91,14 @@ public class ApplicationSerializerTest {
Optional.of(Instant.ofEpochMilli(666)),
Optional.empty(),
Optional.of("best commit"),
- true);
+ true,
+ Optional.of("hash1"));
assertEquals("https://github/org/repo/tree/commit1", applicationVersion1.sourceUrl().get());
ApplicationVersion applicationVersion2 = ApplicationVersion
.from(new SourceRevision("repo1", "branch1", "commit1"), 32, "a@b",
Version.fromString("6.3.1"), Instant.ofEpochMilli(496));
+ SortedSet<ApplicationVersion> versions = new TreeSet<>(Set.of(applicationVersion2));
Instant activityAt = Instant.parse("2018-06-01T10:15:30.00Z");
deployments.add(new Deployment(zone1, applicationVersion1, Version.fromString("1.2.3"), Instant.ofEpochMilli(3),
DeploymentMetrics.none, DeploymentActivity.none, QuotaUsage.none, OptionalDouble.empty()));
@@ -120,13 +124,15 @@ public class ApplicationSerializerTest {
Map.of(JobType.systemTest, Instant.ofEpochMilli(333)),
List.of(AssignedRotation.fromStrings("foo", "default", "my-rotation", Set.of("us-west-1"))),
rotationStatus,
- Change.of(new Version("6.1"))),
+ Change.of(new Version("6.1")),
+ Optional.of(applicationVersion2)),
new Instance(id3,
List.of(),
Map.of(),
List.of(),
RotationStatus.EMPTY,
- Change.of(Version.fromString("6.7")).withPin()));
+ Change.of(Version.fromString("6.7")).withPin(),
+ Optional.empty()));
Application original = new Application(TenantAndApplicationId.from(id1),
Instant.now().truncatedTo(ChronoUnit.MILLIS),
@@ -140,6 +146,7 @@ public class ApplicationSerializerTest {
Set.of(publicKey, otherPublicKey),
projectId,
Optional.of(applicationVersion1),
+ versions,
instances);
Application serialized = APPLICATION_SERIALIZER.fromSlime(SlimeUtils.toJsonBytes(APPLICATION_SERIALIZER.toSlime(original)));
@@ -151,6 +158,10 @@ public class ApplicationSerializerTest {
assertEquals(original.latestVersion().get().buildTime(), serialized.latestVersion().get().buildTime());
assertEquals(original.latestVersion().get().sourceUrl(), serialized.latestVersion().get().sourceUrl());
assertEquals(original.latestVersion().get().commit(), serialized.latestVersion().get().commit());
+ assertEquals(original.latestVersion().get().bundleHash(), serialized.latestVersion().get().bundleHash());
+ assertEquals(original.versions(), serialized.versions());
+ assertEquals(original.versions(), serialized.versions());
+
assertEquals(original.deploymentSpec().xmlForm(), serialized.deploymentSpec().xmlForm());
assertEquals(original.validationOverrides().xmlForm(), serialized.validationOverrides().xmlForm());
@@ -182,6 +193,9 @@ public class ApplicationSerializerTest {
assertEquals(original.require(id1.instance()).change(), serialized.require(id1.instance()).change());
assertEquals(original.require(id3.instance()).change(), serialized.require(id3.instance()).change());
+ assertEquals(original.require(id1.instance()).latestDeployed(), serialized.require(id1.instance()).latestDeployed());
+ assertEquals(original.require(id3.instance()).latestDeployed(), serialized.require(id3.instance()).latestDeployed());
+
// Test metrics
assertEquals(original.metrics().queryServiceQuality(), serialized.metrics().queryServiceQuality(), Double.MIN_VALUE);
assertEquals(original.metrics().writeServiceQuality(), serialized.metrics().writeServiceQuality(), Double.MIN_VALUE);
diff --git a/controller-server/src/test/java/com/yahoo/vespa/hosted/controller/persistence/RunSerializerTest.java b/controller-server/src/test/java/com/yahoo/vespa/hosted/controller/persistence/RunSerializerTest.java
index eca2b17a5f1..f4f52b20325 100644
--- a/controller-server/src/test/java/com/yahoo/vespa/hosted/controller/persistence/RunSerializerTest.java
+++ b/controller-server/src/test/java/com/yahoo/vespa/hosted/controller/persistence/RunSerializerTest.java
@@ -91,7 +91,8 @@ public class RunSerializerTest {
Optional.of(Instant.ofEpochMilli(100)),
Optional.empty(),
Optional.empty(),
- true);
+ true,
+ Optional.empty());
assertEquals(applicationVersion, run.versions().targetApplication());
assertEquals(applicationVersion.authorEmail(), run.versions().targetApplication().authorEmail());
assertEquals(applicationVersion.buildTime(), run.versions().targetApplication().buildTime());
diff --git a/controller-server/src/test/java/com/yahoo/vespa/hosted/controller/persistence/testdata/run-status.json b/controller-server/src/test/java/com/yahoo/vespa/hosted/controller/persistence/testdata/run-status.json
index 7b9131a38dd..54cde2bacef 100644
--- a/controller-server/src/test/java/com/yahoo/vespa/hosted/controller/persistence/testdata/run-status.json
+++ b/controller-server/src/test/java/com/yahoo/vespa/hosted/controller/persistence/testdata/run-status.json
@@ -4,6 +4,7 @@
"type": "production-us-east-3",
"number": 112358,
"start": 1196676930000,
+ "sleepUntil": 1196676930100,
"status": "running",
"lastTestRecord": 3,
"lastVespaLogTimestamp": 1196676930000432,
diff --git a/controller-server/src/test/java/com/yahoo/vespa/hosted/controller/restapi/ControllerContainerCloudTest.java b/controller-server/src/test/java/com/yahoo/vespa/hosted/controller/restapi/ControllerContainerCloudTest.java
index a6d061e7c80..2fd8026319b 100644
--- a/controller-server/src/test/java/com/yahoo/vespa/hosted/controller/restapi/ControllerContainerCloudTest.java
+++ b/controller-server/src/test/java/com/yahoo/vespa/hosted/controller/restapi/ControllerContainerCloudTest.java
@@ -92,15 +92,7 @@ public class ControllerContainerCloudTest extends ControllerContainerTest {
Request request = new Request("http://localhost:8080" + path, data, method, principal);
request.getAttributes().put(SecurityContext.ATTRIBUTE_NAME, new SecurityContext(principal, roles));
if (user != null) {
- Map<String, String> userAttributes = new HashMap<>();
- userAttributes.put("email", user.email());
- if (user.name() != null)
- userAttributes.put("name", user.name());
- if (user.nickname() != null)
- userAttributes.put("nickname", user.nickname());
- if (user.picture() != null)
- userAttributes.put("picture", user.picture());
- request.getAttributes().put(User.ATTRIBUTE_NAME, Map.copyOf(userAttributes));
+ request.getAttributes().put(User.ATTRIBUTE_NAME, user);
}
request.getHeaders().put("Content-Type", contentType);
return request;
diff --git a/controller-server/src/test/java/com/yahoo/vespa/hosted/controller/restapi/application/ApplicationApiCloudTest.java b/controller-server/src/test/java/com/yahoo/vespa/hosted/controller/restapi/application/ApplicationApiCloudTest.java
index a4de6ab7700..92055c85a53 100644
--- a/controller-server/src/test/java/com/yahoo/vespa/hosted/controller/restapi/application/ApplicationApiCloudTest.java
+++ b/controller-server/src/test/java/com/yahoo/vespa/hosted/controller/restapi/application/ApplicationApiCloudTest.java
@@ -238,7 +238,7 @@ public class ApplicationApiCloudTest extends ControllerContainerCloudTest {
@Test
public void create_application_on_deploy() {
var application = ApplicationName.from("unique");
- var applicationPackage = new ApplicationPackageBuilder().build();
+ var applicationPackage = new ApplicationPackageBuilder().withoutAthenzIdentity().build();
assertTrue(tester.controller().applications().getApplication(TenantAndApplicationId.from(tenantName, application)).isEmpty());
@@ -256,6 +256,7 @@ public class ApplicationApiCloudTest extends ControllerContainerCloudTest {
var application = ApplicationName.from("unique");
var applicationPackage = new ApplicationPackageBuilder()
.trustDefaultCertificate()
+ .withoutAthenzIdentity()
.build();
assertTrue(tester.controller().applications().getApplication(TenantAndApplicationId.from(tenantName, application)).isEmpty());
@@ -273,6 +274,7 @@ public class ApplicationApiCloudTest extends ControllerContainerCloudTest {
private ApplicationPackageBuilder prodBuilder() {
return new ApplicationPackageBuilder()
+ .withoutAthenzIdentity()
.instances("default")
.region("aws-us-east-1c");
}
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 8eaa190e9fa..516911b3c7b 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
@@ -26,8 +26,6 @@ import com.yahoo.vespa.athenz.api.AthenzPrincipal;
import com.yahoo.vespa.athenz.api.AthenzUser;
import com.yahoo.vespa.athenz.api.OktaAccessToken;
import com.yahoo.vespa.athenz.api.OktaIdentityToken;
-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;
@@ -126,6 +124,7 @@ public class ApplicationApiTest extends ControllerContainerTest {
private static final String accessDenied = "{\n \"code\" : 403,\n \"message\" : \"Access denied\"\n}";
private static final ApplicationPackage applicationPackageDefault = new ApplicationPackageBuilder()
+ .withoutAthenzIdentity()
.instances("default")
.globalServiceId("foo")
.region("us-central-1")
@@ -135,6 +134,7 @@ public class ApplicationApiTest extends ControllerContainerTest {
.build();
private static final ApplicationPackage applicationPackageInstance1 = new ApplicationPackageBuilder()
+ .withoutAthenzIdentity()
.instances("instance1")
.globalServiceId("foo")
.region("us-central-1")
@@ -338,6 +338,7 @@ public class ApplicationApiTest extends ControllerContainerTest {
app1.runJob(JobType.systemTest).runJob(JobType.stagingTest).runJob(JobType.productionUsCentral1);
ApplicationPackage applicationPackage = new ApplicationPackageBuilder()
+ .withoutAthenzIdentity()
.instances("instance1")
.globalServiceId("foo")
.region("us-west-1")
@@ -448,7 +449,6 @@ public class ApplicationApiTest extends ControllerContainerTest {
deploymentTester.upgrader().overrideConfidence(Version.fromString("6.1"), VespaVersion.Confidence.broken);
deploymentTester.controllerTester().computeVersionStatus();
setDeploymentMaintainedInfo();
- setZoneInRotation("rotation-fqdn-1", ZoneId.from("prod", "us-central-1"));
// GET tenant application deployments
tester.assertResponse(request("/application/v4/tenant/tenant1/application/application1/instance/instance1", GET)
@@ -817,6 +817,7 @@ public class ApplicationApiTest extends ControllerContainerTest {
// Sixth attempt has a multi-instance deployment spec, and is accepted.
ApplicationPackage multiInstanceSpec = new ApplicationPackageBuilder()
+ .withoutAthenzIdentity()
.instances("instance1,instance2")
.region("us-central-1")
.parallel("us-west-1", "us-east-3")
@@ -949,7 +950,6 @@ public class ApplicationApiTest extends ControllerContainerTest {
404);
// GET global rotation status
- setZoneInRotation("rotation-fqdn-1", ZoneId.from("prod", "us-west-1"));
tester.assertResponse(request("/application/v4/tenant/tenant1/application/application1/instance/instance1/environment/prod/region/us-west-1/global-rotation", GET)
.userIdentity(USER_ID),
new File("global-rotation.json"));
@@ -1001,10 +1001,6 @@ public class ApplicationApiTest extends ControllerContainerTest {
var app = deploymentTester.newDeploymentContext("tenant1", "application1", "instance1");
app.submit(applicationPackage).deploy();
- setZoneInRotation("rotation-fqdn-2", ZoneId.from("prod", "us-west-1"));
- setZoneInRotation("rotation-fqdn-2", ZoneId.from("prod", "us-east-3"));
- setZoneInRotation("rotation-fqdn-1", ZoneId.from("prod", "eu-west-1"));
-
// GET global rotation status without specifying endpointId fails
tester.assertResponse(request("/application/v4/tenant/tenant1/application/application1/instance/instance1/environment/prod/region/us-west-1/global-rotation", GET)
.userIdentity(USER_ID),
@@ -1528,7 +1524,7 @@ public class ApplicationApiTest extends ControllerContainerTest {
var app = deploymentTester.newDeploymentContext(createTenantAndApplication());
var zone = ZoneId.from(Environment.prod, RegionName.from("us-west-1"));
deploymentTester.controllerTester().zoneRegistry().setRoutingMethod(ZoneApiMock.from(zone),
- List.of(RoutingMethod.exclusive, RoutingMethod.shared));
+ RoutingMethod.exclusive);
ApplicationPackage applicationPackage = new ApplicationPackageBuilder()
.athenzIdentity(com.yahoo.config.provision.AthenzDomain.from("domain"), AthenzService.from("service"))
.instances("instance1")
@@ -1547,15 +1543,6 @@ public class ApplicationApiTest extends ControllerContainerTest {
.userIdentity(USER_ID),
new File("deployment-with-routing-policy.json"));
- // GET deployment including legacy endpoints
- tester.assertResponse(request("/application/v4/tenant/tenant1/application/application1/environment/prod/region/us-west-1/instance/instance1", GET)
- .userIdentity(USER_ID)
- .properties(Map.of("includeLegacyEndpoints", "true")),
- new File("deployment-with-routing-policy-legacy.json"));
-
- // Hide shared endpoints
- ((InMemoryFlagSource) tester.controller().flagSource()).withBooleanFlag(Flags.HIDE_SHARED_ROUTING_ENDPOINT.id(), true);
-
// GET deployment
tester.assertResponse(request("/application/v4/tenant/tenant1/application/application1/environment/prod/region/us-west-1/instance/instance1", GET)
.userIdentity(USER_ID),
@@ -1566,8 +1553,7 @@ public class ApplicationApiTest extends ControllerContainerTest {
public void support_access() {
var app = deploymentTester.newDeploymentContext(createTenantAndApplication());
var zone = ZoneId.from(Environment.prod, RegionName.from("us-west-1"));
- deploymentTester.controllerTester().zoneRegistry().setRoutingMethod(ZoneApiMock.from(zone),
- List.of(RoutingMethod.exclusive, RoutingMethod.shared));
+ deploymentTester.controllerTester().zoneRegistry().setRoutingMethod(ZoneApiMock.from(zone), RoutingMethod.exclusive);
addUserToHostedOperatorRole(HostedAthenzIdentities.from(HOSTED_VESPA_OPERATOR));
ApplicationPackage applicationPackage = new ApplicationPackageBuilder()
.athenzIdentity(com.yahoo.config.provision.AthenzDomain.from("domain"), AthenzService.from("service"))
@@ -1817,11 +1803,6 @@ public class ApplicationApiTest extends ControllerContainerTest {
}
}
- private void setZoneInRotation(String rotationName, ZoneId zone) {
- tester.serviceRegistry().globalRoutingServiceMock().setStatus(rotationName, zone, com.yahoo.vespa.hosted.controller.api.integration.routing.RotationStatus.IN);
- //new RotationStatusUpdater(tester.controller(), Duration.ofDays(1)).run();
- }
-
private void updateContactInformation() {
Contact contact = new Contact(URI.create("www.contacts.tld/1234"),
URI.create("www.properties.tld/1234"),
diff --git a/controller-server/src/test/java/com/yahoo/vespa/hosted/controller/restapi/application/JobControllerApiHandlerHelperTest.java b/controller-server/src/test/java/com/yahoo/vespa/hosted/controller/restapi/application/JobControllerApiHandlerHelperTest.java
index 2ae755ac8fe..4935ab22586 100644
--- a/controller-server/src/test/java/com/yahoo/vespa/hosted/controller/restapi/application/JobControllerApiHandlerHelperTest.java
+++ b/controller-server/src/test/java/com/yahoo/vespa/hosted/controller/restapi/application/JobControllerApiHandlerHelperTest.java
@@ -192,7 +192,7 @@ public class JobControllerApiHandlerHelperTest {
private void compare(HttpResponse response, String expected) throws IOException {
ByteArrayOutputStream baos = new ByteArrayOutputStream();
response.render(baos);
- JsonTestHelper.assertJsonEquals(expected, baos.toString());
+ JsonTestHelper.assertJsonEquals(baos.toString(), expected);
}
private void assertResponse(HttpResponse response, String fileName) {
diff --git a/controller-server/src/test/java/com/yahoo/vespa/hosted/controller/restapi/application/MultipartParserTest.java b/controller-server/src/test/java/com/yahoo/vespa/hosted/controller/restapi/application/MultipartParserTest.java
index 5bf22ede19d..2c81b1a7fd8 100644
--- a/controller-server/src/test/java/com/yahoo/vespa/hosted/controller/restapi/application/MultipartParserTest.java
+++ b/controller-server/src/test/java/com/yahoo/vespa/hosted/controller/restapi/application/MultipartParserTest.java
@@ -1,7 +1,6 @@
// Copyright Yahoo. Licensed under the terms of the Apache 2.0 license. See LICENSE in the project root.
package com.yahoo.vespa.hosted.controller.restapi.application;
-import com.google.inject.Key;
import com.yahoo.container.jdisc.HttpRequest;
import com.yahoo.jdisc.Container;
import com.yahoo.jdisc.Request;
@@ -72,9 +71,6 @@ public class MultipartParserTest {
public RequestHandler resolveHandler(Request request) { return null; }
@Override
- public <T> T getInstance(Key<T> key) { return null; }
-
- @Override
public <T> T getInstance(Class<T> aClass) { return null; }
@Override
diff --git a/controller-server/src/test/java/com/yahoo/vespa/hosted/controller/restapi/application/responses/deployment-cloud.json b/controller-server/src/test/java/com/yahoo/vespa/hosted/controller/restapi/application/responses/deployment-cloud.json
index a214969485d..fd4093ca332 100644
--- a/controller-server/src/test/java/com/yahoo/vespa/hosted/controller/restapi/application/responses/deployment-cloud.json
+++ b/controller-server/src/test/java/com/yahoo/vespa/hosted/controller/restapi/application/responses/deployment-cloud.json
@@ -37,7 +37,6 @@
},
"status": "complete",
"quota": "(ignore)",
- "archiveUri": "s3://bucketName/scoober/",
"activity": {},
"metrics": {
"queriesPerSecond": 0.0,
diff --git a/controller-server/src/test/java/com/yahoo/vespa/hosted/controller/restapi/application/responses/deployment-overview-2.json b/controller-server/src/test/java/com/yahoo/vespa/hosted/controller/restapi/application/responses/deployment-overview-2.json
index b8c48eb3d0c..6223cbbb2b9 100644
--- a/controller-server/src/test/java/com/yahoo/vespa/hosted/controller/restapi/application/responses/deployment-overview-2.json
+++ b/controller-server/src/test/java/com/yahoo/vespa/hosted/controller/restapi/application/responses/deployment-overview-2.json
@@ -1223,5 +1223,40 @@
}
]
}
+ ],
+ "builds": [
+ {
+ "hash": "1.0.3-commit1",
+ "build": 3,
+ "source": {
+ "gitRepository": "repository1",
+ "gitBranch": "master",
+ "gitCommit": "commit1"
+ },
+ "sourceUrl": "repository1/tree/commit1",
+ "commit": "commit1"
+ },
+ {
+ "hash": "1.0.2-commit1",
+ "build": 2,
+ "source": {
+ "gitRepository": "repository1",
+ "gitBranch": "master",
+ "gitCommit": "commit1"
+ },
+ "sourceUrl": "repository1/tree/commit1",
+ "commit": "commit1"
+ },
+ {
+ "hash": "1.0.1-commit1",
+ "build": 1,
+ "source": {
+ "gitRepository": "repository1",
+ "gitBranch": "master",
+ "gitCommit": "commit1"
+ },
+ "sourceUrl": "repository1/tree/commit1",
+ "commit": "commit1"
+ }
]
}
diff --git a/controller-server/src/test/java/com/yahoo/vespa/hosted/controller/restapi/application/responses/deployment-overview.json b/controller-server/src/test/java/com/yahoo/vespa/hosted/controller/restapi/application/responses/deployment-overview.json
index abe3d4100d9..e3fb8eec9c4 100644
--- a/controller-server/src/test/java/com/yahoo/vespa/hosted/controller/restapi/application/responses/deployment-overview.json
+++ b/controller-server/src/test/java/com/yahoo/vespa/hosted/controller/restapi/application/responses/deployment-overview.json
@@ -21,7 +21,7 @@
"platform": {
"platform": "6.1.0",
"at": "(ignore)",
- "upgrade": false,
+ "upgrade": true,
"blockers": []
},
"application": {
@@ -536,7 +536,7 @@
"platform": {
"platform": "6.1.0",
"at": "(ignore)",
- "upgrade": false,
+ "upgrade": true,
"blockers": []
},
"application": {
@@ -547,7 +547,7 @@
"commit": "commit1"
},
"at": 1000,
- "upgrade": false,
+ "upgrade": true,
"blockers": []
}
}
@@ -630,6 +630,52 @@
],
"runs": []
}
+ ],
+ "builds": [
+ {
+ "hash": "1.0.4-commit1",
+ "build": 4,
+ "source": {
+ "gitRepository": "repository1",
+ "gitBranch": "master",
+ "gitCommit": "commit1"
+ },
+ "sourceUrl": "repository1/tree/commit1",
+ "commit": "commit1"
+ },
+ {
+ "hash": "1.0.3-commit1",
+ "build": 3,
+ "source": {
+ "gitRepository": "repository1",
+ "gitBranch": "master",
+ "gitCommit": "commit1"
+ },
+ "sourceUrl": "repository1/tree/commit1",
+ "commit": "commit1"
+ },
+ {
+ "hash": "1.0.2-commit1",
+ "build": 2,
+ "source": {
+ "gitRepository": "repository1",
+ "gitBranch": "master",
+ "gitCommit": "commit1"
+ },
+ "sourceUrl": "repository1/tree/commit1",
+ "commit": "commit1"
+ },
+ {
+ "hash": "1.0.1-commit1",
+ "build": 1,
+ "source": {
+ "gitRepository": "repository1",
+ "gitBranch": "master",
+ "gitCommit": "commit1"
+ },
+ "sourceUrl": "repository1/tree/commit1",
+ "commit": "commit1"
+ }
]
}
diff --git a/controller-server/src/test/java/com/yahoo/vespa/hosted/controller/restapi/application/responses/deployment-with-routing-policy-legacy.json b/controller-server/src/test/java/com/yahoo/vespa/hosted/controller/restapi/application/responses/deployment-with-routing-policy-legacy.json
deleted file mode 100644
index eb508b2459e..00000000000
--- a/controller-server/src/test/java/com/yahoo/vespa/hosted/controller/restapi/application/responses/deployment-with-routing-policy-legacy.json
+++ /dev/null
@@ -1,72 +0,0 @@
-{
- "tenant": "tenant1",
- "application": "application1",
- "instance": "instance1",
- "environment": "prod",
- "region": "us-west-1",
- "endpoints": [
- {
- "cluster": "default",
- "tls": true,
- "url": "https://instance1.application1.tenant1.us-west-1.vespa.oath.cloud/",
- "scope": "zone",
- "routingMethod": "exclusive",
- "legacy": false
- },
- {
- "cluster": "default",
- "tls": true,
- "url": "https://instance1--application1--tenant1.us-west-1.vespa.oath.cloud:4443/",
- "scope": "zone",
- "routingMethod": "shared",
- "legacy": false
- },
- {
- "cluster": "default",
- "tls": false,
- "url": "http://instance1.application1.tenant1.us-west-1.prod.vespa.yahooapis.com:4080/",
- "scope": "zone",
- "routingMethod": "shared",
- "legacy": true
- },
- {
- "cluster": "default",
- "tls": true,
- "url": "https://instance1--application1--tenant1.us-west-1.prod.vespa.yahooapis.com:4443/",
- "scope": "zone",
- "routingMethod": "shared",
- "legacy": true
- }
- ],
- "clusters": "http://localhost:8080/application/v4/tenant/tenant1/application/application1/instance/instance1/environment/prod/region/us-west-1/clusters",
- "nodes": "http://localhost:8080/zone/v2/prod/us-west-1/nodes/v2/node/?recursive=true&application=tenant1.application1.instance1",
- "yamasUrl": "http://monitoring-system.test/?environment=prod&region=us-west-1&application=tenant1.application1.instance1",
- "version": "6.1.0",
- "revision": "1.0.1-commit1",
- "deployTimeEpochMs": "(ignore)",
- "screwdriverId": "1000",
- "gitRepository": "repository1",
- "gitBranch": "master",
- "gitCommit": "commit1",
- "applicationVersion": {
- "hash": "1.0.1-commit1",
- "build": 1,
- "source": {
- "gitRepository": "repository1",
- "gitBranch": "master",
- "gitCommit": "commit1"
- },
- "sourceUrl": "repository1/tree/commit1",
- "commit": "commit1"
- },
- "status": "complete",
- "quota": "(ignore)",
- "activity": {},
- "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-with-routing-policy.json b/controller-server/src/test/java/com/yahoo/vespa/hosted/controller/restapi/application/responses/deployment-with-routing-policy.json
index 97ac87fb5a0..4457bede34e 100644
--- 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
@@ -12,14 +12,6 @@
"scope": "zone",
"routingMethod": "exclusive",
"legacy": false
- },
- {
- "cluster": "default",
- "tls": true,
- "url": "https://instance1--application1--tenant1.us-west-1.vespa.oath.cloud:4443/",
- "scope": "zone",
- "routingMethod": "shared",
- "legacy": false
}
],
"clusters":"http://localhost:8080/application/v4/tenant/tenant1/application/application1/instance/instance1/environment/prod/region/us-west-1/clusters",
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 ab2a3bf945c..621617f1b1c 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
@@ -8,17 +8,17 @@
{
"cluster": "default",
"tls": true,
- "url": "https://instance1--application1--tenant1.us-central-1.vespa.oath.cloud:4443/",
+ "url": "https://instance1.application1.tenant1.us-central-1.vespa.oath.cloud/",
"scope": "zone",
- "routingMethod": "shared",
+ "routingMethod": "sharedLayer4",
"legacy": false
},
{
"cluster": "foo",
"tls": true,
- "url": "https://instance1--application1--tenant1.global.vespa.oath.cloud:4443/",
+ "url": "https://instance1.application1.tenant1.global.vespa.oath.cloud/",
"scope": "global",
- "routingMethod": "shared",
+ "routingMethod": "sharedLayer4",
"legacy": false
},
{
diff --git a/controller-server/src/test/java/com/yahoo/vespa/hosted/controller/restapi/application/responses/dev-us-east-1-log-second-part.json b/controller-server/src/test/java/com/yahoo/vespa/hosted/controller/restapi/application/responses/dev-us-east-1-log-second-part.json
index 45df6aad67c..175c45eb2cd 100644
--- a/controller-server/src/test/java/com/yahoo/vespa/hosted/controller/restapi/application/responses/dev-us-east-1-log-second-part.json
+++ b/controller-server/src/test/java/com/yahoo/vespa/hosted/controller/restapi/application/responses/dev-us-east-1-log-second-part.json
@@ -11,7 +11,7 @@
{
"at": 0,
"type": "info",
- "message": " |-- https://application--tenant.us-east-1.dev.vespa.oath.cloud:4443/ (cluster 'default')"
+ "message": " |-- https://application.tenant.us-east-1.dev.vespa.oath.cloud/ (cluster 'default')"
},
{
"at": 0,
diff --git a/controller-server/src/test/java/com/yahoo/vespa/hosted/controller/restapi/application/responses/dev-us-east-1.json b/controller-server/src/test/java/com/yahoo/vespa/hosted/controller/restapi/application/responses/dev-us-east-1.json
index f2f8e14f093..2ca520c0122 100644
--- a/controller-server/src/test/java/com/yahoo/vespa/hosted/controller/restapi/application/responses/dev-us-east-1.json
+++ b/controller-server/src/test/java/com/yahoo/vespa/hosted/controller/restapi/application/responses/dev-us-east-1.json
@@ -8,9 +8,9 @@
{
"cluster": "default",
"tls": true,
- "url": "https://instance1--application1--tenant1.us-east-1.dev.vespa.oath.cloud:4443/",
+ "url": "https://instance1.application1.tenant1.us-east-1.dev.vespa.oath.cloud/",
"scope": "zone",
- "routingMethod": "shared",
+ "routingMethod": "sharedLayer4",
"legacy": false
}
],
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 62ad3a2db7e..d9ec8e4dfef 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
@@ -11,17 +11,17 @@
{
"cluster": "default",
"tls": true,
- "url": "https://instance1--application1--tenant1.us-central-1.vespa.oath.cloud:4443/",
+ "url": "https://instance1.application1.tenant1.us-central-1.vespa.oath.cloud/",
"scope": "zone",
- "routingMethod": "shared",
+ "routingMethod": "sharedLayer4",
"legacy": false
},
{
"cluster": "foo",
"tls": true,
- "url": "https://instance1--application1--tenant1.global.vespa.oath.cloud:4443/",
+ "url": "https://instance1.application1.tenant1.global.vespa.oath.cloud/",
"scope": "global",
- "routingMethod": "shared",
+ "routingMethod": "sharedLayer4",
"legacy": false
},
{
@@ -33,7 +33,7 @@
"legacy": false
}
],
- "clusters":"http://localhost:8080/application/v4/tenant/tenant1/application/application1/instance/instance1/environment/prod/region/us-central-1/clusters",
+ "clusters": "http://localhost:8080/application/v4/tenant/tenant1/application/application1/instance/instance1/environment/prod/region/us-central-1/clusters",
"nodes": "http://localhost:8080/zone/v2/prod/us-central-1/nodes/v2/node/?recursive=true&application=tenant1.application1.instance1",
"yamasUrl": "http://monitoring-system.test/?environment=prod&region=us-central-1&application=tenant1.application1.instance1",
"version": "(ignore)",
diff --git a/controller-server/src/test/java/com/yahoo/vespa/hosted/controller/restapi/application/responses/staging-test-log.json b/controller-server/src/test/java/com/yahoo/vespa/hosted/controller/restapi/application/responses/staging-test-log.json
index 0525f059dd0..6b1d48f4a08 100644
--- a/controller-server/src/test/java/com/yahoo/vespa/hosted/controller/restapi/application/responses/staging-test-log.json
+++ b/controller-server/src/test/java/com/yahoo/vespa/hosted/controller/restapi/application/responses/staging-test-log.json
@@ -117,16 +117,26 @@
{
"at": 14503000,
"type": "info",
- "message": "host-tenant:application:default-staging.us-east-3: unorchestrated"
+ "message": "Waiting for convergence of 1 services across 1 nodes"
},
{
"at": 14503000,
"type": "info",
+ "message": "1 application services upgrading"
+ },
+ {
+ "at": 14503000,
+ "type": "debug",
+ "message": "host-tenant:application:default-staging.us-east-3: unorchestrated"
+ },
+ {
+ "at": 14503000,
+ "type": "debug",
"message": "--- platform vespa/vespa:6.1"
},
{
"at": 14503000,
- "type": "info",
+ "type": "debug",
"message": "--- container on port 43 has config generation 1, wanted is 2"
},
{
@@ -150,7 +160,7 @@
}
]
},
- "lastId": 27,
+ "lastId": 29,
"steps": {
"deployTester": {
"status": "succeeded",
diff --git a/controller-server/src/test/java/com/yahoo/vespa/hosted/controller/restapi/application/responses/system-test-details.json b/controller-server/src/test/java/com/yahoo/vespa/hosted/controller/restapi/application/responses/system-test-details.json
index 7ee3952a8b5..377b8c6ed69 100644
--- a/controller-server/src/test/java/com/yahoo/vespa/hosted/controller/restapi/application/responses/system-test-details.json
+++ b/controller-server/src/test/java/com/yahoo/vespa/hosted/controller/restapi/application/responses/system-test-details.json
@@ -137,91 +137,151 @@
{
"at": "(ignore)",
"type": "info",
- "message": "host-tenant1:application1:instance1-test.us-east-1: unorchestrated"
+ "message": "Waiting for convergence of 1 services across 1 nodes"
},
{
"at": "(ignore)",
"type": "info",
+ "message": "1 application services upgrading"
+ },
+ {
+ "at": "(ignore)",
+ "type": "debug",
+ "message": "host-tenant1:application1:instance1-test.us-east-1: unorchestrated"
+ },
+ {
+ "at": "(ignore)",
+ "type": "debug",
"message": "--- platform vespa/vespa:6.1"
},
{
"at": "(ignore)",
- "type": "info",
+ "type": "debug",
"message": "--- container on port 43 has config generation 1, wanted is 2"
},
{
"at": "(ignore)",
"type": "info",
- "message": "host-tenant1:application1:instance1-test.us-east-1: unorchestrated"
+ "message": "Waiting for convergence of 1 services across 1 nodes"
},
{
"at": "(ignore)",
"type": "info",
+ "message": "1 application services upgrading"
+ },
+ {
+ "at": "(ignore)",
+ "type": "debug",
+ "message": "host-tenant1:application1:instance1-test.us-east-1: unorchestrated"
+ },
+ {
+ "at": "(ignore)",
+ "type": "debug",
"message": "--- platform vespa/vespa:6.1"
},
{
"at": "(ignore)",
- "type": "info",
+ "type": "debug",
"message": "--- container on port 43 has config generation 1, wanted is 2"
},
{
"at": "(ignore)",
"type": "info",
- "message": "host-tenant1:application1:instance1-test.us-east-1: unorchestrated"
+ "message": "Waiting for convergence of 1 services across 1 nodes"
},
{
"at": "(ignore)",
"type": "info",
+ "message": "1 application services upgrading"
+ },
+ {
+ "at": "(ignore)",
+ "type": "debug",
+ "message": "host-tenant1:application1:instance1-test.us-east-1: unorchestrated"
+ },
+ {
+ "at": "(ignore)",
+ "type": "debug",
"message": "--- platform vespa/vespa:6.1"
},
{
"at": "(ignore)",
- "type": "info",
+ "type": "debug",
"message": "--- container on port 43 has config generation 1, wanted is 2"
},
{
"at": "(ignore)",
"type": "info",
- "message": "host-tenant1:application1:instance1-test.us-east-1: unorchestrated"
+ "message": "Waiting for convergence of 1 services across 1 nodes"
},
{
"at": "(ignore)",
"type": "info",
+ "message": "1 application services upgrading"
+ },
+ {
+ "at": "(ignore)",
+ "type": "debug",
+ "message": "host-tenant1:application1:instance1-test.us-east-1: unorchestrated"
+ },
+ {
+ "at": "(ignore)",
+ "type": "debug",
"message": "--- platform vespa/vespa:6.1"
},
{
"at": "(ignore)",
- "type": "info",
+ "type": "debug",
"message": "--- container on port 43 has config generation 1, wanted is 2"
},
{
"at": "(ignore)",
"type": "info",
- "message": "host-tenant1:application1:instance1-test.us-east-1: unorchestrated"
+ "message": "Waiting for convergence of 1 services across 1 nodes"
},
{
"at": "(ignore)",
"type": "info",
+ "message": "1 application services upgrading"
+ },
+ {
+ "at": "(ignore)",
+ "type": "debug",
+ "message": "host-tenant1:application1:instance1-test.us-east-1: unorchestrated"
+ },
+ {
+ "at": "(ignore)",
+ "type": "debug",
"message": "--- platform vespa/vespa:6.1"
},
{
"at": "(ignore)",
- "type": "info",
+ "type": "debug",
"message": "--- container on port 43 has config generation 1, wanted is 2"
},
{
"at": "(ignore)",
"type": "info",
- "message": "host-tenant1:application1:instance1-test.us-east-1: unorchestrated"
+ "message": "Waiting for convergence of 1 services across 1 nodes"
},
{
"at": "(ignore)",
"type": "info",
+ "message": "1 application services upgrading"
+ },
+ {
+ "at": "(ignore)",
+ "type": "debug",
+ "message": "host-tenant1:application1:instance1-test.us-east-1: unorchestrated"
+ },
+ {
+ "at": "(ignore)",
+ "type": "debug",
"message": "--- platform vespa/vespa:6.1"
},
{
"at": "(ignore)",
- "type": "info",
+ "type": "debug",
"message": "--- container on port 43 has config generation 1, wanted is 2"
},
{
@@ -237,7 +297,7 @@
{
"at": "(ignore)",
"type": "info",
- "message": " |-- https://instance1--application1--tenant1.us-east-1.test.vespa.oath.cloud:4443/ (cluster 'default')"
+ "message": " |-- https://instance1.application1.tenant1.us-east-1.test.vespa.oath.cloud/ (cluster 'default')"
},
{
"at": "(ignore)",
@@ -264,7 +324,7 @@
{
"at": "(ignore)",
"type": "info",
- "message": " |-- https://instance1--application1--tenant1.us-east-1.test.vespa.oath.cloud:4443/ (cluster 'default')"
+ "message": " |-- https://instance1.application1.tenant1.us-east-1.test.vespa.oath.cloud/ (cluster 'default')"
},
{
"at": "(ignore)",
@@ -294,7 +354,7 @@
}
]
},
- "lastId": 54,
+ "lastId": 66,
"steps": {
"deployTester": {
"status": "succeeded",
diff --git a/controller-server/src/test/java/com/yahoo/vespa/hosted/controller/restapi/application/responses/system-test-log.json b/controller-server/src/test/java/com/yahoo/vespa/hosted/controller/restapi/application/responses/system-test-log.json
index 7f59eaf75c2..66173ec4976 100644
--- a/controller-server/src/test/java/com/yahoo/vespa/hosted/controller/restapi/application/responses/system-test-log.json
+++ b/controller-server/src/test/java/com/yahoo/vespa/hosted/controller/restapi/application/responses/system-test-log.json
@@ -132,91 +132,151 @@
{
"at": 0,
"type": "info",
- "message": "host-tenant:application:default-test.us-east-1: unorchestrated"
+ "message": "Waiting for convergence of 1 services across 1 nodes"
},
{
"at": 0,
"type": "info",
+ "message": "1 application services upgrading"
+ },
+ {
+ "at": 0,
+ "type": "debug",
+ "message": "host-tenant:application:default-test.us-east-1: unorchestrated"
+ },
+ {
+ "at": 0,
+ "type": "debug",
"message": "--- platform vespa/vespa:6.1"
},
{
"at": 0,
- "type": "info",
+ "type": "debug",
"message": "--- container on port 43 has config generation 1, wanted is 2"
},
{
"at": 0,
"type": "info",
- "message": "host-tenant:application:default-test.us-east-1: unorchestrated"
+ "message": "Waiting for convergence of 1 services across 1 nodes"
},
{
"at": 0,
"type": "info",
+ "message": "1 application services upgrading"
+ },
+ {
+ "at": 0,
+ "type": "debug",
+ "message": "host-tenant:application:default-test.us-east-1: unorchestrated"
+ },
+ {
+ "at": 0,
+ "type": "debug",
"message": "--- platform vespa/vespa:6.1"
},
{
"at": 0,
- "type": "info",
+ "type": "debug",
"message": "--- container on port 43 has config generation 1, wanted is 2"
},
{
"at": 0,
"type": "info",
- "message": "host-tenant:application:default-test.us-east-1: unorchestrated"
+ "message": "Waiting for convergence of 1 services across 1 nodes"
},
{
"at": 0,
"type": "info",
+ "message": "1 application services upgrading"
+ },
+ {
+ "at": 0,
+ "type": "debug",
+ "message": "host-tenant:application:default-test.us-east-1: unorchestrated"
+ },
+ {
+ "at": 0,
+ "type": "debug",
"message": "--- platform vespa/vespa:6.1"
},
{
"at": 0,
- "type": "info",
+ "type": "debug",
"message": "--- container on port 43 has config generation 1, wanted is 2"
},
{
"at": 0,
"type": "info",
- "message": "host-tenant:application:default-test.us-east-1: unorchestrated"
+ "message": "Waiting for convergence of 1 services across 1 nodes"
},
{
"at": 0,
"type": "info",
+ "message": "1 application services upgrading"
+ },
+ {
+ "at": 0,
+ "type": "debug",
+ "message": "host-tenant:application:default-test.us-east-1: unorchestrated"
+ },
+ {
+ "at": 0,
+ "type": "debug",
"message": "--- platform vespa/vespa:6.1"
},
{
"at": 0,
- "type": "info",
+ "type": "debug",
"message": "--- container on port 43 has config generation 1, wanted is 2"
},
{
"at": 0,
"type": "info",
- "message": "host-tenant:application:default-test.us-east-1: unorchestrated"
+ "message": "Waiting for convergence of 1 services across 1 nodes"
},
{
"at": 0,
"type": "info",
+ "message": "1 application services upgrading"
+ },
+ {
+ "at": 0,
+ "type": "debug",
+ "message": "host-tenant:application:default-test.us-east-1: unorchestrated"
+ },
+ {
+ "at": 0,
+ "type": "debug",
"message": "--- platform vespa/vespa:6.1"
},
{
"at": 0,
- "type": "info",
+ "type": "debug",
"message": "--- container on port 43 has config generation 1, wanted is 2"
},
{
"at": 0,
"type": "info",
- "message": "host-tenant:application:default-test.us-east-1: unorchestrated"
+ "message": "Waiting for convergence of 1 services across 1 nodes"
},
{
"at": 0,
"type": "info",
+ "message": "1 application services upgrading"
+ },
+ {
+ "at": 0,
+ "type": "debug",
+ "message": "host-tenant:application:default-test.us-east-1: unorchestrated"
+ },
+ {
+ "at": 0,
+ "type": "debug",
"message": "--- platform vespa/vespa:6.1"
},
{
"at": 0,
- "type": "info",
+ "type": "debug",
"message": "--- container on port 43 has config generation 1, wanted is 2"
},
{
@@ -232,7 +292,7 @@
{
"at": 0,
"type": "info",
- "message": " |-- https://application--tenant.us-east-1.test.vespa.oath.cloud:4443/ (cluster 'default')"
+ "message": " |-- https://application.tenant.us-east-1.test.vespa.oath.cloud/ (cluster 'default')"
},
{
"at": 0,
@@ -259,7 +319,7 @@
{
"at": 0,
"type": "info",
- "message": " |-- https://application--tenant.us-east-1.test.vespa.oath.cloud:4443/ (cluster 'default')"
+ "message": " |-- https://application.tenant.us-east-1.test.vespa.oath.cloud/ (cluster 'default')"
},
{
"at": 0,
@@ -289,7 +349,7 @@
}
]
},
- "lastId": 54,
+ "lastId": 66,
"steps": {
"deployTester": {
"status": "succeeded",
diff --git a/controller-server/src/test/java/com/yahoo/vespa/hosted/controller/restapi/application/responses/test-config-dev.json b/controller-server/src/test/java/com/yahoo/vespa/hosted/controller/restapi/application/responses/test-config-dev.json
index 0632ab7a67b..3a5e6dc5dc3 100644
--- a/controller-server/src/test/java/com/yahoo/vespa/hosted/controller/restapi/application/responses/test-config-dev.json
+++ b/controller-server/src/test/java/com/yahoo/vespa/hosted/controller/restapi/application/responses/test-config-dev.json
@@ -5,18 +5,18 @@
"isCI": false,
"endpoints": {
"dev.us-east-1": [
- "https://my-user--application1--tenant1.us-east-1.dev.vespa.oath.cloud:4443/"
+ "https://my-user.application1.tenant1.us-east-1.dev.vespa.oath.cloud/"
],
"prod.us-central-1": [
- "https://application1--tenant1.us-central-1.vespa.oath.cloud:4443/"
+ "https://application1.tenant1.us-central-1.vespa.oath.cloud/"
]
},
"zoneEndpoints": {
"dev.us-east-1": {
- "default": "https://my-user--application1--tenant1.us-east-1.dev.vespa.oath.cloud:4443/"
+ "default": "https://my-user.application1.tenant1.us-east-1.dev.vespa.oath.cloud/"
},
"prod.us-central-1": {
- "default": "https://application1--tenant1.us-central-1.vespa.oath.cloud:4443/"
+ "default": "https://application1.tenant1.us-central-1.vespa.oath.cloud/"
}
},
"clusters": {
diff --git a/controller-server/src/test/java/com/yahoo/vespa/hosted/controller/restapi/application/responses/test-config.json b/controller-server/src/test/java/com/yahoo/vespa/hosted/controller/restapi/application/responses/test-config.json
index c81ed767239..0a9236655ba 100644
--- a/controller-server/src/test/java/com/yahoo/vespa/hosted/controller/restapi/application/responses/test-config.json
+++ b/controller-server/src/test/java/com/yahoo/vespa/hosted/controller/restapi/application/responses/test-config.json
@@ -5,12 +5,12 @@
"isCI": false,
"endpoints": {
"prod.us-central-1": [
- "https://application1--tenant1.us-central-1.vespa.oath.cloud:4443/"
+ "https://application1.tenant1.us-central-1.vespa.oath.cloud/"
]
},
"zoneEndpoints": {
"prod.us-central-1": {
- "default": "https://application1--tenant1.us-central-1.vespa.oath.cloud:4443/"
+ "default": "https://application1.tenant1.us-central-1.vespa.oath.cloud/"
}
},
"clusters": {
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 2edf1867fd3..0dad88e645b 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
@@ -13,6 +13,9 @@
"name": "ArchiveUriUpdater"
},
{
+ "name": "BillingDatabaseMaintainer"
+ },
+ {
"name": "ChangeRequestMaintainer"
},
{
diff --git a/controller-server/src/test/java/com/yahoo/vespa/hosted/controller/restapi/filter/ControllerAuthorizationFilterTest.java b/controller-server/src/test/java/com/yahoo/vespa/hosted/controller/restapi/filter/ControllerAuthorizationFilterTest.java
index 9e17b44c9a6..eab3a37a9c3 100644
--- a/controller-server/src/test/java/com/yahoo/vespa/hosted/controller/restapi/filter/ControllerAuthorizationFilterTest.java
+++ b/controller-server/src/test/java/com/yahoo/vespa/hosted/controller/restapi/filter/ControllerAuthorizationFilterTest.java
@@ -4,6 +4,7 @@ package com.yahoo.vespa.hosted.controller.restapi.filter;
import com.fasterxml.jackson.databind.ObjectMapper;
import com.yahoo.application.container.handler.Request;
import com.yahoo.config.provision.SystemName;
+import com.yahoo.config.provision.TenantName;
import com.yahoo.jdisc.http.HttpRequest.Method;
import com.yahoo.jdisc.http.filter.DiscFilterRequest;
import com.yahoo.vespa.hosted.controller.ControllerTester;
@@ -75,6 +76,18 @@ public class ControllerAuthorizationFilterTest {
assertIsAllowed(invokeFilter(filter, createRequest(Method.GET, "/zone/v1/path", securityContext)));
}
+ @Test
+ public void hostedDeveloper() {
+ ControllerTester tester = new ControllerTester();
+ TenantName tenantName = TenantName.defaultName();
+ SecurityContext securityContext = new SecurityContext(() -> "user", Set.of(Role.hostedDeveloper(tenantName)));
+
+ ControllerAuthorizationFilter filter = createFilter(tester);
+ assertIsAllowed(invokeFilter(filter, createRequest(Method.POST, "/application/v4/tenant/" + tenantName.value() + "/application/app/instance/default/environment/dev/region/region/deploy", securityContext)));
+ assertIsForbidden(invokeFilter(filter, createRequest(Method.POST, "/application/v4/tenant/" + tenantName.value() + "/application/app/instance/default/environment/prod/region/region/deploy", securityContext)));
+ assertIsForbidden(invokeFilter(filter, createRequest(Method.POST, "/application/v4/tenant/" + tenantName.value() + "/application/app/submit", securityContext)));
+ }
+
private static void assertIsAllowed(Optional<AuthorizationResponse> response) {
assertFalse("Expected no response from filter, but got \"" +
response.map(r -> r.message + "\" (" + r.statusCode + ")").orElse(""),
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 5b2fabcaff8..0b128ebf7a5 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
@@ -258,7 +258,7 @@ public class RoutingApiTest extends ControllerContainerTest {
// One shared and one exclusive zone
deploymentTester.controllerTester().zoneRegistry().setRoutingMethod(ZoneApiMock.from(westZone),
- RoutingMethod.shared);
+ RoutingMethod.sharedLayer4);
deploymentTester.controllerTester().zoneRegistry().setRoutingMethod(ZoneApiMock.from(eastZone),
RoutingMethod.exclusive);
@@ -273,7 +273,7 @@ public class RoutingApiTest extends ControllerContainerTest {
.build();
context.submit(applicationPackage).deploy();
- // GET status for zone using shared routing
+ // GET status for zone using sharedLayer4 routing
tester.assertResponse(operatorRequest("http://localhost:8080/routing/v1/status/tenant/tenant/application/application/instance/default/environment/prod/region/us-west-1",
"", Request.Method.GET),
new File("rotation/deployment-status-initial.json"));
@@ -331,4 +331,5 @@ public class RoutingApiTest extends ControllerContainerTest {
tester.assertResponse(operatorRequest("http://localhost:8080/routing/v1/status/tenant/t1/application/a1/instance/default/endpoint", "", Request.Method.GET),
new File("endpoint/endpoints.json"));
}
+
}
diff --git a/controller-server/src/test/java/com/yahoo/vespa/hosted/controller/restapi/routing/responses/endpoint/endpoints.json b/controller-server/src/test/java/com/yahoo/vespa/hosted/controller/restapi/routing/responses/endpoint/endpoints.json
index f78f913cb7e..75369a19ea7 100644
--- a/controller-server/src/test/java/com/yahoo/vespa/hosted/controller/restapi/routing/responses/endpoint/endpoints.json
+++ b/controller-server/src/test/java/com/yahoo/vespa/hosted/controller/restapi/routing/responses/endpoint/endpoints.json
@@ -2,13 +2,13 @@
"endpoints": [
{
"name": "default",
- "dnsName": "a1--t1.global.vespa.oath.cloud",
- "routingMethod": "shared",
+ "dnsName": "a1.t1.global.vespa.oath.cloud",
+ "routingMethod": "sharedLayer4",
"cluster": "default",
"scope": "global",
"zones": [
{
- "routingMethod": "shared",
+ "routingMethod": "sharedLayer4",
"instance": "t1:a1:default",
"environment": "prod",
"region": "us-east-3",
@@ -17,7 +17,7 @@
"changedAt": 1497618757000
},
{
- "routingMethod": "shared",
+ "routingMethod": "sharedLayer4",
"instance": "t1:a1:default",
"environment": "prod",
"region": "us-west-1",
@@ -28,4 +28,4 @@
]
}
]
-} \ No newline at end of file
+}
diff --git a/controller-server/src/test/java/com/yahoo/vespa/hosted/controller/restapi/routing/responses/recursion/application.json b/controller-server/src/test/java/com/yahoo/vespa/hosted/controller/restapi/routing/responses/recursion/application.json
index e0b0e5e9b7a..06fb2b92c53 100644
--- a/controller-server/src/test/java/com/yahoo/vespa/hosted/controller/restapi/routing/responses/recursion/application.json
+++ b/controller-server/src/test/java/com/yahoo/vespa/hosted/controller/restapi/routing/responses/recursion/application.json
@@ -1,7 +1,7 @@
{
"deployments": [
{
- "routingMethod": "shared",
+ "routingMethod": "sharedLayer4",
"instance": "t1:a1:default",
"environment": "prod",
"region": "us-east-3",
@@ -10,7 +10,7 @@
"changedAt": "(ignore)"
},
{
- "routingMethod": "shared",
+ "routingMethod": "sharedLayer4",
"instance": "t1:a1:default",
"environment": "prod",
"region": "us-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 f0dd0b7310d..1711bb1f856 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
@@ -1,7 +1,7 @@
{
"zones": [
{
- "routingMethod": "shared",
+ "routingMethod": "sharedLayer4",
"environment": "test",
"region": "us-east-1",
"status": "in",
@@ -9,7 +9,7 @@
"changedAt": 0
},
{
- "routingMethod": "shared",
+ "routingMethod": "sharedLayer4",
"environment": "staging",
"region": "us-east-3",
"status": "in",
@@ -17,7 +17,7 @@
"changedAt": 0
},
{
- "routingMethod": "shared",
+ "routingMethod": "sharedLayer4",
"environment": "dev",
"region": "us-east-1",
"status": "in",
@@ -25,7 +25,7 @@
"changedAt": 0
},
{
- "routingMethod": "shared",
+ "routingMethod": "sharedLayer4",
"environment": "dev",
"region": "aws-us-east-2a",
"status": "in",
@@ -33,7 +33,7 @@
"changedAt": 0
},
{
- "routingMethod": "shared",
+ "routingMethod": "sharedLayer4",
"environment": "perf",
"region": "us-east-3",
"status": "in",
@@ -41,7 +41,7 @@
"changedAt": 0
},
{
- "routingMethod": "shared",
+ "routingMethod": "sharedLayer4",
"environment": "prod",
"region": "aws-us-east-1a",
"status": "in",
@@ -49,7 +49,7 @@
"changedAt": 0
},
{
- "routingMethod": "shared",
+ "routingMethod": "sharedLayer4",
"environment": "prod",
"region": "ap-northeast-1",
"status": "in",
@@ -57,7 +57,7 @@
"changedAt": 0
},
{
- "routingMethod": "shared",
+ "routingMethod": "sharedLayer4",
"environment": "prod",
"region": "ap-northeast-2",
"status": "in",
@@ -65,7 +65,7 @@
"changedAt": 0
},
{
- "routingMethod": "shared",
+ "routingMethod": "sharedLayer4",
"environment": "prod",
"region": "ap-southeast-1",
"status": "in",
@@ -73,7 +73,7 @@
"changedAt": 0
},
{
- "routingMethod": "shared",
+ "routingMethod": "sharedLayer4",
"environment": "prod",
"region": "us-east-3",
"status": "in",
@@ -81,7 +81,7 @@
"changedAt": 0
},
{
- "routingMethod": "shared",
+ "routingMethod": "sharedLayer4",
"environment": "prod",
"region": "us-west-1",
"status": "in",
@@ -89,7 +89,7 @@
"changedAt": 0
},
{
- "routingMethod": "shared",
+ "routingMethod": "sharedLayer4",
"environment": "prod",
"region": "us-central-1",
"status": "in",
@@ -97,7 +97,7 @@
"changedAt": 0
},
{
- "routingMethod": "shared",
+ "routingMethod": "sharedLayer4",
"environment": "prod",
"region": "eu-west-1",
"status": "in",
diff --git a/controller-server/src/test/java/com/yahoo/vespa/hosted/controller/restapi/routing/responses/recursion/tenant.json b/controller-server/src/test/java/com/yahoo/vespa/hosted/controller/restapi/routing/responses/recursion/tenant.json
index 1ee4e1b82ba..5de12d9b1ec 100644
--- a/controller-server/src/test/java/com/yahoo/vespa/hosted/controller/restapi/routing/responses/recursion/tenant.json
+++ b/controller-server/src/test/java/com/yahoo/vespa/hosted/controller/restapi/routing/responses/recursion/tenant.json
@@ -1,7 +1,7 @@
{
"deployments": [
{
- "routingMethod": "shared",
+ "routingMethod": "sharedLayer4",
"instance": "t1:a1:default",
"environment": "prod",
"region": "us-east-3",
@@ -10,7 +10,7 @@
"changedAt": "(ignore)"
},
{
- "routingMethod": "shared",
+ "routingMethod": "sharedLayer4",
"instance": "t1:a1:default",
"environment": "prod",
"region": "us-west-1",
@@ -19,7 +19,7 @@
"changedAt": "(ignore)"
},
{
- "routingMethod": "shared",
+ "routingMethod": "sharedLayer4",
"instance": "t1:a2:default",
"environment": "prod",
"region": "us-east-3",
@@ -28,7 +28,7 @@
"changedAt": "(ignore)"
},
{
- "routingMethod": "shared",
+ "routingMethod": "sharedLayer4",
"instance": "t1:a2:default",
"environment": "prod",
"region": "us-west-1",
diff --git a/controller-server/src/test/java/com/yahoo/vespa/hosted/controller/restapi/routing/responses/rotation/deployment-status-in.json b/controller-server/src/test/java/com/yahoo/vespa/hosted/controller/restapi/routing/responses/rotation/deployment-status-in.json
index 5b15b72752c..4eb51c1e907 100644
--- a/controller-server/src/test/java/com/yahoo/vespa/hosted/controller/restapi/routing/responses/rotation/deployment-status-in.json
+++ b/controller-server/src/test/java/com/yahoo/vespa/hosted/controller/restapi/routing/responses/rotation/deployment-status-in.json
@@ -1,7 +1,7 @@
{
"deployments": [
{
- "routingMethod": "shared",
+ "routingMethod": "sharedLayer4",
"instance": "tenant:application:default",
"environment": "prod",
"region": "us-west-1",
diff --git a/controller-server/src/test/java/com/yahoo/vespa/hosted/controller/restapi/routing/responses/rotation/deployment-status-initial.json b/controller-server/src/test/java/com/yahoo/vespa/hosted/controller/restapi/routing/responses/rotation/deployment-status-initial.json
index 90b2317c1b3..615ce4b4a6e 100644
--- a/controller-server/src/test/java/com/yahoo/vespa/hosted/controller/restapi/routing/responses/rotation/deployment-status-initial.json
+++ b/controller-server/src/test/java/com/yahoo/vespa/hosted/controller/restapi/routing/responses/rotation/deployment-status-initial.json
@@ -1,7 +1,7 @@
{
"deployments": [
{
- "routingMethod": "shared",
+ "routingMethod": "sharedLayer4",
"instance": "tenant:application:default",
"environment": "prod",
"region": "us-west-1",
diff --git a/controller-server/src/test/java/com/yahoo/vespa/hosted/controller/restapi/routing/responses/rotation/deployment-status-out.json b/controller-server/src/test/java/com/yahoo/vespa/hosted/controller/restapi/routing/responses/rotation/deployment-status-out.json
index 85e345c01d0..816bc810048 100644
--- a/controller-server/src/test/java/com/yahoo/vespa/hosted/controller/restapi/routing/responses/rotation/deployment-status-out.json
+++ b/controller-server/src/test/java/com/yahoo/vespa/hosted/controller/restapi/routing/responses/rotation/deployment-status-out.json
@@ -1,7 +1,7 @@
{
"deployments": [
{
- "routingMethod": "shared",
+ "routingMethod": "sharedLayer4",
"instance": "tenant:application:default",
"environment": "prod",
"region": "us-west-1",
diff --git a/controller-server/src/test/java/com/yahoo/vespa/hosted/controller/restapi/routing/responses/rotation/zone-status-in.json b/controller-server/src/test/java/com/yahoo/vespa/hosted/controller/restapi/routing/responses/rotation/zone-status-in.json
index eb06e9ee11d..8460cc5ec8a 100644
--- a/controller-server/src/test/java/com/yahoo/vespa/hosted/controller/restapi/routing/responses/rotation/zone-status-in.json
+++ b/controller-server/src/test/java/com/yahoo/vespa/hosted/controller/restapi/routing/responses/rotation/zone-status-in.json
@@ -1,5 +1,5 @@
{
- "routingMethod": "shared",
+ "routingMethod": "sharedLayer4",
"environment": "prod",
"region": "us-west-1",
"status": "in",
diff --git a/controller-server/src/test/java/com/yahoo/vespa/hosted/controller/restapi/routing/responses/rotation/zone-status-initial.json b/controller-server/src/test/java/com/yahoo/vespa/hosted/controller/restapi/routing/responses/rotation/zone-status-initial.json
index eb06e9ee11d..8460cc5ec8a 100644
--- a/controller-server/src/test/java/com/yahoo/vespa/hosted/controller/restapi/routing/responses/rotation/zone-status-initial.json
+++ b/controller-server/src/test/java/com/yahoo/vespa/hosted/controller/restapi/routing/responses/rotation/zone-status-initial.json
@@ -1,5 +1,5 @@
{
- "routingMethod": "shared",
+ "routingMethod": "sharedLayer4",
"environment": "prod",
"region": "us-west-1",
"status": "in",
diff --git a/controller-server/src/test/java/com/yahoo/vespa/hosted/controller/restapi/routing/responses/rotation/zone-status-out.json b/controller-server/src/test/java/com/yahoo/vespa/hosted/controller/restapi/routing/responses/rotation/zone-status-out.json
index 440b80bc4d0..88fddcbd955 100644
--- a/controller-server/src/test/java/com/yahoo/vespa/hosted/controller/restapi/routing/responses/rotation/zone-status-out.json
+++ b/controller-server/src/test/java/com/yahoo/vespa/hosted/controller/restapi/routing/responses/rotation/zone-status-out.json
@@ -1,5 +1,5 @@
{
- "routingMethod": "shared",
+ "routingMethod": "sharedLayer4",
"environment": "prod",
"region": "us-west-1",
"status": "out",
diff --git a/controller-server/src/test/java/com/yahoo/vespa/hosted/controller/restapi/user/UserApiTest.java b/controller-server/src/test/java/com/yahoo/vespa/hosted/controller/restapi/user/UserApiTest.java
index 537f6c48bdf..a93e9f55e30 100644
--- a/controller-server/src/test/java/com/yahoo/vespa/hosted/controller/restapi/user/UserApiTest.java
+++ b/controller-server/src/test/java/com/yahoo/vespa/hosted/controller/restapi/user/UserApiTest.java
@@ -67,9 +67,16 @@ public class UserApiTest extends ControllerContainerCloudTest {
tester.assertResponse(request("/application/v4/tenant/my-tenant", POST)
.roles(operator)
.principal("administrator@tenant")
+ .user(new User("administrator@tenant", "administrator", "admin", "picture"))
.data("{\"token\":\"hello\"}"),
new File("tenant-without-applications.json"));
+ // GET at tenant/info with contact information.
+ tester.assertResponse(request("/application/v4/tenant/my-tenant/info")
+ .roles(operator)
+ .principal("administrator@tenant"),
+ new File("tenant-info-after-created.json"));
+
// GET at user/v1 root fails as no access control is defined there.
tester.assertResponse(request("/user/v1/"),
accessDenied, 403);
diff --git a/controller-server/src/test/java/com/yahoo/vespa/hosted/controller/restapi/user/responses/tenant-info-after-created.json b/controller-server/src/test/java/com/yahoo/vespa/hosted/controller/restapi/user/responses/tenant-info-after-created.json
new file mode 100644
index 00000000000..942b5c1db45
--- /dev/null
+++ b/controller-server/src/test/java/com/yahoo/vespa/hosted/controller/restapi/user/responses/tenant-info-after-created.json
@@ -0,0 +1,8 @@
+{
+ "name": "",
+ "email": "",
+ "website":"",
+ "invoiceEmail":"",
+ "contactName": "administrator",
+ "contactEmail": "administrator@tenant"
+} \ No newline at end of file
diff --git a/controller-server/src/test/java/com/yahoo/vespa/hosted/controller/restapi/user/responses/tenant-with-keys.json b/controller-server/src/test/java/com/yahoo/vespa/hosted/controller/restapi/user/responses/tenant-with-keys.json
index 7cc1a51a114..54585767d51 100644
--- a/controller-server/src/test/java/com/yahoo/vespa/hosted/controller/restapi/user/responses/tenant-with-keys.json
+++ b/controller-server/src/test/java/com/yahoo/vespa/hosted/controller/restapi/user/responses/tenant-with-keys.json
@@ -1,6 +1,7 @@
{
"tenant": "my-tenant",
"type": "CLOUD",
+ "creator": "administrator@tenant",
"pemDeveloperKeys": [
{
"key": "-----BEGIN PUBLIC KEY-----\nMFkwEwYHKoZIzj0CAQYIKoZIzj0DAQcDQgAEuKVFA8dXk43kVfYKzkUqhEY2rDT9\nz/4jKSTHwbYR8wdsOSrJGVEUPbS2nguIJ64OJH7gFnxM6sxUVj+Nm2HlXw==\n-----END PUBLIC KEY-----\n",
diff --git a/controller-server/src/test/java/com/yahoo/vespa/hosted/controller/restapi/user/responses/tenant-with-secrets.json b/controller-server/src/test/java/com/yahoo/vespa/hosted/controller/restapi/user/responses/tenant-with-secrets.json
index 1662484ade8..1cd2fb41263 100644
--- a/controller-server/src/test/java/com/yahoo/vespa/hosted/controller/restapi/user/responses/tenant-with-secrets.json
+++ b/controller-server/src/test/java/com/yahoo/vespa/hosted/controller/restapi/user/responses/tenant-with-secrets.json
@@ -1,6 +1,7 @@
{
"tenant": "my-tenant",
"type": "CLOUD",
+ "creator": "administrator@tenant",
"pemDeveloperKeys": [
{
"key": "-----BEGIN PUBLIC KEY-----\nMFkwEwYHKoZIzj0CAQYIKoZIzj0DAQcDQgAEFELzPyinTfQ/sZnTmRp5E4Ve/sbE\npDhJeqczkyFcT2PysJ5sZwm7rKPEeXDOhzTPCyRvbUqc2SGdWbKUGGa/Yw==\n-----END PUBLIC KEY-----\n",
diff --git a/controller-server/src/test/java/com/yahoo/vespa/hosted/controller/routing/rotation/RotationRepositoryTest.java b/controller-server/src/test/java/com/yahoo/vespa/hosted/controller/routing/rotation/RotationRepositoryTest.java
index 9a56123e8e3..d7847da2404 100644
--- a/controller-server/src/test/java/com/yahoo/vespa/hosted/controller/routing/rotation/RotationRepositoryTest.java
+++ b/controller-server/src/test/java/com/yahoo/vespa/hosted/controller/routing/rotation/RotationRepositoryTest.java
@@ -60,8 +60,8 @@ public class RotationRepositoryTest {
Rotation expected = new Rotation(new RotationId("foo-1"), "foo-1.com");
assertEquals(List.of(expected.id()), rotationIds(application.instance().rotations()));
- assertEquals(URI.create("https://app1--tenant1.global.vespa.oath.cloud:4443/"),
- tester.controller().routing().readDeclaredEndpointsOf(application.instanceId()).primary().get().url());
+ assertEquals(URI.create("https://app1.tenant1.global.vespa.oath.cloud/"),
+ tester.controller().routing().readDeclaredEndpointsOf(application.instanceId()).direct().first().get().url());
try (RotationLock lock = repository.lock()) {
List<AssignedRotation> rotations = repository.getOrAssignRotations(application.application().deploymentSpec(),
application.instance(),
@@ -151,13 +151,13 @@ public class RotationRepositoryTest {
ZoneApiMock.fromId("prod.cd-us-west-1"));
tester.controllerTester().zoneRegistry()
.setZones(zones)
- .setRoutingMethod(zones, RoutingMethod.shared)
+ .setRoutingMethod(zones, RoutingMethod.sharedLayer4)
.setSystemName(SystemName.cd);
tester.configServer().bootstrap(tester.controllerTester().zoneRegistry().zones().all().ids(), SystemApplication.notController());
var application2 = tester.newDeploymentContext("tenant2", "app2", "default");
application2.submit(applicationPackage).deploy();
assertEquals(List.of(new RotationId("foo-1")), rotationIds(application2.instance().rotations()));
- assertEquals("https://cd--app2--tenant2.global.vespa.oath.cloud:4443/",
+ assertEquals("https://cd.app2.tenant2.global.vespa.oath.cloud/",
tester.controller().routing().readDeclaredEndpointsOf(application2.instanceId()).primary().get().url().toString());
}
@@ -175,10 +175,10 @@ public class RotationRepositoryTest {
var instance2 = tester.newDeploymentContext("tenant1", "application1", "instance2");
assertEquals(List.of(new RotationId("foo-1")), rotationIds(instance1.instance().rotations()));
assertEquals(List.of(new RotationId("foo-2")), rotationIds(instance2.instance().rotations()));
- assertEquals(URI.create("https://instance1--application1--tenant1.global.vespa.oath.cloud:4443/"),
- tester.controller().routing().readDeclaredEndpointsOf(instance1.instanceId()).primary().get().url());
- assertEquals(URI.create("https://instance2--application1--tenant1.global.vespa.oath.cloud:4443/"),
- tester.controller().routing().readDeclaredEndpointsOf(instance2.instanceId()).primary().get().url());
+ assertEquals(URI.create("https://instance1.application1.tenant1.global.vespa.oath.cloud/"),
+ tester.controller().routing().readDeclaredEndpointsOf(instance1.instanceId()).direct().first().get().url());
+ assertEquals(URI.create("https://instance2.application1.tenant1.global.vespa.oath.cloud/"),
+ tester.controller().routing().readDeclaredEndpointsOf(instance2.instanceId()).direct().first().get().url());
}
@Test
@@ -197,10 +197,10 @@ public class RotationRepositoryTest {
assertEquals(List.of(new RotationId("foo-1")), rotationIds(instance1.instance().rotations()));
assertEquals(List.of(new RotationId("foo-2")), rotationIds(instance2.instance().rotations()));
- assertEquals(URI.create("https://instance1--application1--tenant1.global.vespa.oath.cloud:4443/"),
- tester.controller().routing().readDeclaredEndpointsOf(instance1.instanceId()).primary().get().url());
- assertEquals(URI.create("https://instance2--application1--tenant1.global.vespa.oath.cloud:4443/"),
- tester.controller().routing().readDeclaredEndpointsOf(instance2.instanceId()).primary().get().url());
+ assertEquals(URI.create("https://instance1.application1.tenant1.global.vespa.oath.cloud/"),
+ tester.controller().routing().readDeclaredEndpointsOf(instance1.instanceId()).direct().first().get().url());
+ assertEquals(URI.create("https://instance2.application1.tenant1.global.vespa.oath.cloud/"),
+ tester.controller().routing().readDeclaredEndpointsOf(instance2.instanceId()).direct().first().get().url());
}
private void assertSingleRotation(Rotation expected, List<AssignedRotation> assignedRotations, RotationRepository repository) {