diff options
author | Martin Polden <mpolden@mpolden.no> | 2022-08-17 11:37:07 +0200 |
---|---|---|
committer | Martin Polden <mpolden@mpolden.no> | 2022-08-17 11:37:07 +0200 |
commit | 265dad4b6c20059978edd4b9f5ebe17ea4712764 (patch) | |
tree | d0478d66f61bc0597a369e7e6947070f88ffdfb8 | |
parent | 7431909f44dcdf905cd81c3032e5322551abcff1 (diff) |
Require that requested region is configured in cloud account
4 files changed, 48 insertions, 8 deletions
diff --git a/controller-api/src/main/java/com/yahoo/vespa/hosted/controller/api/integration/zone/ZoneRegistry.java b/controller-api/src/main/java/com/yahoo/vespa/hosted/controller/api/integration/zone/ZoneRegistry.java index 8b4c00e9b9d..e0524091c39 100644 --- a/controller-api/src/main/java/com/yahoo/vespa/hosted/controller/api/integration/zone/ZoneRegistry.java +++ b/controller-api/src/main/java/com/yahoo/vespa/hosted/controller/api/integration/zone/ZoneRegistry.java @@ -4,6 +4,7 @@ package com.yahoo.vespa.hosted.controller.api.integration.zone; import com.yahoo.config.provision.ApplicationId; import com.yahoo.config.provision.ApplicationName; import com.yahoo.config.provision.AthenzDomain; +import com.yahoo.config.provision.CloudAccount; import com.yahoo.config.provision.CloudName; import com.yahoo.config.provision.Environment; import com.yahoo.config.provision.NodeType; @@ -34,6 +35,9 @@ public interface ZoneRegistry { /** Returns whether the system of this registry contains the given zone */ boolean hasZone(ZoneId zoneId); + /** Returns whether cloudAccount in this system supports given zone */ + boolean hasZone(ZoneId zoneId, CloudAccount cloudAccount); + /** Returns a list containing the id of all zones in this registry */ ZoneFilter zones(); diff --git a/controller-server/src/main/java/com/yahoo/vespa/hosted/controller/application/pkg/ApplicationPackageValidator.java b/controller-server/src/main/java/com/yahoo/vespa/hosted/controller/application/pkg/ApplicationPackageValidator.java index 281ac50e63a..b3df417bd80 100644 --- a/controller-server/src/main/java/com/yahoo/vespa/hosted/controller/application/pkg/ApplicationPackageValidator.java +++ b/controller-server/src/main/java/com/yahoo/vespa/hosted/controller/application/pkg/ApplicationPackageValidator.java @@ -11,6 +11,7 @@ import com.yahoo.config.provision.CloudAccount; 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.TenantName; import com.yahoo.config.provision.zone.ZoneApi; import com.yahoo.config.provision.zone.ZoneId; @@ -54,8 +55,8 @@ public class ApplicationPackageValidator { * @throws IllegalArgumentException if any validations fail */ public void validate(Application application, ApplicationPackage applicationPackage, Instant instant) { - validateSteps(applicationPackage.deploymentSpec()); validateCloudAccounts(application, applicationPackage.deploymentSpec()); + validateSteps(applicationPackage.deploymentSpec()); validateEndpointRegions(applicationPackage.deploymentSpec()); validateEndpointChange(application, applicationPackage, instant); validateCompactedEndpoint(applicationPackage); @@ -88,12 +89,22 @@ public class ApplicationPackageValidator { private void validateSteps(DeploymentSpec deploymentSpec) { for (var spec : deploymentSpec.instances()) { for (var zone : spec.zones()) { - if (zone.environment().isManuallyDeployed()) - throw new IllegalArgumentException("region must be one with automated deployments, but got: " + zone.environment()); + Environment environment = zone.environment(); + if (environment.isManuallyDeployed()) + throw new IllegalArgumentException("region must be one with automated deployments, but got: " + environment); - if ( zone.environment() == Environment.prod - && ! controller.zoneRegistry().hasZone(ZoneId.from(zone.environment(), zone.region().orElseThrow()))) - throw new IllegalArgumentException("Zone " + zone + " in deployment spec was not found in this system!"); + if (environment == Environment.prod) { + RegionName region = zone.region().orElseThrow(); + if (!controller.zoneRegistry().hasZone(ZoneId.from(environment, region))) { + throw new IllegalArgumentException("Zone " + zone + " in deployment spec was not found in this system!"); + } + Optional<CloudAccount> cloudAccount = spec.cloudAccount(environment, region); + if (cloudAccount.isPresent() && !controller.zoneRegistry().hasZone(ZoneId.from(environment, region), cloudAccount.get())) { + throw new IllegalArgumentException("Zone " + zone + " in deployment spec is not configured for " + + "use in cloud account '" + cloudAccount.get().value() + + "', in this system"); + } + } } } } 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 b5177cd1d3e..6c193e9b539 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 @@ -9,6 +9,7 @@ import com.yahoo.config.application.api.ValidationOverrides; import com.yahoo.config.provision.ApplicationId; import com.yahoo.config.provision.AthenzDomain; import com.yahoo.config.provision.AthenzService; +import com.yahoo.config.provision.CloudAccount; import com.yahoo.config.provision.CloudName; import com.yahoo.config.provision.ClusterSpec; import com.yahoo.config.provision.Environment; @@ -1194,13 +1195,25 @@ public class ControllerTest { .cloudAccount(cloudAccount) .region(zone.region()) .build(); + // Deployment fails because cloud account is not declared for this tenant try { context.submit(applicationPackage).deploy(); - fail("Expected exception"); // Account invalid for tenant - } catch (IllegalArgumentException ignored) { + fail("Expected exception"); + } catch (IllegalArgumentException e) { + assertEquals("Cloud account '012345678912' is not valid for tenant 'tenant'", e.getMessage()); } + // Deployment fails because requested region is not configured in cloud account tester.controllerTester().flagSource().withListFlag(PermanentFlags.CLOUD_ACCOUNTS.id(), List.of(cloudAccount), String.class); + try { + context.submit(applicationPackage).deploy(); + fail("Expected exception"); + } catch (IllegalArgumentException e) { + assertEquals("Zone prod.us-west-1 in deployment spec is not configured for use in cloud account '012345678912', in this system", e.getMessage()); + } + + // Deployment succeeds + tester.controllerTester().zoneRegistry().setCloudAccountZones(new CloudAccount(cloudAccount), zone); context.submit(applicationPackage).deploy(); assertEquals(cloudAccount, tester.controllerTester().configServer().cloudAccount(context.deploymentIdIn(zone)).get().value()); } 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 4131bfd8b9f..680e69998b6 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 @@ -5,6 +5,7 @@ import com.yahoo.component.AbstractComponent; import com.yahoo.config.provision.ApplicationId; import com.yahoo.config.provision.ApplicationName; import com.yahoo.config.provision.AthenzDomain; +import com.yahoo.config.provision.CloudAccount; import com.yahoo.config.provision.CloudName; import com.yahoo.config.provision.Environment; import com.yahoo.config.provision.NodeType; @@ -43,6 +44,7 @@ public class ZoneRegistryMock extends AbstractComponent implements ZoneRegistry private final Map<Environment, RegionName> defaultRegionForEnvironment = new HashMap<>(); private final Map<CloudName, UpgradePolicy> osUpgradePolicies = new HashMap<>(); private final Map<ZoneApi, List<RoutingMethod>> zoneRoutingMethods = new HashMap<>(); + private final Map<CloudAccount, Set<ZoneId>> cloudAccountZones = new HashMap<>(); private final Set<ZoneApi> reprovisionToUpgradeOs = new HashSet<>(); private final SystemName system; // Don't even think about making it non-final! ƪ(`▿▿▿▿´ƪ) @@ -146,6 +148,11 @@ public class ZoneRegistryMock extends AbstractComponent implements ZoneRegistry return this; } + public ZoneRegistryMock setCloudAccountZones(CloudAccount cloudAccount, ZoneId... zones) { + this.cloudAccountZones.put(cloudAccount, Set.of(zones)); + return this; + } + @Override public SystemName system() { return system; @@ -254,6 +261,11 @@ public class ZoneRegistryMock extends AbstractComponent implements ZoneRegistry } @Override + public boolean hasZone(ZoneId zoneId, CloudAccount cloudAccount) { + return hasZone(zoneId) && cloudAccountZones.getOrDefault(cloudAccount, Set.of()).contains(zoneId); + } + + @Override public URI getConfigServerVipUri(ZoneId zoneId) { return URI.create(Text.format("https://cfg.%s.test.vip:4443/", zoneId.value())); } |