summaryrefslogtreecommitdiffstats
path: root/config-model
diff options
context:
space:
mode:
authorBjørn Christian Seime <bjorncs@verizonmedia.com>2023-01-06 13:44:29 +0100
committerGitHub <noreply@github.com>2023-01-06 13:44:29 +0100
commitb75f439e480861ece1517353d7f22e356daa8d1d (patch)
treebb49cc8c619404fed48a8c8bfbc87e0cf10af8da /config-model
parent5e102423eb410449268bd5161e870f14d47de50d (diff)
parenta65f9f4a87aa56032eadb2c66ad7bd1a4970c447 (diff)
Merge pull request #25416 from vespa-engine/bjorncs/hosted-http-filter
Bjorncs/hosted http filter
Diffstat (limited to 'config-model')
-rw-r--r--config-model/src/main/java/com/yahoo/config/model/deploy/DeployState.java10
-rw-r--r--config-model/src/main/java/com/yahoo/config/model/deploy/TestProperties.java4
-rw-r--r--config-model/src/main/java/com/yahoo/vespa/model/application/validation/CloudUserFilterValidator.java50
-rw-r--r--config-model/src/main/java/com/yahoo/vespa/model/application/validation/UriBindingsValidator.java4
-rw-r--r--config-model/src/main/java/com/yahoo/vespa/model/application/validation/Validation.java1
-rw-r--r--config-model/src/main/java/com/yahoo/vespa/model/container/http/AccessControl.java5
-rw-r--r--config-model/src/main/java/com/yahoo/vespa/model/container/http/FilterChains.java9
-rw-r--r--config-model/src/main/java/com/yahoo/vespa/model/container/http/Http.java3
-rw-r--r--config-model/src/main/java/com/yahoo/vespa/model/container/http/HttpFilterChain.java27
-rw-r--r--config-model/src/main/java/com/yahoo/vespa/model/container/http/xml/FilterChainBuilder.java8
-rw-r--r--config-model/src/main/java/com/yahoo/vespa/model/container/http/xml/FilterChainsBuilder.java8
-rw-r--r--config-model/src/main/java/com/yahoo/vespa/model/container/xml/ContainerModelBuilder.java13
-rw-r--r--config-model/src/test/java/com/yahoo/vespa/model/application/validation/CloudUserFilterValidatorTest.java68
13 files changed, 179 insertions, 31 deletions
diff --git a/config-model/src/main/java/com/yahoo/config/model/deploy/DeployState.java b/config-model/src/main/java/com/yahoo/config/model/deploy/DeployState.java
index 985fc5fd22e..54521b946dd 100644
--- a/config-model/src/main/java/com/yahoo/config/model/deploy/DeployState.java
+++ b/config-model/src/main/java/com/yahoo/config/model/deploy/DeployState.java
@@ -11,6 +11,7 @@ import com.yahoo.config.application.api.DeployLogger;
import com.yahoo.config.application.api.FileRegistry;
import com.yahoo.config.application.api.UnparsedConfigDefinition;
import com.yahoo.config.application.api.ValidationOverrides;
+import com.yahoo.config.model.ConfigModelContext.ApplicationType;
import com.yahoo.config.model.api.ConfigDefinitionRepo;
import com.yahoo.config.model.api.ContainerEndpoint;
import com.yahoo.config.model.api.EndpointCertificateSecrets;
@@ -28,11 +29,11 @@ import com.yahoo.config.model.test.MockApplicationPackage;
import com.yahoo.config.provision.DockerImage;
import com.yahoo.config.provision.Zone;
import com.yahoo.io.IOUtils;
-import com.yahoo.search.query.profile.QueryProfileRegistry;
import com.yahoo.schema.Application;
+import com.yahoo.schema.ApplicationBuilder;
import com.yahoo.schema.RankProfileRegistry;
import com.yahoo.schema.Schema;
-import com.yahoo.schema.ApplicationBuilder;
+import com.yahoo.search.query.profile.QueryProfileRegistry;
import com.yahoo.vespa.config.ConfigDefinition;
import com.yahoo.vespa.config.ConfigDefinitionBuilder;
import com.yahoo.vespa.config.ConfigDefinitionKey;
@@ -302,6 +303,11 @@ public class DeployState implements ConfigDefinitionStore {
public Optional<Reindexing> reindexing() { return Optional.ofNullable(reindexing); }
+ public boolean isHostedTenantApplication(ApplicationType type) {
+ boolean isTesterApplication = getProperties().applicationId().instance().isTester();
+ return isHosted() && type == ApplicationType.DEFAULT && !isTesterApplication;
+ }
+
public static class Builder {
private ApplicationPackage applicationPackage = MockApplicationPackage.createEmpty();
diff --git a/config-model/src/main/java/com/yahoo/config/model/deploy/TestProperties.java b/config-model/src/main/java/com/yahoo/config/model/deploy/TestProperties.java
index 6b8428a07ac..fba2f711111 100644
--- a/config-model/src/main/java/com/yahoo/config/model/deploy/TestProperties.java
+++ b/config-model/src/main/java/com/yahoo/config/model/deploy/TestProperties.java
@@ -82,6 +82,7 @@ public class TestProperties implements ModelContext.Properties, ModelContext.Fea
private Architecture adminClusterNodeResourcesArchitecture = Architecture.getDefault();
private boolean useRestrictedDataPlaneBindings = false;
private Optional<CloudAccount> cloudAccount = Optional.empty();
+ private boolean allowUserFilters = true;
@Override public ModelContext.FeatureFlags featureFlags() { return this; }
@Override public boolean multitenant() { return multitenant; }
@@ -137,6 +138,7 @@ public class TestProperties implements ModelContext.Properties, ModelContext.Fea
@Override public boolean useTwoPhaseDocumentGc() { return useTwoPhaseDocumentGc; }
@Override public boolean useRestrictedDataPlaneBindings() { return useRestrictedDataPlaneBindings; }
@Override public Optional<CloudAccount> cloudAccount() { return cloudAccount; }
+ @Override public boolean allowUserFilters() { return allowUserFilters; }
public TestProperties sharedStringRepoNoReclaim(boolean sharedStringRepoNoReclaim) {
this.sharedStringRepoNoReclaim = sharedStringRepoNoReclaim;
@@ -366,6 +368,8 @@ public class TestProperties implements ModelContext.Properties, ModelContext.Fea
return this;
}
+ public TestProperties setAllowUserFilters(boolean b) { this.allowUserFilters = b; return this; }
+
public static class Spec implements ConfigServerSpec {
private final String hostName;
diff --git a/config-model/src/main/java/com/yahoo/vespa/model/application/validation/CloudUserFilterValidator.java b/config-model/src/main/java/com/yahoo/vespa/model/application/validation/CloudUserFilterValidator.java
new file mode 100644
index 00000000000..3d4a0e2c919
--- /dev/null
+++ b/config-model/src/main/java/com/yahoo/vespa/model/application/validation/CloudUserFilterValidator.java
@@ -0,0 +1,50 @@
+// 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.deploy.DeployState;
+import com.yahoo.vespa.model.VespaModel;
+import com.yahoo.vespa.model.container.http.HttpFilterChain;
+
+import java.util.Comparator;
+import java.util.TreeSet;
+import java.util.logging.Level;
+import java.util.stream.Collectors;
+
+/**
+ * Validates that only allowed-listed cloud applications can set up user-specified filter chains
+ *
+ * @author bjorncs
+ */
+public class CloudUserFilterValidator extends Validator {
+
+ @Override
+ public void validate(VespaModel model, DeployState state) {
+ if (!state.isHostedTenantApplication(model.getAdmin().getApplicationType())) return;
+ if (state.getProperties().allowUserFilters()) return;
+ var violations = new TreeSet<Violation>();
+ for (var cluster : model.getContainerClusters().values()) {
+ if (cluster.getHttp() == null) continue;
+ for (var chain : cluster.getHttp().getFilterChains().allChains().allComponents()) {
+ if (chain.type() == HttpFilterChain.Type.USER) {
+ var msg = "Found filter chain violation - chain '%s' in cluster '%s'".formatted(cluster.name(), chain.id());
+ state.getDeployLogger().log(Level.WARNING, msg);
+ violations.add(new Violation(cluster.name(), chain.id()));
+ }
+ }
+ }
+ if (violations.isEmpty()) return;
+ var violationsStr = violations.stream()
+ .map(v -> "chain '%s' in cluster '%s'".formatted(v.chain(), v.cluster()))
+ .collect(Collectors.joining(", ", "[", "]"));
+ var msg = ("HTTP filter chains are currently not supported in Vespa Cloud (%s)").formatted(violationsStr);
+ throw new IllegalArgumentException(msg);
+ }
+
+ private record Violation(String cluster, String chain) implements Comparable<Violation> {
+ @Override
+ public int compareTo(Violation other) {
+ return Comparator.comparing(Violation::chain).thenComparing(Violation::cluster).compare(this, other);
+ }
+ }
+
+}
diff --git a/config-model/src/main/java/com/yahoo/vespa/model/application/validation/UriBindingsValidator.java b/config-model/src/main/java/com/yahoo/vespa/model/application/validation/UriBindingsValidator.java
index a57a8fa9e70..f4aa4f649bd 100644
--- a/config-model/src/main/java/com/yahoo/vespa/model/application/validation/UriBindingsValidator.java
+++ b/config-model/src/main/java/com/yahoo/vespa/model/application/validation/UriBindingsValidator.java
@@ -12,8 +12,6 @@ import com.yahoo.vespa.model.container.http.Http;
import java.util.logging.Level;
-import static com.yahoo.config.model.ConfigModelContext.ApplicationType.HOSTED_INFRASTRUCTURE;
-
/**
* Validates URI bindings for filters and handlers
*
@@ -71,7 +69,7 @@ class UriBindingsValidator extends Validator {
}
private static boolean isHostedApplication(VespaModel model, DeployState deployState) {
- return deployState.isHosted() && model.getAdmin().getApplicationType() != HOSTED_INFRASTRUCTURE;
+ return deployState.isHostedTenantApplication(model.getAdmin().getApplicationType());
}
private static String createErrorMessage(BindingPattern binding, String message) {
diff --git a/config-model/src/main/java/com/yahoo/vespa/model/application/validation/Validation.java b/config-model/src/main/java/com/yahoo/vespa/model/application/validation/Validation.java
index a558902d6ff..877dd12104f 100644
--- a/config-model/src/main/java/com/yahoo/vespa/model/application/validation/Validation.java
+++ b/config-model/src/main/java/com/yahoo/vespa/model/application/validation/Validation.java
@@ -89,6 +89,7 @@ public class Validation {
new UriBindingsValidator().validate(model, deployState);
new CloudDataPlaneFilterValidator().validate(model, deployState);
new AccessControlFilterExcludeValidator().validate(model, deployState);
+ new CloudUserFilterValidator().validate(model, deployState);
additionalValidators.forEach(v -> v.validate(model, deployState));
diff --git a/config-model/src/main/java/com/yahoo/vespa/model/container/http/AccessControl.java b/config-model/src/main/java/com/yahoo/vespa/model/container/http/AccessControl.java
index 65164ac857b..6f4c35ad6ed 100644
--- a/config-model/src/main/java/com/yahoo/vespa/model/container/http/AccessControl.java
+++ b/config-model/src/main/java/com/yahoo/vespa/model/container/http/AccessControl.java
@@ -10,7 +10,6 @@ import com.yahoo.vespa.model.container.component.BindingPattern;
import com.yahoo.vespa.model.container.component.FileStatusHandlerComponent;
import com.yahoo.vespa.model.container.component.Handler;
import com.yahoo.vespa.model.container.component.SystemBindingPattern;
-import com.yahoo.vespa.model.container.component.chain.Chain;
import com.yahoo.vespa.model.container.http.ssl.HostedSslConnectorFactory;
import java.util.Collection;
@@ -144,7 +143,7 @@ public class AccessControl {
// Add a filter chain used by default hosted connector
private void addDefaultHostedRequestChain(Http http) {
- Chain<Filter> chain = createChain(DEFAULT_CONNECTOR_HOSTED_REQUEST_CHAIN_ID);
+ HttpFilterChain chain = createChain(DEFAULT_CONNECTOR_HOSTED_REQUEST_CHAIN_ID);
http.getFilterChains().add(chain);
}
@@ -184,7 +183,7 @@ public class AccessControl {
rewrittenBinding);
}
- private static Chain<Filter> createChain(ComponentId id) { return new Chain<>(FilterChains.emptyChainSpec(id)); }
+ private static HttpFilterChain createChain(ComponentId id) { return new HttpFilterChain(id, HttpFilterChain.Type.SYSTEM); }
private static boolean isExcludedHandler(Handler handler) { return EXCLUDED_HANDLERS.contains(handler.getClassId().getName()); }
diff --git a/config-model/src/main/java/com/yahoo/vespa/model/container/http/FilterChains.java b/config-model/src/main/java/com/yahoo/vespa/model/container/http/FilterChains.java
index 2139fd731e2..64506ed60e8 100644
--- a/config-model/src/main/java/com/yahoo/vespa/model/container/http/FilterChains.java
+++ b/config-model/src/main/java/com/yahoo/vespa/model/container/http/FilterChains.java
@@ -6,7 +6,6 @@ import com.yahoo.component.ComponentSpecification;
import com.yahoo.component.chain.model.ChainSpecification;
import com.yahoo.config.model.producer.AbstractConfigProducer;
import com.yahoo.vespa.model.container.component.SimpleComponent;
-import com.yahoo.vespa.model.container.component.chain.Chain;
import com.yahoo.vespa.model.container.component.chain.Chains;
import java.util.Set;
@@ -14,16 +13,16 @@ import java.util.Set;
/**
* @author Tony Vaagenes
*/
-public class FilterChains extends Chains<Chain<Filter>> {
+public class FilterChains extends Chains<HttpFilterChain> {
- public FilterChains(AbstractConfigProducer parent) {
+ public FilterChains(AbstractConfigProducer<?> parent) {
super(parent, "filters");
addChild(new SimpleComponent("com.yahoo.container.http.filter.FilterChainRepository"));
}
public boolean hasChain(ComponentId filterChain) {
- for (Chain<Filter> chain : allChains().allComponents()) {
+ for (HttpFilterChain chain : allChains().allComponents()) {
if (chain.getId().equals(filterChain))
return true;
}
@@ -31,7 +30,7 @@ public class FilterChains extends Chains<Chain<Filter>> {
}
public boolean hasChainThatInherits(ComponentId filterChain) {
- for (Chain<Filter> chain : allChains().allComponents()) {
+ for (HttpFilterChain chain : allChains().allComponents()) {
for (ComponentSpecification spec : chain.getChainSpecification().inheritance.chainSpecifications) {
if(spec.toId().equals(filterChain))
return true;
diff --git a/config-model/src/main/java/com/yahoo/vespa/model/container/http/Http.java b/config-model/src/main/java/com/yahoo/vespa/model/container/http/Http.java
index eea3ec68cc0..e6096dc75b3 100644
--- a/config-model/src/main/java/com/yahoo/vespa/model/container/http/Http.java
+++ b/config-model/src/main/java/com/yahoo/vespa/model/container/http/Http.java
@@ -4,7 +4,6 @@ package com.yahoo.vespa.model.container.http;
import com.yahoo.component.provider.ComponentRegistry;
import com.yahoo.config.model.producer.AbstractConfigProducer;
import com.yahoo.jdisc.http.ServerConfig;
-import com.yahoo.vespa.model.container.component.chain.Chain;
import com.yahoo.vespa.model.container.component.chain.ChainedComponent;
import java.util.Collection;
@@ -99,7 +98,7 @@ public class Http extends AbstractConfigProducer<AbstractConfigProducer<?>> impl
throw new IllegalArgumentException("Null FilterChains are not allowed when there are filter bindings");
ComponentRegistry<ChainedComponent<?>> filters = filterChains.componentsRegistry();
- ComponentRegistry<Chain<Filter>> chains = filterChains.allChains();
+ var chains = filterChains.allChains();
for (FilterBinding binding: bindings) {
if (filters.getComponent(binding.chainId()) == null && chains.getComponent(binding.chainId()) == null)
diff --git a/config-model/src/main/java/com/yahoo/vespa/model/container/http/HttpFilterChain.java b/config-model/src/main/java/com/yahoo/vespa/model/container/http/HttpFilterChain.java
new file mode 100644
index 00000000000..2a1c4d1665c
--- /dev/null
+++ b/config-model/src/main/java/com/yahoo/vespa/model/container/http/HttpFilterChain.java
@@ -0,0 +1,27 @@
+// Copyright Yahoo. Licensed under the terms of the Apache 2.0 license. See LICENSE in the project root.
+package com.yahoo.vespa.model.container.http;
+
+import com.yahoo.component.ComponentId;
+import com.yahoo.component.chain.model.ChainSpecification;
+import com.yahoo.vespa.model.container.component.chain.Chain;
+
+/**
+ * @author bjorncs
+ */
+public class HttpFilterChain extends Chain<Filter> {
+
+ public enum Type { USER, SYSTEM }
+
+ private final Type type;
+
+ public HttpFilterChain(ChainSpecification inner, Type type) {
+ super(inner);
+ this.type = type;
+ }
+
+ public HttpFilterChain(ComponentId id, Type type) { this(FilterChains.emptyChainSpec(id), type); }
+ public HttpFilterChain(String id, Type type) { this(ComponentId.fromString(id), type); }
+
+ public Type type() { return type; }
+ public String id() { return getComponentId().stringValue(); }
+}
diff --git a/config-model/src/main/java/com/yahoo/vespa/model/container/http/xml/FilterChainBuilder.java b/config-model/src/main/java/com/yahoo/vespa/model/container/http/xml/FilterChainBuilder.java
index 293480e6c7f..7b81b3052a4 100644
--- a/config-model/src/main/java/com/yahoo/vespa/model/container/http/xml/FilterChainBuilder.java
+++ b/config-model/src/main/java/com/yahoo/vespa/model/container/http/xml/FilterChainBuilder.java
@@ -5,8 +5,8 @@ import com.yahoo.component.chain.model.ChainSpecification;
import com.yahoo.config.model.deploy.DeployState;
import com.yahoo.config.model.producer.AbstractConfigProducer;
import com.yahoo.vespa.model.builder.xml.dom.chains.DomChainBuilderBase;
-import com.yahoo.vespa.model.container.component.chain.Chain;
import com.yahoo.vespa.model.container.http.Filter;
+import com.yahoo.vespa.model.container.http.HttpFilterChain;
import org.w3c.dom.Element;
import java.util.Collection;
@@ -18,7 +18,7 @@ import static com.yahoo.vespa.model.builder.xml.dom.chains.ComponentsBuilder.Com
/**
* @author Tony Vaagenes
*/
-public class FilterChainBuilder extends DomChainBuilderBase<Filter, Chain<Filter>> {
+public class FilterChainBuilder extends DomChainBuilderBase<Filter, HttpFilterChain> {
private static final Collection<ComponentType<Filter>> allowedComponentTypes = Collections.singleton(ComponentType.filter);
@@ -27,7 +27,7 @@ public class FilterChainBuilder extends DomChainBuilderBase<Filter, Chain<Filter
}
@Override
- protected Chain<Filter> buildChain(DeployState deployState, AbstractConfigProducer<?> ancestor, Element producerSpec, ChainSpecification specWithoutInnerComponents) {
- return new Chain<>(specWithoutInnerComponents);
+ protected HttpFilterChain buildChain(DeployState deployState, AbstractConfigProducer<?> ancestor, Element producerSpec, ChainSpecification specWithoutInnerComponents) {
+ return new HttpFilterChain(specWithoutInnerComponents, HttpFilterChain.Type.USER);
}
}
diff --git a/config-model/src/main/java/com/yahoo/vespa/model/container/http/xml/FilterChainsBuilder.java b/config-model/src/main/java/com/yahoo/vespa/model/container/http/xml/FilterChainsBuilder.java
index 35a91fc95ab..6325ee8da05 100644
--- a/config-model/src/main/java/com/yahoo/vespa/model/container/http/xml/FilterChainsBuilder.java
+++ b/config-model/src/main/java/com/yahoo/vespa/model/container/http/xml/FilterChainsBuilder.java
@@ -8,9 +8,9 @@ import com.yahoo.vespa.model.builder.xml.dom.chains.ComponentsBuilder;
import com.yahoo.vespa.model.builder.xml.dom.chains.ComponentsBuilder.ComponentType;
import com.yahoo.vespa.model.builder.xml.dom.chains.DomChainBuilderBase;
import com.yahoo.vespa.model.builder.xml.dom.chains.DomChainsBuilder;
-import com.yahoo.vespa.model.container.component.chain.Chain;
import com.yahoo.vespa.model.container.http.Filter;
import com.yahoo.vespa.model.container.http.FilterChains;
+import com.yahoo.vespa.model.container.http.HttpFilterChain;
import org.w3c.dom.Element;
import java.util.Collection;
@@ -21,11 +21,11 @@ import java.util.Map;
/**
* @author Tony Vaagenes
*/
-public class FilterChainsBuilder extends DomChainsBuilder<Filter, Chain<Filter>, FilterChains> {
+public class FilterChainsBuilder extends DomChainsBuilder<Filter, HttpFilterChain, FilterChains> {
private static final Collection<ComponentType<Filter>> allowedComponentTypes =
Collections.singleton(ComponentType.filter);
- private static final Map<String, Class<? extends DomChainBuilderBase<? extends Filter, ? extends Chain<Filter>>>> chainType2BuilderClass =
+ private static final Map<String, Class<? extends DomChainBuilderBase<? extends Filter, ? extends HttpFilterChain>>> chainType2BuilderClass =
Map.of(
HttpBuilder.REQUEST_CHAIN_TAG_NAME, FilterChainBuilder.class,
HttpBuilder.RESPONSE_CHAIN_TAG_NAME, FilterChainBuilder.class);
@@ -40,7 +40,7 @@ public class FilterChainsBuilder extends DomChainsBuilder<Filter, Chain<Filter>,
}
@Override
- protected ChainsBuilder<Filter, Chain<Filter>> readChains(
+ protected ChainsBuilder<Filter, HttpFilterChain> readChains(
DeployState deployState,
AbstractConfigProducer<?> ancestor,
List<Element> allChainsElems, Map<String, ComponentsBuilder.ComponentType<?>> outerComponentTypeByComponentName) {
diff --git a/config-model/src/main/java/com/yahoo/vespa/model/container/xml/ContainerModelBuilder.java b/config-model/src/main/java/com/yahoo/vespa/model/container/xml/ContainerModelBuilder.java
index f48f91e8cd0..d0a03be2869 100644
--- a/config-model/src/main/java/com/yahoo/vespa/model/container/xml/ContainerModelBuilder.java
+++ b/config-model/src/main/java/com/yahoo/vespa/model/container/xml/ContainerModelBuilder.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.model.container.xml;
-import com.yahoo.component.ComponentId;
import com.yahoo.component.ComponentSpecification;
import com.yahoo.component.Version;
import com.yahoo.component.chain.dependencies.Dependencies;
@@ -13,7 +12,6 @@ import com.yahoo.config.application.api.DeployLogger;
import com.yahoo.config.application.api.DeploymentInstanceSpec;
import com.yahoo.config.application.api.DeploymentSpec;
import com.yahoo.config.model.ConfigModelContext;
-import com.yahoo.config.model.ConfigModelContext.ApplicationType;
import com.yahoo.config.model.api.ApplicationClusterEndpoint;
import com.yahoo.config.model.api.ConfigServerSpec;
import com.yahoo.config.model.api.ContainerEndpoint;
@@ -77,7 +75,6 @@ import com.yahoo.vespa.model.container.component.Handler;
import com.yahoo.vespa.model.container.component.SimpleComponent;
import com.yahoo.vespa.model.container.component.SystemBindingPattern;
import com.yahoo.vespa.model.container.component.UserBindingPattern;
-import com.yahoo.vespa.model.container.component.chain.Chain;
import com.yahoo.vespa.model.container.docproc.ContainerDocproc;
import com.yahoo.vespa.model.container.docproc.DocprocChains;
import com.yahoo.vespa.model.container.http.AccessControl;
@@ -90,6 +87,7 @@ import com.yahoo.vespa.model.container.http.Http;
import com.yahoo.vespa.model.container.http.JettyHttpServer;
import com.yahoo.vespa.model.container.http.ssl.HostedSslConnectorFactory;
import com.yahoo.vespa.model.container.http.xml.HttpBuilder;
+import com.yahoo.vespa.model.container.http.HttpFilterChain;
import com.yahoo.vespa.model.container.processing.ProcessingChains;
import com.yahoo.vespa.model.container.search.ContainerSearch;
import com.yahoo.vespa.model.container.search.PageTemplates;
@@ -98,6 +96,7 @@ import com.yahoo.vespa.model.container.xml.document.DocumentFactoryBuilder;
import com.yahoo.vespa.model.content.StorageGroup;
import org.w3c.dom.Element;
import org.w3c.dom.Node;
+
import java.io.IOException;
import java.io.Reader;
import java.net.URI;
@@ -462,7 +461,7 @@ public class ContainerModelBuilder extends ConfigModelBuilder<ContainerModel> {
if (!deployState.isHosted() || !deployState.zone().system().isPublic()) return;
// Setup secure filter chain
- var secureChain = new Chain<Filter>(FilterChains.emptyChainSpec(ComponentId.fromString("cloud-data-plane-secure")));
+ var secureChain = new HttpFilterChain("cloud-data-plane-secure", HttpFilterChain.Type.SYSTEM);
secureChain.addInnerComponent(new CloudDataPlaneFilter(cluster, cluster.clientsLegacyMode()));
cluster.getHttp().getFilterChains().add(secureChain);
// Set cloud data plane filter as default request filter chain for data plane connector
@@ -471,7 +470,7 @@ public class ContainerModelBuilder extends ConfigModelBuilder<ContainerModel> {
.setDefaultRequestFilterChain(secureChain.getComponentId());
// Setup insecure filter chain
- var insecureChain = new Chain<Filter>(FilterChains.emptyChainSpec(ComponentId.fromString("cloud-data-plane-insecure")));
+ var insecureChain = new HttpFilterChain("cloud-data-plane-insecure", HttpFilterChain.Type.SYSTEM);
insecureChain.addInnerComponent(new Filter(
new ChainedComponentModel(
new BundleInstantiationSpecification(
@@ -597,9 +596,7 @@ public class ContainerModelBuilder extends ConfigModelBuilder<ContainerModel> {
}
private static boolean isHostedTenantApplication(ConfigModelContext context) {
- var deployState = context.getDeployState();
- boolean isTesterApplication = deployState.getProperties().applicationId().instance().isTester();
- return deployState.isHosted() && context.getApplicationType() == ApplicationType.DEFAULT && !isTesterApplication;
+ return context.getDeployState().isHostedTenantApplication(context.getApplicationType());
}
private static void addHostedImplicitHttpIfNotPresent(DeployState deployState, ApplicationContainerCluster cluster) {
diff --git a/config-model/src/test/java/com/yahoo/vespa/model/application/validation/CloudUserFilterValidatorTest.java b/config-model/src/test/java/com/yahoo/vespa/model/application/validation/CloudUserFilterValidatorTest.java
new file mode 100644
index 00000000000..62a8b1131fa
--- /dev/null
+++ b/config-model/src/test/java/com/yahoo/vespa/model/application/validation/CloudUserFilterValidatorTest.java
@@ -0,0 +1,68 @@
+// 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.application.api.ApplicationPackage;
+import com.yahoo.config.model.NullConfigModelRegistry;
+import com.yahoo.config.model.deploy.DeployState;
+import com.yahoo.config.model.deploy.TestProperties;
+import com.yahoo.config.model.test.MockApplicationPackage;
+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;
+
+/**
+ * @author bjorncs
+ */
+class CloudUserFilterValidatorTest {
+
+ @Test
+ void fails_on_user_configured_filter_chain() {
+ var exception = assertThrows(IllegalArgumentException.class, () -> runValidatorOnApp(true, ""));
+ var expected = "HTTP filter chains are currently not supported in Vespa Cloud ([chain 'myChain' in cluster 'container'])";
+ assertEquals(expected, exception.getMessage());
+ }
+
+ @Test
+ void allows_user_configured_filter_chain_for_infrastructure_app() {
+ assertDoesNotThrow(() -> runValidatorOnApp(true, " application-type='hosted-infrastructure'"));
+ }
+
+ @Test
+ void allows_user_configured_filter_chain_for_self_hosted() {
+ assertDoesNotThrow(() -> runValidatorOnApp(false, ""));
+ }
+
+ private static void runValidatorOnApp(boolean isHosted, String applicationTypeAttribute) throws IOException, SAXException {
+ String servicesXml = """
+ <services version='1.0'%s>
+ <container version='1.0'>
+ <http>
+ <filtering>
+ <request-chain id='myChain'>
+ <filter id='myFilter'/>
+ <binding>http://*/search/</binding>
+ </request-chain>
+ </filtering>
+ </http>
+ </container>
+ </services>
+ """.formatted(applicationTypeAttribute);
+ ApplicationPackage app = new MockApplicationPackage.Builder()
+ .withServices(servicesXml)
+ .build();
+ DeployState deployState = new DeployState.Builder()
+ .applicationPackage(app)
+ .properties(new TestProperties().setHostedVespa(isHosted).setAllowUserFilters(false))
+ .build();
+ VespaModel model = new VespaModel(new NullConfigModelRegistry(), deployState);
+ new CloudUserFilterValidator().validate(model, deployState);
+ }
+
+} \ No newline at end of file