aboutsummaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
-rw-r--r--config-model-api/abi-spec.json6
-rw-r--r--config-model-api/src/main/java/com/yahoo/config/application/api/Endpoint.java11
-rw-r--r--config-model-api/src/main/java/com/yahoo/config/application/api/ValidationId.java3
-rw-r--r--controller-server/src/main/java/com/yahoo/vespa/hosted/controller/ApplicationController.java17
-rw-r--r--controller-server/src/main/java/com/yahoo/vespa/hosted/controller/application/ApplicationPackageValidator.java85
-rw-r--r--controller-server/src/test/java/com/yahoo/vespa/hosted/controller/ControllerTest.java141
-rw-r--r--controller-server/src/test/java/com/yahoo/vespa/hosted/controller/deployment/ApplicationPackageBuilder.java9
-rw-r--r--controller-server/src/test/java/com/yahoo/vespa/hosted/controller/maintenance/RoutingPoliciesTest.java2
-rw-r--r--controller-server/src/test/java/com/yahoo/vespa/hosted/controller/restapi/application/ApplicationApiTest.java4
9 files changed, 227 insertions, 51 deletions
diff --git a/config-model-api/abi-spec.json b/config-model-api/abi-spec.json
index d08cda06e5d..affc94e2bcb 100644
--- a/config-model-api/abi-spec.json
+++ b/config-model-api/abi-spec.json
@@ -373,9 +373,10 @@
"public java.lang.String endpointId()",
"public java.lang.String containerId()",
"public java.util.Set regions()",
+ "public com.yahoo.config.application.api.Endpoint withRegions(java.util.Set)",
"public boolean equals(java.lang.Object)",
"public int hashCode()",
- "public com.yahoo.config.application.api.Endpoint withRegions(java.util.Set)"
+ "public java.lang.String toString()"
],
"fields": []
},
@@ -518,7 +519,8 @@
"public static final enum com.yahoo.config.application.api.ValidationId configModelVersionMismatch",
"public static final enum com.yahoo.config.application.api.ValidationId skipOldConfigModels",
"public static final enum com.yahoo.config.application.api.ValidationId forceAutomaticTenantUpgradeTests",
- "public static final enum com.yahoo.config.application.api.ValidationId accessControl"
+ "public static final enum com.yahoo.config.application.api.ValidationId accessControl",
+ "public static final enum com.yahoo.config.application.api.ValidationId globalEndpointChange"
]
},
"com.yahoo.config.application.api.ValidationOverrides$Allow": {
diff --git a/config-model-api/src/main/java/com/yahoo/config/application/api/Endpoint.java b/config-model-api/src/main/java/com/yahoo/config/application/api/Endpoint.java
index e47dcd78219..99cb07f3104 100644
--- a/config-model-api/src/main/java/com/yahoo/config/application/api/Endpoint.java
+++ b/config-model-api/src/main/java/com/yahoo/config/application/api/Endpoint.java
@@ -60,6 +60,10 @@ public class Endpoint {
return regions;
}
+ public Endpoint withRegions(Set<String> regions) {
+ return new Endpoint(endpointId, containerId, regions);
+ }
+
@Override
public boolean equals(Object o) {
if (this == o) return true;
@@ -75,7 +79,10 @@ public class Endpoint {
return Objects.hash(endpointId, containerId, regions);
}
- public Endpoint withRegions(Set<String> regions) {
- return new Endpoint(endpointId, containerId, regions);
+ @Override
+ public String toString() {
+ return "endpoint '" + endpointId() + "' (cluster " + containerId + ") -> " +
+ regions.stream().map(RegionName::value).sorted().collect(Collectors.joining(", "));
}
+
}
diff --git a/config-model-api/src/main/java/com/yahoo/config/application/api/ValidationId.java b/config-model-api/src/main/java/com/yahoo/config/application/api/ValidationId.java
index 65dc264eb8a..35ece71a72e 100644
--- a/config-model-api/src/main/java/com/yahoo/config/application/api/ValidationId.java
+++ b/config-model-api/src/main/java/com/yahoo/config/application/api/ValidationId.java
@@ -22,7 +22,8 @@ public enum ValidationId {
configModelVersionMismatch("config-model-version-mismatch"), // Internal use
skipOldConfigModels("skip-old-config-models"), // Internal use
forceAutomaticTenantUpgradeTests("force-automatic-tenant-upgrade-test"), // Internal use
- accessControl("access-control"); // Internal use, used in zones where there should be no access-control
+ accessControl("access-control"), // Internal use, used in zones where there should be no access-control
+ globalEndpointChange("global-endpoint-change"); // Changing global endpoints
private final String id;
diff --git a/controller-server/src/main/java/com/yahoo/vespa/hosted/controller/ApplicationController.java b/controller-server/src/main/java/com/yahoo/vespa/hosted/controller/ApplicationController.java
index cdd2eb2a332..703fc71dc31 100644
--- a/controller-server/src/main/java/com/yahoo/vespa/hosted/controller/ApplicationController.java
+++ b/controller-server/src/main/java/com/yahoo/vespa/hosted/controller/ApplicationController.java
@@ -385,11 +385,6 @@ public class ApplicationController {
validateRun(application.get(), instance, zone, platformVersion, applicationVersion);
}
- if (zone.environment().isProduction()) // Assign and register endpoints
- application = withRotation(applicationPackage.deploymentSpec(), application, instance);
-
- endpoints = registerEndpointsInDns(applicationPackage.deploymentSpec(), application.get().require(instanceId.instance()), zone);
-
if (controller.zoneRegistry().zones().directlyRouted().ids().contains(zone)) {
// Provisions a new certificate if missing
applicationCertificate = getApplicationCertificate(application.get().require(instance));
@@ -401,8 +396,13 @@ public class ApplicationController {
if ( ! preferOldestVersion
&& ! application.get().internal()
&& ! zone.environment().isManuallyDeployed()) {
- storeWithUpdatedConfig(application, applicationPackage);
+ application = storeWithUpdatedConfig(application, applicationPackage);
}
+
+ if (zone.environment().isProduction()) // Assign and register endpoints
+ application = withRotation(applicationPackage.deploymentSpec(), application, instance);
+
+ endpoints = registerEndpointsInDns(applicationPackage.deploymentSpec(), application.get().require(instanceId.instance()), zone);
} // Release application lock while doing the deployment, which is a lengthy task.
// Carry out deployment without holding the application lock.
@@ -454,8 +454,8 @@ public class ApplicationController {
}
/** Stores the deployment spec and validation overrides from the application package, and runs cleanup. */
- public void storeWithUpdatedConfig(LockedApplication application, ApplicationPackage applicationPackage) {
- applicationPackageValidator.validate(applicationPackage);
+ public LockedApplication storeWithUpdatedConfig(LockedApplication application, ApplicationPackage applicationPackage) {
+ applicationPackageValidator.validate(application.get(), applicationPackage, clock.instant());
application = application.with(applicationPackage.deploymentSpec());
application = application.with(applicationPackage.validationOverrides());
@@ -471,6 +471,7 @@ public class ApplicationController {
application = application.with(instanceName, instance -> withoutUnreferencedDeploymentJobs(deploymentSpec, instance));
}
store(application);
+ return application;
}
/** Deploy a system application to given zone */
diff --git a/controller-server/src/main/java/com/yahoo/vespa/hosted/controller/application/ApplicationPackageValidator.java b/controller-server/src/main/java/com/yahoo/vespa/hosted/controller/application/ApplicationPackageValidator.java
index 27d8f69108f..5ee269f8448 100644
--- a/controller-server/src/main/java/com/yahoo/vespa/hosted/controller/application/ApplicationPackageValidator.java
+++ b/controller-server/src/main/java/com/yahoo/vespa/hosted/controller/application/ApplicationPackageValidator.java
@@ -1,16 +1,27 @@
// Copyright 2019 Oath Inc. Licensed under the terms of the Apache 2.0 license. See LICENSE in the project root.
package com.yahoo.vespa.hosted.controller.application;
+import com.yahoo.config.application.api.DeploymentInstanceSpec;
import com.yahoo.config.application.api.DeploymentSpec;
+import com.yahoo.config.application.api.Endpoint;
+import com.yahoo.config.application.api.ValidationId;
+import com.yahoo.config.application.api.ValidationOverrides;
import com.yahoo.config.provision.CloudName;
import com.yahoo.config.provision.Environment;
+import com.yahoo.config.provision.InstanceName;
+import com.yahoo.config.provision.RegionName;
import com.yahoo.config.provision.zone.ZoneApi;
import com.yahoo.config.provision.zone.ZoneId;
+import com.yahoo.vespa.hosted.controller.Application;
import com.yahoo.vespa.hosted.controller.Controller;
import com.yahoo.vespa.hosted.controller.deployment.DeploymentSteps;
+import java.time.Instant;
+import java.util.ArrayList;
import java.util.HashSet;
+import java.util.List;
import java.util.Objects;
+import java.util.Optional;
import java.util.stream.Collectors;
/**
@@ -31,9 +42,10 @@ public class ApplicationPackageValidator {
*
* @throws IllegalArgumentException if any validations fail
*/
- public void validate(ApplicationPackage applicationPackage) {
+ public void validate(Application application, ApplicationPackage applicationPackage, Instant instant) {
validateSteps(applicationPackage.deploymentSpec());
- validateEndpoints(applicationPackage.deploymentSpec());
+ validateEndpointRegions(applicationPackage.deploymentSpec());
+ validateEndpointChange(application, applicationPackage, instant);
}
/** Verify that each of the production zones listed in the deployment spec exist in this system */
@@ -50,7 +62,7 @@ public class ApplicationPackageValidator {
}
/** Verify that no single endpoint contains regions in different clouds */
- private void validateEndpoints(DeploymentSpec deploymentSpec) {
+ private void validateEndpointRegions(DeploymentSpec deploymentSpec) {
for (var instance : deploymentSpec.instances()) {
for (var endpoint : instance.endpoints()) {
var clouds = new HashSet<CloudName>();
@@ -68,4 +80,71 @@ public class ApplicationPackageValidator {
}
}
+ /** Verify endpoint configuration of given application package */
+ private void validateEndpointChange(Application application, ApplicationPackage applicationPackage, Instant instant) {
+ applicationPackage.deploymentSpec().instances().forEach(instance -> validateEndpointChange(application,
+ instance.name(),
+ applicationPackage,
+ instant));
+ }
+
+ /** Verify changes to endpoint configuration by comparing given application package to the existing one, if any */
+ private void validateEndpointChange(Application application, InstanceName instanceName, ApplicationPackage applicationPackage, Instant instant) {
+ var validationId = ValidationId.globalEndpointChange;
+ if (applicationPackage.validationOverrides().allows(validationId, instant)) return;
+
+ var endpoints = application.deploymentSpec().instance(instanceName)
+ .map(ApplicationPackageValidator::allEndpointsOf)
+ .orElseGet(List::of);
+ var newEndpoints = allEndpointsOf(applicationPackage.deploymentSpec().requireInstance(instanceName));
+
+ if (newEndpoints.containsAll(endpoints)) return; // Adding new endpoints is fine
+ if (containsAllRegions(newEndpoints, endpoints)) return; // Adding regions to endpoints is fine
+
+ var removedEndpoints = new ArrayList<>(endpoints);
+ removedEndpoints.removeAll(newEndpoints);
+ newEndpoints.removeAll(endpoints);
+ throw new IllegalArgumentException(validationId.value() + ": application '" + application.id() +
+ (instanceName.isDefault() ? "" : "." + instanceName.value()) +
+ "' has endpoints " + endpoints +
+ ", but does not include all of these in deployment.xml. Deploying given " +
+ "deployment.xml will remove " + removedEndpoints +
+ (newEndpoints.isEmpty() ? "" : " and add " + newEndpoints) +
+ ". " + ValidationOverrides.toAllowMessage(validationId));
+ }
+
+ /** Returns whether endpoint regions in newEndpoints contains all regions of corresponding endpoint in endpoints */
+ private static boolean containsAllRegions(List<Endpoint> newEndpoints, List<Endpoint> endpoints) {
+ var containsAllRegions = true;
+ for (var endpoint : endpoints) {
+ var endpointContainsAllRegions = false;
+ for (var newEndpoint : newEndpoints) {
+ if (endpoint.endpointId().equals(newEndpoint.endpointId())) {
+ endpointContainsAllRegions = newEndpoint.regions().containsAll(endpoint.regions());
+ }
+ }
+ containsAllRegions &= endpointContainsAllRegions;
+ }
+ return containsAllRegions;
+ }
+
+ /** Returns all configued endpoints of given deployment instance spec */
+ private static List<Endpoint> allEndpointsOf(DeploymentInstanceSpec deploymentInstanceSpec) {
+ var endpoints = new ArrayList<>(deploymentInstanceSpec.endpoints());
+ legacyEndpoint(deploymentInstanceSpec).ifPresent(endpoints::add);
+ return endpoints;
+ }
+
+ /** Returns global service ID as a endpoint, if any global service ID is set */
+ private static Optional<Endpoint> legacyEndpoint(DeploymentInstanceSpec instance) {
+ return instance.globalServiceId().map(globalServiceId -> {
+ var regions = instance.zones().stream()
+ .filter(zone -> zone.environment().isProduction())
+ .map(zone -> zone.region().get())
+ .map(RegionName::value)
+ .collect(Collectors.toSet());
+ return new Endpoint(Optional.of(EndpointId.defaultId().id()), instance.globalServiceId().get(), regions);
+ });
+ }
+
}
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 1558656b086..e38f6d25cc8 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
@@ -402,49 +402,130 @@ public class ControllerTest {
}
@Test
- public void testDnsAliasRegistrationWithChangingZones() {
+ public void testDnsAliasRegistrationWithChangingEndpoints() {
Application application = tester.createApplication("app1", "tenant1", 1, 1L);
+ var west = ZoneId.from("prod", "us-west-1");
+ var central = ZoneId.from("prod", "us-central-1");
+ var east = ZoneId.from("prod", "us-east-3");
+ var buildNumber = BuildJob.defaultBuildNumber;
+ // Application is deployed with endpoint pointing to 2/3 zones
ApplicationPackage applicationPackage = new ApplicationPackageBuilder()
.environment(Environment.prod)
- .endpoint("default", "qrs", "us-west-1", "us-central-1")
- .region("us-west-1")
- .region("us-central-1")
+ .endpoint("default", "qrs", west.region().value(), central.region().value())
+ .region(west.region().value())
+ .region(central.region().value())
+ .region(east.region().value())
.build();
+ tester.deployCompletely(application, applicationPackage, ++buildNumber);
+
+ 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"),
+ tester.configServer().rotationNames().get(new DeploymentId(application.id().defaultInstance(), zone))
+ );
+ }
- tester.deployCompletely(application, applicationPackage);
-
- assertEquals(
- Set.of("rotation-id-01", "app1--tenant1.global.vespa.oath.cloud"),
- tester.configServer().rotationNames().get(new DeploymentId(application.id().defaultInstance(), ZoneId.from("prod", "us-west-1")))
- );
-
+ // Application is deployed with an additional endpoint
+ ApplicationPackage applicationPackage2 = new ApplicationPackageBuilder()
+ .environment(Environment.prod)
+ .endpoint("default", "qrs", west.region().value(), central.region().value())
+ .endpoint("east", "qrs", east.region().value())
+ .region(west.region().value())
+ .region(central.region().value())
+ .region(east.region().value())
+ .build();
+ tester.deployCompletely(application, applicationPackage2, ++buildNumber);
+
+ 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"),
+ tester.configServer().rotationNames().get(new DeploymentId(application.id().defaultInstance(), zone))
+ );
+ }
assertEquals(
- Set.of("rotation-id-01", "app1--tenant1.global.vespa.oath.cloud"),
- tester.configServer().rotationNames().get(new DeploymentId(application.id().defaultInstance(), ZoneId.from("prod", "us-central-1")))
+ "Zone " + east + " is a member of global endpoint",
+ Set.of("rotation-id-02", "east--app1--tenant1.global.vespa.oath.cloud"),
+ tester.configServer().rotationNames().get(new DeploymentId(application.id().defaultInstance(), east))
);
-
- ApplicationPackage applicationPackage2 = new ApplicationPackageBuilder()
+ // Application is deployed with default endpoint pointing to 3/3 zones
+ ApplicationPackage applicationPackage3 = new ApplicationPackageBuilder()
.environment(Environment.prod)
- .endpoint("default", "qrs", "us-west-1")
- .region("us-west-1")
- .region("us-central-1")
+ .endpoint("default", "qrs", west.region().value(), central.region().value(), east.region().value())
+ .endpoint("east", "qrs", east.region().value())
+ .region(west.region().value())
+ .region(central.region().value())
+ .region(east.region().value())
.build();
+ tester.deployCompletely(application, applicationPackage3, ++buildNumber);
+ for (var zone : List.of(west, central, east)) {
+ 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"),
+ tester.configServer().rotationNames().get(new DeploymentId(application.id().defaultInstance(), zone))
+ );
+ }
- tester.deployCompletely(application, applicationPackage2, BuildJob.defaultBuildNumber + 1);
-
- assertEquals(
- Set.of("rotation-id-01", "app1--tenant1.global.vespa.oath.cloud"),
- tester.configServer().rotationNames().get(new DeploymentId(application.id().defaultInstance(), ZoneId.from("prod", "us-west-1")))
- );
+ // Region is removed from an endpoint without override
+ ApplicationPackage applicationPackage4 = new ApplicationPackageBuilder()
+ .environment(Environment.prod)
+ .endpoint("default", "qrs", west.region().value(), central.region().value())
+ .endpoint("east", "qrs", east.region().value())
+ .region(west.region().value())
+ .region(central.region().value())
+ .region(east.region().value())
+ .build();
+ try {
+ tester.deployCompletely(application, applicationPackage4, ++buildNumber);
+ fail("Expected exception");
+ } catch (IllegalArgumentException e) {
+ assertEquals("global-endpoint-change: application 'tenant1.app1' has endpoints " +
+ "[endpoint 'default' (cluster qrs) -> us-central-1, us-east-3, us-west-1, endpoint 'east' (cluster qrs) -> us-east-3], " +
+ "but does not include all of these in deployment.xml. Deploying given deployment.xml " +
+ "will remove [endpoint 'default' (cluster qrs) -> us-central-1, us-east-3, us-west-1] " +
+ "and add [endpoint 'default' (cluster qrs) -> us-central-1, us-west-1]. " +
+ ValidationOverrides.toAllowMessage(ValidationId.globalEndpointChange), e.getMessage());
+ } finally {
+ tester.buildService().clear();
+ }
- assertEquals(
- Set.of(),
- tester.configServer().rotationNames().get(new DeploymentId(application.id().defaultInstance(), ZoneId.from("prod", "us-central-1")))
- );
+ // Entire endpoint is removed without override
+ ApplicationPackage applicationPackage5 = new ApplicationPackageBuilder()
+ .environment(Environment.prod)
+ .endpoint("east", "qrs", east.region().value())
+ .region(west.region().value())
+ .region(central.region().value())
+ .region(east.region().value())
+ .build();
+ try {
+ tester.deployCompletely(application, applicationPackage5, ++buildNumber);
+ fail("Expected exception");
+ } catch (IllegalArgumentException e) {
+ assertEquals("global-endpoint-change: application 'tenant1.app1' has endpoints " +
+ "[endpoint 'default' (cluster qrs) -> us-central-1, us-east-3, us-west-1, endpoint 'east' (cluster qrs) -> us-east-3], " +
+ "but does not include all of these in deployment.xml. Deploying given deployment.xml " +
+ "will remove [endpoint 'default' (cluster qrs) -> us-central-1, us-east-3, us-west-1]. " +
+ ValidationOverrides.toAllowMessage(ValidationId.globalEndpointChange), e.getMessage());
+ } finally {
+ tester.buildService().clear();
+ }
- assertEquals(Set.of(RegionName.from("us-west-1")), tester.defaultInstance(application.id()).rotations().get(0).regions());
+ // ... override is added
+ ApplicationPackage applicationPackage6 = new ApplicationPackageBuilder()
+ .environment(Environment.prod)
+ .endpoint("east", "qrs", east.region().value())
+ .region(west.region().value())
+ .region(central.region().value())
+ .region(east.region().value())
+ .allow(ValidationId.globalEndpointChange)
+ .build();
+ tester.deployCompletely(application, applicationPackage6, ++buildNumber);
}
@Test
@@ -464,6 +545,7 @@ public class ControllerTest {
.environment(Environment.prod)
.region("us-west-1")
.region("us-central-1") // Two deployments should result in each DNS alias being registered once
+ .allow(ValidationId.globalEndpointChange)
.build();
tester.deployCompletely(application, applicationPackage2, BuildJob.defaultBuildNumber + 1);
@@ -504,6 +586,7 @@ public class ControllerTest {
applicationPackage = new ApplicationPackageBuilder()
.environment(Environment.prod)
.allow(ValidationId.deploymentRemoval)
+ .allow(ValidationId.globalEndpointChange)
.build();
tester.jobCompletion(component).application(app1).nextBuildNumber().uploadArtifact(applicationPackage).submit();
tester.deployAndNotify(tester.defaultInstance(app1.id()).id(), Optional.of(applicationPackage), true, systemTest);
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 9449f2b0854..c352fc5550f 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
@@ -12,7 +12,6 @@ import com.yahoo.vespa.hosted.controller.application.ApplicationPackage;
import java.io.ByteArrayOutputStream;
import java.io.IOException;
import java.io.UncheckedIOException;
-import java.nio.charset.StandardCharsets;
import java.security.cert.X509Certificate;
import java.text.SimpleDateFormat;
import java.time.Duration;
@@ -20,9 +19,7 @@ import java.time.Instant;
import java.util.ArrayList;
import java.util.Arrays;
import java.util.Date;
-import java.util.LinkedHashMap;
import java.util.List;
-import java.util.Map;
import java.util.OptionalInt;
import java.util.StringJoiner;
import java.util.zip.ZipEntry;
@@ -80,14 +77,14 @@ public class ApplicationPackageBuilder {
}
public ApplicationPackageBuilder endpoint(String endpointId, String containerId, String... regions) {
- endpointsBody.append(" <endpoint");
+ endpointsBody.append(" <endpoint");
endpointsBody.append(" id='").append(endpointId).append("'");
endpointsBody.append(" container-id='").append(containerId).append("'");
endpointsBody.append(">\n");
for (var region : regions) {
- endpointsBody.append(" <region>").append(region).append("</region>\n");
+ endpointsBody.append(" <region>").append(region).append("</region>\n");
}
- endpointsBody.append(" </endpoint>\n");
+ endpointsBody.append(" </endpoint>\n");
return this;
}
diff --git a/controller-server/src/test/java/com/yahoo/vespa/hosted/controller/maintenance/RoutingPoliciesTest.java b/controller-server/src/test/java/com/yahoo/vespa/hosted/controller/maintenance/RoutingPoliciesTest.java
index 78a9be9f1d3..5e10bc3e5db 100644
--- a/controller-server/src/test/java/com/yahoo/vespa/hosted/controller/maintenance/RoutingPoliciesTest.java
+++ b/controller-server/src/test/java/com/yahoo/vespa/hosted/controller/maintenance/RoutingPoliciesTest.java
@@ -1,6 +1,7 @@
// Copyright 2019 Oath Inc. Licensed under the terms of the Apache 2.0 license. See LICENSE in the project root.
package com.yahoo.vespa.hosted.controller.maintenance;
+import com.yahoo.config.application.api.ValidationId;
import com.yahoo.config.provision.ApplicationId;
import com.yahoo.config.provision.ClusterSpec;
import com.yahoo.config.provision.HostName;
@@ -127,6 +128,7 @@ public class RoutingPoliciesTest {
.region(zone1.region())
.region(zone2.region())
.region(zone3.region())
+ .allow(ValidationId.globalEndpointChange)
.build();
tester.deployCompletely(app1, applicationPackage4, ++buildNumber);
assertEquals("DNS records are removed", List.of(), aliasDataOf(endpoint1));
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 ea96a839959..6ffe2fb83fc 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
@@ -5,6 +5,7 @@ import ai.vespa.hosted.api.MultiPartStreamer;
import ai.vespa.hosted.api.Signatures;
import com.yahoo.application.container.handler.Request;
import com.yahoo.component.Version;
+import com.yahoo.config.application.api.ValidationId;
import com.yahoo.config.provision.ApplicationId;
import com.yahoo.config.provision.AthenzService;
import com.yahoo.config.provision.ClusterSpec;
@@ -325,8 +326,10 @@ public class ApplicationApiTest extends ControllerContainerTest {
// POST (create) another application
ApplicationPackage applicationPackage = new ApplicationPackageBuilder()
.instances("instance1")
+ .globalServiceId("foo")
.environment(Environment.prod)
.region("us-west-1")
+ .allow(ValidationId.globalEndpointChange)
.build();
tester.assertResponse(request("/application/v4/tenant/tenant2/application/application2/instance/default", POST)
@@ -626,6 +629,7 @@ public class ApplicationApiTest extends ControllerContainerTest {
// Third attempt finally has a service under the domain of the tenant, and succeeds.
ApplicationPackage packageWithService = new ApplicationPackageBuilder()
.instances("instance1")
+ .globalServiceId("foo")
.environment(Environment.prod)
.athenzIdentity(com.yahoo.config.provision.AthenzDomain.from(ATHENZ_TENANT_DOMAIN.getName()), AthenzService.from("service"))
.region("us-west-1")