From 11d7ec6b4c909845d1f19ec9056a75c7571054d6 Mon Sep 17 00:00:00 2001 From: Bjørn Christian Seime Date: Mon, 12 Apr 2021 11:59:28 +0200 Subject: Add feature flag to enable HTTP/2 for jdisc --- .../com/yahoo/config/model/api/ModelContext.java | 1 + .../com/yahoo/vespa/model/container/Container.java | 5 ++++- .../model/container/http/ConnectorFactory.java | 9 ++++++--- .../http/ssl/HostedSslConnectorFactory.java | 21 +++++++++++++-------- .../container/http/xml/JettyConnectorBuilder.java | 4 ++-- .../model/container/xml/ContainerModelBuilder.java | 7 ++++--- .../config/server/deploy/ModelContextImpl.java | 3 +++ .../src/main/java/com/yahoo/vespa/flags/Flags.java | 7 +++++++ 8 files changed, 40 insertions(+), 17 deletions(-) diff --git a/config-model-api/src/main/java/com/yahoo/config/model/api/ModelContext.java b/config-model-api/src/main/java/com/yahoo/config/model/api/ModelContext.java index f15d700a398..ef491c039ba 100644 --- a/config-model-api/src/main/java/com/yahoo/config/model/api/ModelContext.java +++ b/config-model-api/src/main/java/com/yahoo/config/model/api/ModelContext.java @@ -90,6 +90,7 @@ public interface ModelContext { @ModelFeatureFlag(owners = {"tokle"}) default boolean tenantIamRole() { return false; } @ModelFeatureFlag(owners = {"vekterli"}) default int maxActivationInhibitedOutOfSyncGroups() { return 0; } @ModelFeatureFlag(owners = {"hmusum"}) default String jvmOmitStackTraceInFastThrowOption(ClusterSpec.Type type) { return ""; } + @ModelFeatureFlag(owners = {"bjorncs", "jonmv"}) default boolean enableJdiscHttp2() { return false; } } /** Warning: As elsewhere in this package, do not make backwards incompatible changes that will break old config models! */ 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 cd596038137..6ef29269bc1 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 @@ -79,6 +79,7 @@ public abstract class Container extends AbstractService implements private final ComponentGroup> components = new ComponentGroup<>(this, "components"); private final JettyHttpServer defaultHttpServer; + private final boolean enableJdiscHttp2; protected Container(AbstractConfigProducer parent, String name, int index, DeployState deployState) { this(parent, name, false, index, deployState); @@ -99,6 +100,8 @@ public abstract class Container extends AbstractService implements addChild(new SimpleComponent("com.yahoo.container.jdisc.ConfiguredApplication$ApplicationContext")); appendJvmOptions(jvmOmitStackTraceInFastThrowOption(deployState.featureFlags())); + + this.enableJdiscHttp2 = deployState.featureFlags().enableJdiscHttp2(); } protected String jvmOmitStackTraceInFastThrowOption(ModelContext.FeatureFlags featureFlags) { @@ -180,7 +183,7 @@ public abstract class Container extends AbstractService implements } private void initDefaultJettyConnector() { - defaultHttpServer.addConnector(new ConnectorFactory.Builder("SearchServer", getSearchPort()).build()); + defaultHttpServer.addConnector(new ConnectorFactory.Builder("SearchServer", getSearchPort()).enableHttp2(enableJdiscHttp2).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 989f911fc5e..9b0075c79c3 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 @@ -2,7 +2,6 @@ package com.yahoo.vespa.model.container.http; import com.yahoo.component.ComponentId; -import com.yahoo.container.bundle.BundleInstantiationSpecification; import com.yahoo.jdisc.http.ConnectorConfig; import com.yahoo.osgi.provider.model.ComponentModel; import com.yahoo.vespa.model.container.component.SimpleComponent; @@ -11,8 +10,6 @@ import com.yahoo.vespa.model.container.http.ssl.SslProvider; import java.util.Optional; -import static com.yahoo.component.ComponentSpecification.fromString; - /** * @author Einar M R Rosenvinge * @author bjorncs @@ -23,6 +20,7 @@ public class ConnectorFactory extends SimpleComponent implements ConnectorConfig private final String name; private final int listenPort; private final SslProvider sslProviderComponent; + private final boolean enableHttp2; private volatile ComponentId defaultRequestFilterChain; private volatile ComponentId defaultResponseFilterChain; @@ -35,6 +33,7 @@ public class ConnectorFactory extends SimpleComponent implements ConnectorConfig this.sslProviderComponent = builder.sslProvider != null ? builder.sslProvider : new DefaultSslProvider(name); this.defaultRequestFilterChain = builder.defaultRequestFilterChain; this.defaultResponseFilterChain = builder.defaultResponseFilterChain; + this.enableHttp2 = builder.enableHttp2 != null ? builder.enableHttp2 : false; addChild(sslProviderComponent); inject(sslProviderComponent); } @@ -43,6 +42,7 @@ public class ConnectorFactory extends SimpleComponent implements ConnectorConfig public void getConfig(ConnectorConfig.Builder connectorBuilder) { connectorBuilder.listenPort(listenPort); connectorBuilder.name(name); + connectorBuilder.http2Enabled(enableHttp2); sslProviderComponent.amendConnectorConfig(connectorBuilder); } @@ -69,6 +69,7 @@ public class ConnectorFactory extends SimpleComponent implements ConnectorConfig private SslProvider sslProvider; private ComponentId defaultRequestFilterChain; private ComponentId defaultResponseFilterChain; + private Boolean enableHttp2; public Builder(String name, int listenPort) { this.name = name; @@ -87,6 +88,8 @@ public class ConnectorFactory extends SimpleComponent implements ConnectorConfig this.defaultResponseFilterChain = filterChain; return this; } + public Builder enableHttp2(boolean enabled) { this.enableHttp2 = enabled; return this; } + public ConnectorFactory build() { return new ConnectorFactory(this); } diff --git a/config-model/src/main/java/com/yahoo/vespa/model/container/http/ssl/HostedSslConnectorFactory.java b/config-model/src/main/java/com/yahoo/vespa/model/container/http/ssl/HostedSslConnectorFactory.java index 30ebb843aa7..51570cac4a7 100644 --- a/config-model/src/main/java/com/yahoo/vespa/model/container/http/ssl/HostedSslConnectorFactory.java +++ b/config-model/src/main/java/com/yahoo/vespa/model/container/http/ssl/HostedSslConnectorFactory.java @@ -29,27 +29,32 @@ public class HostedSslConnectorFactory extends ConnectorFactory { * Create connector factory that uses a certificate provided by the config-model / configserver and default hosted Vespa truststore. */ public static HostedSslConnectorFactory withProvidedCertificate( - String serverName, EndpointCertificateSecrets endpointCertificateSecrets, boolean enforceHandshakeClientAuth) { - return new HostedSslConnectorFactory(createConfiguredDirectSslProvider(serverName, endpointCertificateSecrets, DEFAULT_HOSTED_TRUSTSTORE, /*tlsCaCertificates*/null, enforceHandshakeClientAuth), false, enforceHandshakeClientAuth); + String serverName, EndpointCertificateSecrets endpointCertificateSecrets, boolean enforceHandshakeClientAuth, boolean enableHttp2) { + ConfiguredDirectSslProvider sslProvider = createConfiguredDirectSslProvider( + serverName, endpointCertificateSecrets, DEFAULT_HOSTED_TRUSTSTORE, /*tlsCaCertificates*/null, enforceHandshakeClientAuth); + return new HostedSslConnectorFactory(sslProvider, false, enforceHandshakeClientAuth, enableHttp2); } /** * Create connector factory that uses a certificate provided by the config-model / configserver and a truststore configured by the application. */ public static HostedSslConnectorFactory withProvidedCertificateAndTruststore( - String serverName, EndpointCertificateSecrets endpointCertificateSecrets, String tlsCaCertificates) { - return new HostedSslConnectorFactory(createConfiguredDirectSslProvider(serverName, endpointCertificateSecrets, /*tlsCaCertificatesPath*/null, tlsCaCertificates, false), true, false); + String serverName, EndpointCertificateSecrets endpointCertificateSecrets, String tlsCaCertificates, boolean enableHttp2) { + ConfiguredDirectSslProvider sslProvider = createConfiguredDirectSslProvider( + serverName, endpointCertificateSecrets, /*tlsCaCertificatesPath*/null, tlsCaCertificates, false); + return new HostedSslConnectorFactory(sslProvider, true, false, enableHttp2); } /** * Create connector factory that uses the default certificate and truststore provided by Vespa (through Vespa-global TLS configuration). */ - public static HostedSslConnectorFactory withDefaultCertificateAndTruststore(String serverName) { - return new HostedSslConnectorFactory(new DefaultSslProvider(serverName), true, false); + public static HostedSslConnectorFactory withDefaultCertificateAndTruststore(String serverName, boolean enableHttp2) { + return new HostedSslConnectorFactory(new DefaultSslProvider(serverName), true, false, enableHttp2); } - private HostedSslConnectorFactory(SslProvider sslProvider, boolean enforceClientAuth, boolean enforceHandshakeClientAuth) { - super(new Builder("tls4443", 4443).sslProvider(sslProvider)); + private HostedSslConnectorFactory(SslProvider sslProvider, boolean enforceClientAuth, + boolean enforceHandshakeClientAuth, boolean enableHttp2) { + super(new Builder("tls4443", 4443).sslProvider(sslProvider).enableHttp2(enableHttp2)); this.enforceClientAuth = enforceClientAuth; this.enforceHandshakeClientAuth = enforceHandshakeClientAuth; } 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 c3f6264a8cc..3b616c34a03 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 @@ -28,7 +28,7 @@ import static java.util.stream.Collectors.toList; public class JettyConnectorBuilder extends VespaDomBuilder.DomConfigProducerBuilder { @Override - protected ConnectorFactory doBuild(DeployState deployState, AbstractConfigProducer ancestor, Element serverSpec) { + 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); @@ -39,7 +39,7 @@ public class JettyConnectorBuilder extends VespaDomBuilder.DomConfigProducerBuil .map(ComponentId::new) .ifPresent(builder::defaultResponseFilterChain); SslProvider sslProviderComponent = getSslConfigComponents(name, serverSpec); - return builder.sslProvider(sslProviderComponent).build(); + return builder.sslProvider(sslProviderComponent).enableHttp2(deployState.featureFlags().enableJdiscHttp2()).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 d7ef7fbb143..10ea7fb1838 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 @@ -431,6 +431,7 @@ public class ContainerModelBuilder extends ConfigModelBuilder { // If the deployment contains certificate/private key reference, setup TLS port HostedSslConnectorFactory connectorFactory; + boolean enableHttp2 = deployState.featureFlags().enableJdiscHttp2(); if (deployState.endpointCertificateSecrets().isPresent()) { boolean authorizeClient = deployState.zone().system().isPublic(); if (authorizeClient && deployState.tlsClientAuthority().isEmpty()) { @@ -444,10 +445,10 @@ public class ContainerModelBuilder extends ConfigModelBuilder { .orElse(false); connectorFactory = authorizeClient - ? HostedSslConnectorFactory.withProvidedCertificateAndTruststore(serverName, endpointCertificateSecrets, deployState.tlsClientAuthority().get()) - : HostedSslConnectorFactory.withProvidedCertificate(serverName, endpointCertificateSecrets, enforceHandshakeClientAuth); + ? HostedSslConnectorFactory.withProvidedCertificateAndTruststore(serverName, endpointCertificateSecrets, deployState.tlsClientAuthority().get(), enableHttp2) + : HostedSslConnectorFactory.withProvidedCertificate(serverName, endpointCertificateSecrets, enforceHandshakeClientAuth, enableHttp2); } else { - connectorFactory = HostedSslConnectorFactory.withDefaultCertificateAndTruststore(serverName); + connectorFactory = HostedSslConnectorFactory.withDefaultCertificateAndTruststore(serverName, enableHttp2); } cluster.getHttp().getAccessControl().ifPresent(accessControl -> accessControl.configureHostedConnector(connectorFactory)); server.addConnector(connectorFactory); diff --git a/configserver/src/main/java/com/yahoo/vespa/config/server/deploy/ModelContextImpl.java b/configserver/src/main/java/com/yahoo/vespa/config/server/deploy/ModelContextImpl.java index b4dd81ad7aa..20699a7211a 100644 --- a/configserver/src/main/java/com/yahoo/vespa/config/server/deploy/ModelContextImpl.java +++ b/configserver/src/main/java/com/yahoo/vespa/config/server/deploy/ModelContextImpl.java @@ -178,6 +178,7 @@ public class ModelContextImpl implements ModelContext { private final boolean tenantIamRole; private final int maxActivationInhibitedOutOfSyncGroups; private final ToIntFunction jvmOmitStackTraceInFastThrow; + private final boolean enableJdiscHttp2; public FeatureFlags(FlagSource source, ApplicationId appId) { this.dedicatedClusterControllerFlavor = parseDedicatedClusterControllerFlavor(flagValue(source, appId, Flags.DEDICATED_CLUSTER_CONTROLLER_FLAVOR)); @@ -202,6 +203,7 @@ public class ModelContextImpl implements ModelContext { this.tenantIamRole = flagValue(source, appId.tenant(), Flags.TENANT_IAM_ROLE); this.maxActivationInhibitedOutOfSyncGroups = flagValue(source, appId, Flags.MAX_ACTIVATION_INHIBITED_OUT_OF_SYNC_GROUPS); this.jvmOmitStackTraceInFastThrow = type -> flagValueAsInt(source, appId, type, PermanentFlags.JVM_OMIT_STACK_TRACE_IN_FAST_THROW); + this.enableJdiscHttp2 = flagValue(source, appId, Flags.ENABLE_JDISC_HTTP2); } @Override public Optional dedicatedClusterControllerFlavor() { return Optional.ofNullable(dedicatedClusterControllerFlavor); } @@ -228,6 +230,7 @@ public class ModelContextImpl implements ModelContext { @Override public String jvmOmitStackTraceInFastThrowOption(ClusterSpec.Type type) { return translateJvmOmitStackTraceInFastThrowIntToString(jvmOmitStackTraceInFastThrow, type); } + @Override public boolean enableJdiscHttp2() { return enableJdiscHttp2; } private static V flagValue(FlagSource source, ApplicationId appId, UnboundFlag flag) { return flag.bindTo(source) diff --git a/flags/src/main/java/com/yahoo/vespa/flags/Flags.java b/flags/src/main/java/com/yahoo/vespa/flags/Flags.java index 71111ed923e..2be74ed5ed4 100644 --- a/flags/src/main/java/com/yahoo/vespa/flags/Flags.java +++ b/flags/src/main/java/com/yahoo/vespa/flags/Flags.java @@ -266,6 +266,13 @@ public class Flags { "Whether HostRebuilder should rebuild hosts marked wantToRebuild", "Takes effect on next HostRebuilder maintenance run"); + public static final UnboundBooleanFlag ENABLE_JDISC_HTTP2 = defineFeatureFlag( + "enable-jdisc-http2", false, + List.of("bjorncs", "jonmv"), "2021-04-12", "2021-08-01", + "Whether jdisc HTTPS connectors should allow HTTP/2", + "Takes effect at redeployment", + APPLICATION_ID); + /** WARNING: public for testing: All flags should be defined in {@link Flags}. */ public static UnboundBooleanFlag defineFeatureFlag(String flagId, boolean defaultValue, List owners, String createdAt, String expiresAt, String description, -- cgit v1.2.3