From f0a6e9ec11836851e3029ca5f63b93243484059a Mon Sep 17 00:00:00 2001 From: Bjørn Christian Seime Date: Wed, 18 Nov 2020 12:37:35 +0100 Subject: Support default request/response filter chain per connector --- config-model/pom.xml | 5 ++ .../com/yahoo/vespa/model/container/Container.java | 2 +- .../model/container/http/ConnectorFactory.java | 65 +++++++++++++++++--- .../com/yahoo/vespa/model/container/http/Http.java | 16 +++++ .../container/http/xml/JettyConnectorBuilder.java | 11 +++- .../model/container/xml/ContainerModelBuilder.java | 2 +- .../model/container/http/DefaultFilterTest.java | 69 ++++++++++++++++++++++ 7 files changed, 158 insertions(+), 12 deletions(-) create mode 100644 config-model/src/test/java/com/yahoo/vespa/model/container/http/DefaultFilterTest.java (limited to 'config-model') diff --git a/config-model/pom.xml b/config-model/pom.xml index c0751431d03..56517b63884 100644 --- a/config-model/pom.xml +++ b/config-model/pom.xml @@ -45,6 +45,11 @@ guava-testlib test + + org.assertj + assertj-core + test + com.google.protobuf protobuf-java diff --git a/config-model/src/main/java/com/yahoo/vespa/model/container/Container.java b/config-model/src/main/java/com/yahoo/vespa/model/container/Container.java index a7f5398c7b5..e8b56a6190a 100644 --- a/config-model/src/main/java/com/yahoo/vespa/model/container/Container.java +++ b/config-model/src/main/java/com/yahoo/vespa/model/container/Container.java @@ -172,7 +172,7 @@ public abstract class Container extends AbstractService implements } private void initDefaultJettyConnector() { - defaultHttpServer.addConnector(new ConnectorFactory("SearchServer", getSearchPort())); + defaultHttpServer.addConnector(new ConnectorFactory.Builder("SearchServer", getSearchPort()).build()); } private ContainerServiceType myServiceType = null; diff --git a/config-model/src/main/java/com/yahoo/vespa/model/container/http/ConnectorFactory.java b/config-model/src/main/java/com/yahoo/vespa/model/container/http/ConnectorFactory.java index 2633fa958eb..9eab99af4d0 100644 --- a/config-model/src/main/java/com/yahoo/vespa/model/container/http/ConnectorFactory.java +++ b/config-model/src/main/java/com/yahoo/vespa/model/container/http/ConnectorFactory.java @@ -9,6 +9,8 @@ import com.yahoo.vespa.model.container.component.SimpleComponent; import com.yahoo.vespa.model.container.http.ssl.DefaultSslProvider; import com.yahoo.vespa.model.container.http.ssl.SslProvider; +import java.util.Optional; + import static com.yahoo.component.ComponentSpecification.fromString; /** @@ -21,21 +23,29 @@ public class ConnectorFactory extends SimpleComponent implements ConnectorConfig private final String name; private final int listenPort; private final SslProvider sslProviderComponent; + private volatile ComponentId defaultRequestFilterChain; + private volatile ComponentId defaultResponseFilterChain; - public ConnectorFactory(String name, int listenPort) { - this(name, listenPort, new DefaultSslProvider(name)); + protected ConnectorFactory(String name, int listenPort, SslProvider sslProviderComponent) { + this(name, listenPort, sslProviderComponent, null, null); } - public ConnectorFactory(String name, - int listenPort, - SslProvider sslProviderComponent) { + protected ConnectorFactory( + String name, + int listenPort, + SslProvider sslProviderComponent, + ComponentId defaultRequestFilterChain, + ComponentId defaultResponseFilterChain) { super(new ComponentModel( - new BundleInstantiationSpecification(new ComponentId(name), - fromString("com.yahoo.jdisc.http.server.jetty.ConnectorFactory"), - fromString("jdisc_http_service")))); + new BundleInstantiationSpecification( + new ComponentId(name), + fromString("com.yahoo.jdisc.http.server.jetty.ConnectorFactory"), + fromString("jdisc_http_service")))); this.name = name; this.listenPort = listenPort; this.sslProviderComponent = sslProviderComponent; + this.defaultRequestFilterChain = defaultRequestFilterChain; + this.defaultResponseFilterChain = defaultResponseFilterChain; addChild(sslProviderComponent); inject(sslProviderComponent); } @@ -55,4 +65,43 @@ public class ConnectorFactory extends SimpleComponent implements ConnectorConfig return listenPort; } + public Optional getDefaultRequestFilterChain() { return Optional.ofNullable(defaultRequestFilterChain); } + + public Optional getDefaultResponseFilterChain() { return Optional.ofNullable(defaultResponseFilterChain); } + + public void setDefaultRequestFilterChain(ComponentId filterChain) { this.defaultRequestFilterChain = filterChain; } + + public void setDefaultResponseFilterChain(ComponentId filterChain) { this.defaultResponseFilterChain = filterChain; } + + public static class Builder { + private final String name; + private final int listenPort; + + private SslProvider sslProvider; + private ComponentId defaultRequestFilterChain; + private ComponentId defaultResponseFilterChain; + + public Builder(String name, int listenPort) { + this.name = name; + this.listenPort = listenPort; + } + + public Builder setSslProvider(SslProvider sslProvider) { + this.sslProvider = sslProvider; return this; + } + + public Builder setDefaultRequestFilterChain(ComponentId filterChain) { + this.defaultRequestFilterChain = filterChain; return this; + } + + public Builder setDefaultResponseFilterChain(ComponentId filterChain) { + this.defaultResponseFilterChain = filterChain; + return this; + } + + public ConnectorFactory build() { + SslProvider sslProvider = this.sslProvider != null ? this.sslProvider : new DefaultSslProvider(name); + return new ConnectorFactory(name, listenPort, sslProvider, defaultRequestFilterChain, defaultResponseFilterChain); + } + } } 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 f58f5faa382..1ed043857e2 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 @@ -79,6 +79,7 @@ public class Http extends AbstractConfigProducer> impl .id(binding.chainId().stringValue()) .binding(binding.binding().patternString())); } + populateDefaultFiltersConfig(builder, httpServer); } @Override @@ -96,4 +97,19 @@ public class Http extends AbstractConfigProducer> impl throw new RuntimeException("Can't find filter " + binding.chainId() + " for binding " + binding.binding()); } } + + private static void populateDefaultFiltersConfig(ServerConfig.Builder builder, JettyHttpServer httpServer) { + if (httpServer != null) { + for (ConnectorFactory connector : httpServer.getConnectorFactories()) { + connector.getDefaultRequestFilterChain().ifPresent( + filterChain -> builder.defaultFilters(new ServerConfig.DefaultFilters.Builder() + .filterId(filterChain.stringValue()) + .localPort(connector.getListenPort()))); + connector.getDefaultResponseFilterChain().ifPresent( + filterChain -> builder.defaultFilters(new ServerConfig.DefaultFilters.Builder() + .filterId(filterChain.stringValue()) + .localPort(connector.getListenPort()))); + } + } + } } diff --git a/config-model/src/main/java/com/yahoo/vespa/model/container/http/xml/JettyConnectorBuilder.java b/config-model/src/main/java/com/yahoo/vespa/model/container/http/xml/JettyConnectorBuilder.java index 505cc81c0cb..9f25550418e 100644 --- a/config-model/src/main/java/com/yahoo/vespa/model/container/http/xml/JettyConnectorBuilder.java +++ b/config-model/src/main/java/com/yahoo/vespa/model/container/http/xml/JettyConnectorBuilder.java @@ -1,6 +1,7 @@ // Copyright 2017 Yahoo Holdings. Licensed under the terms of the Apache 2.0 license. See LICENSE in the project root. package com.yahoo.vespa.model.container.http.xml; +import com.yahoo.component.ComponentId; import com.yahoo.config.model.builder.xml.XmlHelper; import com.yahoo.config.model.deploy.DeployState; import com.yahoo.config.model.producer.AbstractConfigProducer; @@ -30,9 +31,15 @@ public class JettyConnectorBuilder extends VespaDomBuilder.DomConfigProducerBuil protected ConnectorFactory doBuild(DeployState deployState, AbstractConfigProducer ancestor, Element serverSpec) { String name = XmlHelper.getIdString(serverSpec); int port = HttpBuilder.readPort(new ModelElement(serverSpec), deployState.isHosted(), deployState.getDeployLogger()); - + ConnectorFactory.Builder builder = new ConnectorFactory.Builder(name, port); + XmlHelper.getOptionalAttribute(serverSpec, "default-request-chain") + .map(ComponentId::new) + .ifPresent(builder::setDefaultRequestFilterChain); + XmlHelper.getOptionalAttribute(serverSpec, "default-response-chain") + .map(ComponentId::new) + .ifPresent(builder::setDefaultResponseFilterChain); SslProvider sslProviderComponent = getSslConfigComponents(name, serverSpec); - return new ConnectorFactory(name, port, sslProviderComponent); + return builder.setSslProvider(sslProviderComponent).build(); } SslProvider getSslConfigComponents(String serverName, Element serverSpec) { 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 fc604c6174a..c8f2bd08ea5 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 @@ -362,7 +362,7 @@ public class ContainerModelBuilder extends ConfigModelBuilder { if(cluster.getHttp().getHttpServer().isEmpty()) { JettyHttpServer defaultHttpServer = new JettyHttpServer(new ComponentId("DefaultHttpServer"), cluster, cluster.isHostedVespa()); cluster.getHttp().setHttpServer(defaultHttpServer); - defaultHttpServer.addConnector(new ConnectorFactory("SearchServer", Defaults.getDefaults().vespaWebServicePort())); + defaultHttpServer.addConnector(new ConnectorFactory.Builder("SearchServer", Defaults.getDefaults().vespaWebServicePort()).build()); } } diff --git a/config-model/src/test/java/com/yahoo/vespa/model/container/http/DefaultFilterTest.java b/config-model/src/test/java/com/yahoo/vespa/model/container/http/DefaultFilterTest.java new file mode 100644 index 00000000000..e5c01989c22 --- /dev/null +++ b/config-model/src/test/java/com/yahoo/vespa/model/container/http/DefaultFilterTest.java @@ -0,0 +1,69 @@ +// Copyright Verizon Media. 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.config.model.builder.xml.test.DomBuilderTest; +import com.yahoo.config.model.deploy.DeployState; +import com.yahoo.container.core.ChainsConfig; +import com.yahoo.jdisc.http.ServerConfig; +import com.yahoo.vespa.model.container.component.BindingPattern; +import com.yahoo.vespa.model.container.component.UserBindingPattern; +import com.yahoo.vespa.model.container.xml.ContainerModelBuilder; +import org.junit.Test; +import org.w3c.dom.Element; + +import java.util.Set; + +import static java.util.stream.Collectors.toSet; +import static org.assertj.core.api.Assertions.assertThat; + +/** + * @author bjorncs + */ +public class DefaultFilterTest extends DomBuilderTest { + + private void buildContainerCluster(Element containerElem) { + new ContainerModelBuilder(true, ContainerModelBuilder.Networking.enable).build(DeployState.createTestState(), null, null, root, containerElem); + root.freezeModelTopology(); + } + + @Test + public void default_request_and_response_filters_in_services_xml_are_listen_in_server_config() { + BindingPattern binding = UserBindingPattern.fromHttpPath("/my-chain-binding"); + Element xml = parse( + "", + " ", + " ", + " ", + " " + binding.patternString() + "", + " ", + " ", + " " + binding.patternString() + "", + " ", + " " + + " ", + " ", + " ", + " ", + " ", + ""); + buildContainerCluster(xml); + + assertDefaultFiltersInConfig(root.getConfig(ServerConfig.class, "container/http/jdisc-jetty/server1")); + assertDefaultFiltersInConfig(root.getConfig(ServerConfig.class, "container/http/jdisc-jetty/server2")); + + ChainsConfig chainsConfig = root.getConfig(ChainsConfig.class, "container/filters/chain"); + Set chainsIds = chainsConfig.chains().stream().map(ChainsConfig.Chains::id).collect(toSet()); + assertThat(chainsIds) + .containsExactlyInAnyOrder( + "request-chain-with-binding", "response-chain-with-binding", "my-default-request-chain", "my-default-response-chain"); + } + + private static void assertDefaultFiltersInConfig(ServerConfig config) { + assertThat(config.defaultFilters()) + .containsExactlyInAnyOrder( + new ServerConfig.DefaultFilters(new ServerConfig.DefaultFilters.Builder() + .filterId("my-default-request-chain").localPort(8000)), + new ServerConfig.DefaultFilters(new ServerConfig.DefaultFilters.Builder() + .filterId("my-default-response-chain").localPort(8000))); + } +} -- cgit v1.2.3