diff options
Diffstat (limited to 'config-model')
4 files changed, 93 insertions, 5 deletions
diff --git a/config-model/src/main/java/com/yahoo/config/model/test/MockApplicationPackage.java b/config-model/src/main/java/com/yahoo/config/model/test/MockApplicationPackage.java index 3b715c63105..dbcd1cea2fa 100644 --- a/config-model/src/main/java/com/yahoo/config/model/test/MockApplicationPackage.java +++ b/config-model/src/main/java/com/yahoo/config/model/test/MockApplicationPackage.java @@ -63,6 +63,7 @@ public class MockApplicationPackage implements ApplicationPackage { private final boolean failOnValidateXml; private final QueryProfileRegistry queryProfileRegistry; private final ApplicationMetaData applicationMetaData; + private final TenantName tenantName; private DeploymentSpec deploymentSpec = null; @@ -70,7 +71,7 @@ public class MockApplicationPackage implements ApplicationPackage { Map<Path, MockApplicationFile> files, String schemaDir, String deploymentSpec, String validationOverrides, boolean failOnValidateXml, - String queryProfile, String queryProfileType) { + String queryProfile, String queryProfileType, TenantName tenantName) { this.root = root; this.hostsS = hosts; this.servicesS = services; @@ -85,19 +86,20 @@ public class MockApplicationPackage implements ApplicationPackage { applicationMetaData = new ApplicationMetaData("dir", 0L, false, - ApplicationId.from(TenantName.defaultName(), + ApplicationId.from(tenantName, ApplicationName.from(APPLICATION_NAME), InstanceName.defaultName()), "checksum", APPLICATION_GENERATION, 0L); + this.tenantName = tenantName; } /** Returns the root of this application package relative to the current dir */ protected File root() { return root; } @Override - public ApplicationId getApplicationId() { return ApplicationId.from("default", "mock-application", "default"); } + public ApplicationId getApplicationId() { return ApplicationId.from(tenantName.value(), "mock-application", "default"); } @Override public Reader getServices() { @@ -246,6 +248,7 @@ public class MockApplicationPackage implements ApplicationPackage { private boolean failOnValidateXml = false; private String queryProfile = null; private String queryProfileType = null; + private TenantName tenantName = TenantName.defaultName(); public Builder() { } @@ -323,10 +326,15 @@ public class MockApplicationPackage implements ApplicationPackage { return this; } + public Builder withTenantname(TenantName tenantName) { + this.tenantName = tenantName; + return this; + } + public ApplicationPackage build() { return new MockApplicationPackage(root, hosts, services, schemas, files, schemaDir, deploymentSpec, validationOverrides, failOnValidateXml, - queryProfile, queryProfileType); + queryProfile, queryProfileType, tenantName); } } diff --git a/config-model/src/main/java/com/yahoo/vespa/model/application/validation/InfrastructureDeploymentValidator.java b/config-model/src/main/java/com/yahoo/vespa/model/application/validation/InfrastructureDeploymentValidator.java new file mode 100644 index 00000000000..842405e68f9 --- /dev/null +++ b/config-model/src/main/java/com/yahoo/vespa/model/application/validation/InfrastructureDeploymentValidator.java @@ -0,0 +1,30 @@ +// Copyright Yahoo. Licensed under the terms of the Apache 2.0 license. See LICENSE in the project root. +package com.yahoo.vespa.model.application.validation; + +import com.yahoo.config.model.ConfigModelContext; +import com.yahoo.config.model.deploy.DeployState; +import com.yahoo.config.provision.ApplicationId; +import com.yahoo.vespa.model.VespaModel; + +import java.util.logging.Logger; + +/** + * Validator to check that only infrastructure tenant can use non-default application-type + * + * @author mortent + */ +public class InfrastructureDeploymentValidator extends Validator { + + private static final Logger log = Logger.getLogger(InfrastructureDeploymentValidator.class.getName()); + + @Override + public void validate(VespaModel model, DeployState deployState) { + // Allow the internally defined tenant owning all infrastructure applications + if (ApplicationId.global().tenant().equals(model.applicationPackage().getApplicationId().tenant())) return; + ConfigModelContext.ApplicationType applicationType = model.getAdmin().getApplicationType(); + if (applicationType != ConfigModelContext.ApplicationType.DEFAULT) { + log.warning("Tenant %s is not allowed to use application type %s".formatted(model.applicationPackage().getApplicationId().toFullString(), applicationType)); + throw new IllegalArgumentException("Tenant is not allowed to override application type"); + } + } +} diff --git a/config-model/src/test/java/com/yahoo/schema/processing/RankingExpressionWithOnnxTestCase.java b/config-model/src/test/java/com/yahoo/schema/processing/RankingExpressionWithOnnxTestCase.java index 2f53dba7bb4..8db8f0710a0 100644 --- a/config-model/src/test/java/com/yahoo/schema/processing/RankingExpressionWithOnnxTestCase.java +++ b/config-model/src/test/java/com/yahoo/schema/processing/RankingExpressionWithOnnxTestCase.java @@ -4,6 +4,8 @@ package com.yahoo.schema.processing; import com.yahoo.config.application.api.ApplicationFile; import com.yahoo.config.application.api.ApplicationPackage; import com.yahoo.config.model.test.MockApplicationPackage; +import com.yahoo.config.provision.ApplicationId; +import com.yahoo.config.provision.TenantName; import com.yahoo.io.IOUtils; import com.yahoo.io.reader.NamedReader; import com.yahoo.path.Path; @@ -400,7 +402,7 @@ public class RankingExpressionWithOnnxTestCase { StoringApplicationPackage(Path applicationPackageWritableRoot, String queryProfile, String queryProfileType) { super(new File(applicationPackageWritableRoot.toString()), null, null, List.of(), Map.of(), null, - null, null, false, queryProfile, queryProfileType); + null, null, false, queryProfile, queryProfileType, TenantName.defaultName()); } @Override diff --git a/config-model/src/test/java/com/yahoo/vespa/model/application/validation/InfrastructureDeploymentValidatorTest.java b/config-model/src/test/java/com/yahoo/vespa/model/application/validation/InfrastructureDeploymentValidatorTest.java new file mode 100644 index 00000000000..0281d5cd6ee --- /dev/null +++ b/config-model/src/test/java/com/yahoo/vespa/model/application/validation/InfrastructureDeploymentValidatorTest.java @@ -0,0 +1,48 @@ +// Copyright Yahoo. Licensed under the terms of the Apache 2.0 license. See LICENSE in the project root. +package com.yahoo.vespa.model.application.validation; + +import com.yahoo.config.model.NullConfigModelRegistry; +import com.yahoo.config.model.deploy.DeployState; +import com.yahoo.config.model.test.MockApplicationPackage; +import com.yahoo.config.provision.ApplicationId; +import com.yahoo.config.provision.TenantName; +import com.yahoo.vespa.model.VespaModel; +import org.junit.jupiter.api.Test; +import org.xml.sax.SAXException; + +import java.io.IOException; + +import static org.junit.jupiter.api.Assertions.assertDoesNotThrow; +import static org.junit.jupiter.api.Assertions.assertEquals; +import static org.junit.jupiter.api.Assertions.assertThrows; + +public class InfrastructureDeploymentValidatorTest { + + @Test + public void allows_infrastructure_deployments() { + assertDoesNotThrow(() -> runValidator(ApplicationId.global().tenant())); + } + + @Test + public void prevents_non_infrastructure_deployments() { + IllegalArgumentException exception = assertThrows(IllegalArgumentException.class, () -> runValidator(TenantName.defaultName())); + assertEquals("Tenant is not allowed to override application type", exception.getMessage()); + } + + private void runValidator(TenantName tenantName) throws IOException, SAXException { + String services = """ + <services version='1.0' application-type="hosted-infrastructure"> + <container id='default' version='1.0' /> + </services> + """; + var app = new MockApplicationPackage.Builder() + .withTenantname(tenantName) + .withServices(services) + .build(); + var deployState = new DeployState.Builder().applicationPackage(app).build(); + var model = new VespaModel(new NullConfigModelRegistry(), deployState); + + var validator = new InfrastructureDeploymentValidator(); + validator.validate(model, deployState); + } +} |