diff options
author | Ola Aunronning <olaa@yahooinc.com> | 2023-05-19 11:06:30 +0200 |
---|---|---|
committer | Ola Aunronning <olaa@yahooinc.com> | 2023-05-19 11:06:30 +0200 |
commit | a89a6d9269fcdb23d907c92bb348c7a3655f9cae (patch) | |
tree | 93a6989e096e06aec3adb94df577c7f8f4b9f2eb | |
parent | 2853860a3c0b8884668b4d76ad90db50228b52cd (diff) |
Add dataplane proxy in config model
4 files changed, 97 insertions, 8 deletions
diff --git a/config-model/src/main/java/com/yahoo/vespa/model/container/DataplaneProxy.java b/config-model/src/main/java/com/yahoo/vespa/model/container/DataplaneProxy.java new file mode 100644 index 00000000000..a4fc7a59d5a --- /dev/null +++ b/config-model/src/main/java/com/yahoo/vespa/model/container/DataplaneProxy.java @@ -0,0 +1,52 @@ +// Copyright Yahoo. Licensed under the terms of the Apache 2.0 license. See LICENSE in the project root. +package com.yahoo.vespa.model.container; + +import com.yahoo.cloud.config.DataplaneProxyConfig; +import com.yahoo.config.model.producer.TreeConfigProducer; +import com.yahoo.vespa.model.AbstractService; +import com.yahoo.vespa.model.PortAllocBridge; + +import java.util.Optional; + +public class DataplaneProxy extends AbstractService implements DataplaneProxyConfig.Producer { + + private final Integer port; + + public DataplaneProxy(TreeConfigProducer<? super DataplaneProxy> parent, Integer port) { + super(parent, "dataplane-proxy"); + this.port = port; + setProp("clustertype", "hosts"); + setProp("clustername", "admin"); + } + + + // Does not need any ports. + @Override + public void allocatePorts(int start, PortAllocBridge from) { } + + /** + * + * @return The number of ports reserved + */ + public int getPortCount() { return 0; } + + /** + * @return The command used to start + */ + @Override + public Optional<String> getStartupCommand() { return Optional.of("exec $ROOT/bin/vespa-dataplane-proxy-start -c " + getConfigId()); } + + @Override + public void getConfig(DataplaneProxyConfig.Builder builder) { + builder.port(port); + } + + @Override + public Optional<String> getPreShutdownCommand() { + var builder = new DataplaneProxyConfig.Builder(); + getConfig(builder); + String cmd = "$ROOT/bin/vespa-dataplane-proxy-start -S -c " + getConfigId(); + return Optional.of(cmd); + } + +} 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 3cb0731c43a..c8bd661a00b 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 @@ -67,6 +67,7 @@ import com.yahoo.vespa.model.container.ContainerCluster; import com.yahoo.vespa.model.container.ContainerModel; import com.yahoo.vespa.model.container.ContainerModelEvaluation; import com.yahoo.vespa.model.container.ContainerThreadpool; +import com.yahoo.vespa.model.container.DataplaneProxy; import com.yahoo.vespa.model.container.IdentityProvider; import com.yahoo.vespa.model.container.PlatformBundles; import com.yahoo.vespa.model.container.SecretStore; @@ -459,19 +460,21 @@ public class ContainerModelBuilder extends ConfigModelBuilder<ContainerModel> { addDefaultConnectorHostedFilterBinding(cluster); addAdditionalHostedConnector(deployState, cluster); addCloudDataPlaneFilter(deployState, cluster); + addDataplaneProxy(deployState, cluster); } } private static void addCloudDataPlaneFilter(DeployState deployState, ApplicationContainerCluster cluster) { if (!deployState.isHosted() || !deployState.zone().system().isPublic()) return; + var dataplanePort = getDataplanePort(deployState); // Setup secure filter chain 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 cluster.getHttp().getHttpServer().orElseThrow().getConnectorFactories().stream() - .filter(c -> c.getListenPort() == HOSTED_VESPA_DATAPLANE_PORT).findAny().orElseThrow() + .filter(c -> c.getListenPort() == dataplanePort).findAny().orElseThrow() .setDefaultRequestFilterChain(secureChain.getComponentId()); // Setup insecure filter chain @@ -494,6 +497,28 @@ public class ContainerModelBuilder extends ConfigModelBuilder<ContainerModel> { } + private void addDataplaneProxy(DeployState deployState, ApplicationContainerCluster cluster) { + if (!deployState.featureFlags().enableDataplaneProxy()) + return; + + var tokenChain = new HttpFilterChain("cloud-data-plane-token", HttpFilterChain.Type.SYSTEM); + tokenChain.addInnerComponent(new Filter( + new ChainedComponentModel( + new BundleInstantiationSpecification( + new ComponentSpecification("com.yahoo.jdisc.http.filter.security.misc.BlockingRequestFilter"), + null, new ComponentSpecification("jdisc-security-filters")), + Dependencies.emptyDependencies()))); + + cluster.getHttp().getFilterChains().add(tokenChain); + + cluster.getContainers().forEach(container -> { + var hostResource = container.getHostResource(); + var dataplaneProxy = new DataplaneProxy(hostResource.getHost(), getDataplanePort(deployState)); + dataplaneProxy.setHostResource(hostResource); + dataplaneProxy.initService(deployState); + }); + } + protected void addClients(DeployState deployState, Element spec, ApplicationContainerCluster cluster) { if (!deployState.isHosted() || !deployState.zone().system().isPublic()) return; @@ -566,6 +591,7 @@ public class ContainerModelBuilder extends ConfigModelBuilder<ContainerModel> { Collection<String> tlsCiphersOverride = deployState.getProperties().tlsCiphersOverride(); boolean proxyProtocolMixedMode = deployState.getProperties().featureFlags().enableProxyProtocolMixedMode(); Duration endpointConnectionTtl = deployState.getProperties().endpointConnectionTtl(); + var port = getDataplanePort(deployState); if (deployState.endpointCertificateSecrets().isPresent()) { boolean authorizeClient = deployState.zone().system().isPublic(); List<X509Certificate> clientCertificates = getClientCertificates(cluster); @@ -583,13 +609,13 @@ public class ContainerModelBuilder extends ConfigModelBuilder<ContainerModel> { connectorFactory = authorizeClient ? HostedSslConnectorFactory.withProvidedCertificateAndTruststore( serverName, endpointCertificateSecrets, X509CertificateUtils.toPem(clientCertificates), - tlsCiphersOverride, proxyProtocolMixedMode, HOSTED_VESPA_DATAPLANE_PORT, endpointConnectionTtl) + tlsCiphersOverride, proxyProtocolMixedMode, port, endpointConnectionTtl) : HostedSslConnectorFactory.withProvidedCertificate( serverName, endpointCertificateSecrets, enforceHandshakeClientAuth, tlsCiphersOverride, - proxyProtocolMixedMode, HOSTED_VESPA_DATAPLANE_PORT, endpointConnectionTtl); + proxyProtocolMixedMode, port, endpointConnectionTtl); } else { connectorFactory = HostedSslConnectorFactory.withDefaultCertificateAndTruststore( - serverName, tlsCiphersOverride, proxyProtocolMixedMode, HOSTED_VESPA_DATAPLANE_PORT, + serverName, tlsCiphersOverride, proxyProtocolMixedMode, port, endpointConnectionTtl); } cluster.getHttp().getAccessControl().ifPresent(accessControl -> accessControl.configureHostedConnector(connectorFactory)); @@ -755,7 +781,7 @@ public class ContainerModelBuilder extends ConfigModelBuilder<ContainerModel> { } private void addUserHandlers(DeployState deployState, ApplicationContainerCluster cluster, Element spec, ConfigModelContext context) { - OptionalInt portBindingOverride = isHostedTenantApplication(context) ? OptionalInt.of(HOSTED_VESPA_DATAPLANE_PORT) : OptionalInt.empty(); + OptionalInt portBindingOverride = isHostedTenantApplication(context) ? OptionalInt.of(getDataplanePort(deployState)) : OptionalInt.empty(); for (Element component: XML.getChildren(spec, "handler")) { cluster.addComponent( new DomHandlerBuilder(cluster, portBindingOverride).build(deployState, cluster, component)); @@ -1047,7 +1073,7 @@ public class ContainerModelBuilder extends ConfigModelBuilder<ContainerModel> { private void addSearchHandler(DeployState deployState, ApplicationContainerCluster cluster, Element searchElement, ConfigModelContext context) { BindingPattern bindingPattern = SearchHandler.DEFAULT_BINDING; if (isHostedTenantApplication(context) && deployState.featureFlags().useRestrictedDataPlaneBindings()) { - bindingPattern = SearchHandler.bindingPattern(Optional.of(Integer.toString(HOSTED_VESPA_DATAPLANE_PORT))); + bindingPattern = SearchHandler.bindingPattern(Optional.of(Integer.toString(getDataplanePort(deployState)))); } SearchHandler searchHandler = new SearchHandler(cluster, serverBindings(deployState, context, searchElement, bindingPattern), @@ -1068,7 +1094,7 @@ public class ContainerModelBuilder extends ConfigModelBuilder<ContainerModel> { private List<BindingPattern> toBindingList(DeployState deployState, ConfigModelContext context, List<Element> bindingElements) { List<BindingPattern> result = new ArrayList<>(); - OptionalInt portOverride = isHostedTenantApplication(context) && deployState.featureFlags().useRestrictedDataPlaneBindings() ? OptionalInt.of(HOSTED_VESPA_DATAPLANE_PORT) : OptionalInt.empty(); + OptionalInt portOverride = isHostedTenantApplication(context) && deployState.featureFlags().useRestrictedDataPlaneBindings() ? OptionalInt.of(getDataplanePort(deployState)) : OptionalInt.empty(); for (Element element: bindingElements) { String text = element.getTextContent().trim(); if (!text.isEmpty()) @@ -1091,7 +1117,7 @@ public class ContainerModelBuilder extends ConfigModelBuilder<ContainerModel> { ContainerDocumentApi.HandlerOptions documentApiOptions = DocumentApiOptionsBuilder.build(documentApiElement); Element ignoreUndefinedFields = XML.getChild(documentApiElement, "ignore-undefined-fields"); OptionalInt portBindingOverride = deployState.featureFlags().useRestrictedDataPlaneBindings() && isHostedTenantApplication(context) - ? OptionalInt.of(HOSTED_VESPA_DATAPLANE_PORT) + ? OptionalInt.of(getDataplanePort(deployState)) : OptionalInt.empty(); return new ContainerDocumentApi(cluster, documentApiOptions, "true".equals(XML.getValue(ignoreUndefinedFields)), portBindingOverride); @@ -1354,4 +1380,9 @@ public class ContainerModelBuilder extends ConfigModelBuilder<ContainerModel> { } + private static int getDataplanePort(DeployState deployState) { + // TODO: Determine port + return deployState.featureFlags().enableDataplaneProxy() ? 9999 : HOSTED_VESPA_DATAPLANE_PORT; + } + } diff --git a/configdefinitions/src/vespa/CMakeLists.txt b/configdefinitions/src/vespa/CMakeLists.txt index 95e9a31cb73..6a737e6f57d 100644 --- a/configdefinitions/src/vespa/CMakeLists.txt +++ b/configdefinitions/src/vespa/CMakeLists.txt @@ -83,3 +83,5 @@ install_config_definition(onnx-models.def vespa.config.search.core.onnx-models.d vespa_generate_config(configdefinitions proton.def) install_config_definition(proton.def vespa.config.search.core.proton.def) vespa_generate_config(configdefinitions hwinfo.def) +vespa_generate_config(configdefinitions dataplane-proxy.def) +install_config_definition(dataplane-proxy.def cloud.config.dataplane-proxy.def)
\ No newline at end of file diff --git a/configdefinitions/src/vespa/dataplane-proxy.def b/configdefinitions/src/vespa/dataplane-proxy.def new file mode 100644 index 00000000000..bef2c8457f7 --- /dev/null +++ b/configdefinitions/src/vespa/dataplane-proxy.def @@ -0,0 +1,4 @@ +# Copyright Yahoo. Licensed under the terms of the Apache 2.0 license. See LICENSE in the project root. +namespace=cloud.config + +port int
\ No newline at end of file |