diff options
56 files changed, 368 insertions, 144 deletions
diff --git a/config-model/src/main/java/com/yahoo/vespa/model/container/search/ContainerSearch.java b/config-model/src/main/java/com/yahoo/vespa/model/container/search/ContainerSearch.java index e19d81e7fb2..77916921fe4 100644 --- a/config-model/src/main/java/com/yahoo/vespa/model/container/search/ContainerSearch.java +++ b/config-model/src/main/java/com/yahoo/vespa/model/container/search/ContainerSearch.java @@ -59,6 +59,7 @@ public class ContainerSearch extends ContainerSubsystem<SearchChains> for (AbstractSearchCluster searchCluster : searchClusters) { if ( ! ( searchCluster instanceof IndexedSearchCluster)) continue; owningCluster.addComponent(new DispatcherComponent((IndexedSearchCluster)searchCluster)); + owningCluster.addComponent(new RpcResourcePoolComponent((IndexedSearchCluster)searchCluster)); } } diff --git a/config-model/src/main/java/com/yahoo/vespa/model/container/search/RpcResourcePoolComponent.java b/config-model/src/main/java/com/yahoo/vespa/model/container/search/RpcResourcePoolComponent.java new file mode 100644 index 00000000000..0291da611e8 --- /dev/null +++ b/config-model/src/main/java/com/yahoo/vespa/model/container/search/RpcResourcePoolComponent.java @@ -0,0 +1,31 @@ +// Copyright 2020 Oath Inc. Licensed under the terms of the Apache 2.0 license. See LICENSE in the project root. +package com.yahoo.vespa.model.container.search; + +import com.yahoo.osgi.provider.model.ComponentModel; +import com.yahoo.vespa.config.search.DispatchConfig; +import com.yahoo.vespa.model.container.component.Component; +import com.yahoo.vespa.model.container.xml.BundleMapper; +import com.yahoo.vespa.model.search.IndexedSearchCluster; + +public class RpcResourcePoolComponent extends Component<RpcResourcePoolComponent, ComponentModel> + implements DispatchConfig.Producer { + private final IndexedSearchCluster indexedSearchCluster; + + public RpcResourcePoolComponent(IndexedSearchCluster indexedSearchCluster) { + super(toComponentModel(indexedSearchCluster)); + this.indexedSearchCluster = indexedSearchCluster; + } + + @Override + public void getConfig(DispatchConfig.Builder builder) { + indexedSearchCluster.getConfig(builder); + } + + private static ComponentModel toComponentModel(IndexedSearchCluster indexedSearchCluster) { + String componentId = "rpcresourcepool." + indexedSearchCluster.getClusterName(); // used by Dispatcher + return new ComponentModel(componentId, + "com.yahoo.search.dispatch.rpc.RpcResourcePool", + BundleMapper.searchAndDocprocBundle, + null); + } +} diff --git a/config-model/src/test/java/com/yahoo/vespa/model/search/test/SearchClusterTest.java b/config-model/src/test/java/com/yahoo/vespa/model/search/test/SearchClusterTest.java index 1c4e005cb67..c5bf5153369 100644 --- a/config-model/src/test/java/com/yahoo/vespa/model/search/test/SearchClusterTest.java +++ b/config-model/src/test/java/com/yahoo/vespa/model/search/test/SearchClusterTest.java @@ -18,7 +18,6 @@ import com.yahoo.vespa.model.VespaModel; import com.yahoo.vespa.model.container.ContainerCluster; import com.yahoo.vespa.model.container.component.Component; import com.yahoo.vespa.model.search.AbstractSearchCluster; -import com.yahoo.vespa.model.search.SearchCluster; import com.yahoo.vespa.model.test.utils.ApplicationPackageUtils; import com.yahoo.vespa.model.test.utils.VespaModelCreatorWithMockPkg; import org.junit.Test; @@ -160,23 +159,28 @@ public class SearchClusterTest { AbstractSearchCluster searchCluster2 = model.getSearchClusters().get(xbulkIndex); assertEquals("xbulk", searchCluster2.getClusterName()); - Component<?,?> normalDispatcher = (Component<?, ?>)containerCluster1.getComponentsMap().get(new ComponentId("dispatcher.normal")); - assertNotNull(normalDispatcher); - assertEquals("dispatcher.normal", normalDispatcher.getComponentId().stringValue()); - assertEquals("com.yahoo.search.dispatch.Dispatcher", normalDispatcher.getClassId().stringValue()); - assertEquals("j1/component/dispatcher.normal", normalDispatcher.getConfigId()); - DispatchConfig.Builder normalDispatchConfigBuilder = new DispatchConfig.Builder(); - model.getConfig(normalDispatchConfigBuilder, "j1/component/dispatcher.normal"); - assertEquals("node2host", normalDispatchConfigBuilder.build().node(0).host()); - - Component<?,?> xbulkDispatcher = (Component<?, ?>)containerCluster1.getComponentsMap().get(new ComponentId("dispatcher.xbulk")); - assertNotNull(xbulkDispatcher); - assertEquals("dispatcher.xbulk", xbulkDispatcher.getComponentId().stringValue()); - assertEquals("com.yahoo.search.dispatch.Dispatcher", xbulkDispatcher.getClassId().stringValue()); - assertEquals("j1/component/dispatcher.xbulk", xbulkDispatcher.getConfigId()); - DispatchConfig.Builder xbulkDispatchConfigBuilder = new DispatchConfig.Builder(); - model.getConfig(xbulkDispatchConfigBuilder, "j1/component/dispatcher.xbulk"); - assertEquals("node0host", xbulkDispatchConfigBuilder.build().node(0).host()); + verifyDispatch(model, containerCluster1, "normal", "node2host"); + verifyDispatch(model, containerCluster1, "xbulk", "node0host"); + } + + private void verifyDispatch(VespaModel model, ContainerCluster containerCluster, String cluster, String host) { + Component<?,?> dispatcher = (Component<?, ?>)containerCluster.getComponentsMap().get(new ComponentId("dispatcher." + cluster)); + assertNotNull(dispatcher); + assertEquals("dispatcher." + cluster, dispatcher.getComponentId().stringValue()); + assertEquals("com.yahoo.search.dispatch.Dispatcher", dispatcher.getClassId().stringValue()); + assertEquals("j1/component/dispatcher." + cluster, dispatcher.getConfigId()); + DispatchConfig.Builder dispatchConfigBuilder = new DispatchConfig.Builder(); + model.getConfig(dispatchConfigBuilder, "j1/component/dispatcher." + cluster); + assertEquals(host, dispatchConfigBuilder.build().node(0).host()); + + Component<?,?> rpcResourcePool = (Component<?, ?>)containerCluster.getComponentsMap().get(new ComponentId("rpcresourcepool." + cluster)); + assertNotNull(dispatcher); + assertEquals("rpcresourcepool." + cluster, rpcResourcePool.getComponentId().stringValue()); + assertEquals("com.yahoo.search.dispatch.rpc.RpcResourcePool", rpcResourcePool.getClassId().stringValue()); + assertEquals("j1/component/rpcresourcepool."+cluster, rpcResourcePool.getConfigId()); + DispatchConfig.Builder rpcResourcePoolDispatchConfigBuilder = new DispatchConfig.Builder(); + model.getConfig(rpcResourcePoolDispatchConfigBuilder, "j1/component/rpcresourcepool." + cluster); + assertEquals(host, rpcResourcePoolDispatchConfigBuilder.build().node(0).host()); } } diff --git a/config-proxy/src/main/sh/vespa-config-ctl.sh b/config-proxy/src/main/sh/vespa-config-ctl.sh index a17f0abed92..3998d4f69d6 100755 --- a/config-proxy/src/main/sh/vespa-config-ctl.sh +++ b/config-proxy/src/main/sh/vespa-config-ctl.sh @@ -113,7 +113,7 @@ case $1 in if [ "$userargs" == "" ]; then userargs=$services__jvmargs_configproxy fi - jvmopts="-Xms32M -Xmx256M -XX:ThreadStackSize=256 -XX:MaxJavaStackTraceDepth=1000000" + jvmopts="-Xms32M -Xmx256M -XX:CompressedClassSpaceSize=32m -XX:MaxDirectMemorySize=32m -XX:ThreadStackSize=256 -XX:MaxJavaStackTraceDepth=1000" VESPA_SERVICE_NAME=configproxy export VESPA_SERVICE_NAME @@ -122,6 +122,7 @@ case $1 in java ${jvmopts} \ -XX:+ExitOnOutOfMemoryError $(getJavaOptionsIPV46) \ -Dproxyconfigsources="${configsources}" ${userargs} \ + -XX:ActiveProcessorCount=2 \ -cp $cp com.yahoo.vespa.config.proxy.ProxyServer 19090 echo "Waiting for config proxy to start" diff --git a/container-search/src/main/java/com/yahoo/search/dispatch/Dispatcher.java b/container-search/src/main/java/com/yahoo/search/dispatch/Dispatcher.java index 6ef41eefd12..abe6fffba39 100644 --- a/container-search/src/main/java/com/yahoo/search/dispatch/Dispatcher.java +++ b/container-search/src/main/java/com/yahoo/search/dispatch/Dispatcher.java @@ -83,18 +83,11 @@ public class Dispatcher extends AbstractComponent { public static QueryProfileType getArgumentType() { return argumentType; } @Inject - public Dispatcher(ComponentId clusterId, + public Dispatcher(RpcResourcePool resourcePool, + ComponentId clusterId, DispatchConfig dispatchConfig, VipStatus vipStatus, Metric metric) { - this(new RpcResourcePool(dispatchConfig), clusterId, dispatchConfig, vipStatus, metric); - } - - private Dispatcher(RpcResourcePool resourcePool, - ComponentId clusterId, - DispatchConfig dispatchConfig, - VipStatus vipStatus, - Metric metric) { this(resourcePool, new SearchCluster(clusterId.stringValue(), dispatchConfig, vipStatus, new RpcPingFactory(resourcePool)), dispatchConfig, metric); diff --git a/container-search/src/main/java/com/yahoo/search/dispatch/rpc/RpcInvokerFactory.java b/container-search/src/main/java/com/yahoo/search/dispatch/rpc/RpcInvokerFactory.java index a45ec59c3ee..74bc9e8bfbb 100644 --- a/container-search/src/main/java/com/yahoo/search/dispatch/rpc/RpcInvokerFactory.java +++ b/container-search/src/main/java/com/yahoo/search/dispatch/rpc/RpcInvokerFactory.java @@ -1,25 +1,19 @@ // Copyright 2019 Oath Inc. Licensed under the terms of the Apache 2.0 license. See LICENSE in the project root. package com.yahoo.search.dispatch.rpc; -import com.yahoo.prelude.Pong; import com.yahoo.prelude.fastsearch.DocumentDatabase; import com.yahoo.prelude.fastsearch.VespaBackEndSearcher; import com.yahoo.processing.request.CompoundName; import com.yahoo.search.Query; import com.yahoo.search.Result; -import com.yahoo.search.cluster.ClusterMonitor; import com.yahoo.search.dispatch.Dispatcher; import com.yahoo.search.dispatch.FillInvoker; import com.yahoo.search.dispatch.InvokerFactory; import com.yahoo.search.dispatch.SearchInvoker; import com.yahoo.search.dispatch.searchcluster.Node; -import com.yahoo.search.dispatch.searchcluster.PingFactory; -import com.yahoo.search.dispatch.searchcluster.Pinger; -import com.yahoo.search.dispatch.searchcluster.PongHandler; import com.yahoo.search.dispatch.searchcluster.SearchCluster; import java.util.Optional; -import java.util.concurrent.Callable; /** * @author ollivir @@ -62,7 +56,4 @@ public class RpcInvokerFactory extends InvokerFactory { return new RpcFillInvoker(rpcResourcePool, documentDb); } - public void release() { - rpcResourcePool.release(); - } } diff --git a/container-search/src/main/java/com/yahoo/search/dispatch/rpc/RpcResourcePool.java b/container-search/src/main/java/com/yahoo/search/dispatch/rpc/RpcResourcePool.java index ca2a0c9bfb0..065489ef9a0 100644 --- a/container-search/src/main/java/com/yahoo/search/dispatch/rpc/RpcResourcePool.java +++ b/container-search/src/main/java/com/yahoo/search/dispatch/rpc/RpcResourcePool.java @@ -2,6 +2,9 @@ package com.yahoo.search.dispatch.rpc; import com.google.common.collect.ImmutableMap; +import com.google.inject.Inject; +import com.yahoo.component.AbstractComponent; +import com.yahoo.component.ComponentId; import com.yahoo.compress.CompressionType; import com.yahoo.compress.Compressor; import com.yahoo.compress.Compressor.Compression; @@ -23,7 +26,7 @@ import java.util.Random; * * @author ollivir */ -public class RpcResourcePool { +public class RpcResourcePool extends AbstractComponent { /** The compression method which will be used with rpc dispatch. "lz4" (default) and "none" is supported. */ public final static CompoundName dispatchCompression = new CompoundName("dispatch.compression"); @@ -33,13 +36,15 @@ public class RpcResourcePool { /** Connections to the search nodes this talks to, indexed by node id ("partid") */ private final ImmutableMap<Integer, NodeConnectionPool> nodeConnectionPools; - public RpcResourcePool(Map<Integer, NodeConnection> nodeConnections) { + RpcResourcePool(Map<Integer, NodeConnection> nodeConnections) { var builder = new ImmutableMap.Builder<Integer, NodeConnectionPool>(); nodeConnections.forEach((key, connection) -> builder.put(key, new NodeConnectionPool(Collections.singletonList(connection)))); this.nodeConnectionPools = builder.build(); } + @Inject public RpcResourcePool(DispatchConfig dispatchConfig) { + super(); var client = new RpcClient(dispatchConfig.numJrtTransportThreads()); // Create rpc node connection pools indexed by the node distribution key @@ -73,7 +78,9 @@ public class RpcResourcePool { } } - public void release() { + @Override + public void deconstruct() { + super.deconstruct(); nodeConnectionPools.values().forEach(NodeConnectionPool::release); } diff --git a/container-search/src/main/java/com/yahoo/search/dispatch/rpc/RpcSearchInvoker.java b/container-search/src/main/java/com/yahoo/search/dispatch/rpc/RpcSearchInvoker.java index 07d8439ff46..76240e55c98 100644 --- a/container-search/src/main/java/com/yahoo/search/dispatch/rpc/RpcSearchInvoker.java +++ b/container-search/src/main/java/com/yahoo/search/dispatch/rpc/RpcSearchInvoker.java @@ -5,7 +5,6 @@ import com.yahoo.compress.CompressionType; import com.yahoo.compress.Compressor; import com.yahoo.prelude.fastsearch.VespaBackEndSearcher; import com.yahoo.search.Query; -import com.yahoo.search.Result; import com.yahoo.search.dispatch.InvokerResult; import com.yahoo.search.dispatch.SearchInvoker; import com.yahoo.search.dispatch.rpc.Client.ProtobufResponse; diff --git a/container-search/src/main/java/com/yahoo/search/dispatch/searchcluster/SearchCluster.java b/container-search/src/main/java/com/yahoo/search/dispatch/searchcluster/SearchCluster.java index cc705668992..59b73df0ef3 100644 --- a/container-search/src/main/java/com/yahoo/search/dispatch/searchcluster/SearchCluster.java +++ b/container-search/src/main/java/com/yahoo/search/dispatch/searchcluster/SearchCluster.java @@ -79,6 +79,13 @@ public class SearchCluster implements NodeManager<Node> { this.localCorpusDispatchTarget = findLocalCorpusDispatchTarget(HostName.getLocalhost(), nodesByHost, groups); } + + /* Testing only */ + public SearchCluster(String clusterId, DispatchConfig dispatchConfig, + VipStatus vipStatus, PingFactory pingFactory) { + this(clusterId, dispatchConfig, 1, vipStatus, pingFactory); + } + public void addMonitoring(ClusterMonitor clusterMonitor) { for (var group : orderedGroups) { for (var node : group.nodes()) diff --git a/container-search/src/test/java/com/yahoo/prelude/cluster/ClusterSearcherTestCase.java b/container-search/src/test/java/com/yahoo/prelude/cluster/ClusterSearcherTestCase.java index fb57f5eccd6..5382999f96a 100644 --- a/container-search/src/test/java/com/yahoo/prelude/cluster/ClusterSearcherTestCase.java +++ b/container-search/src/test/java/com/yahoo/prelude/cluster/ClusterSearcherTestCase.java @@ -21,6 +21,7 @@ import com.yahoo.search.Query; import com.yahoo.search.Result; import com.yahoo.search.config.ClusterConfig; import com.yahoo.search.dispatch.Dispatcher; +import com.yahoo.search.dispatch.rpc.RpcResourcePool; import com.yahoo.search.result.Hit; import com.yahoo.search.searchchain.Execution; import com.yahoo.vespa.config.search.DispatchConfig; @@ -513,8 +514,10 @@ public class ClusterSearcherTestCase { DocumentdbInfoConfig.Builder documentDbConfig = new DocumentdbInfoConfig.Builder(); documentDbConfig.documentdb(new DocumentdbInfoConfig.Documentdb.Builder().name("type1")); - Dispatcher dispatcher = new Dispatcher(new ComponentId("test-id"), - new DispatchConfig.Builder().build(), + DispatchConfig dispatchConfig = new DispatchConfig.Builder().build(); + Dispatcher dispatcher = new Dispatcher(new RpcResourcePool(dispatchConfig), + ComponentId.createAnonymousComponentId("test-id"), + dispatchConfig, vipStatus, new MockMetric()); ComponentRegistry<Dispatcher> dispatchers = new ComponentRegistry<>(); diff --git a/controller-api/src/main/java/com/yahoo/vespa/hosted/controller/api/integration/user/Roles.java b/controller-api/src/main/java/com/yahoo/vespa/hosted/controller/api/integration/user/Roles.java index 77bd589f23b..f5f3ebe8f35 100644 --- a/controller-api/src/main/java/com/yahoo/vespa/hosted/controller/api/integration/user/Roles.java +++ b/controller-api/src/main/java/com/yahoo/vespa/hosted/controller/api/integration/user/Roles.java @@ -35,6 +35,7 @@ public class Roles { public static Role toRole(String value) { String[] parts = value.split("\\."); if (parts.length == 1 && parts[0].equals("hostedOperator")) return Role.hostedOperator(); + if (parts.length == 1 && parts[0].equals("hostedSupporter")) return Role.hostedSupporter(); if (parts.length == 2) return toRole(TenantName.from(parts[0]), parts[1]); if (parts.length == 3) return toRole(TenantName.from(parts[0]), ApplicationName.from(parts[1]), parts[2]); throw new IllegalArgumentException("Malformed or illegal role value '" + value + "'."); diff --git a/controller-api/src/main/java/com/yahoo/vespa/hosted/controller/api/role/Policy.java b/controller-api/src/main/java/com/yahoo/vespa/hosted/controller/api/role/Policy.java index e27fb0fbf27..0e8e3a13f9f 100644 --- a/controller-api/src/main/java/com/yahoo/vespa/hosted/controller/api/role/Policy.java +++ b/controller-api/src/main/java/com/yahoo/vespa/hosted/controller/api/role/Policy.java @@ -23,6 +23,11 @@ enum Policy { .on(PathGroup.all()) .in(SystemName.all())), + /** Full access to everything. */ + supporter(Privilege.grant(Action.read) + .on(PathGroup.all()) + .in(SystemName.all())), + /** Full access to user management for a tenant in select systems. */ tenantManager(Privilege.grant(Action.all()) .on(PathGroup.tenantUsers) diff --git a/controller-api/src/main/java/com/yahoo/vespa/hosted/controller/api/role/Role.java b/controller-api/src/main/java/com/yahoo/vespa/hosted/controller/api/role/Role.java index b53cf9162e7..263e3284dbd 100644 --- a/controller-api/src/main/java/com/yahoo/vespa/hosted/controller/api/role/Role.java +++ b/controller-api/src/main/java/com/yahoo/vespa/hosted/controller/api/role/Role.java @@ -28,6 +28,11 @@ public abstract class Role { return new UnboundRole(RoleDefinition.hostedOperator); } + /** Returns a {@link RoleDefinition#hostedSupporter} for the current system. */ + public static UnboundRole hostedSupporter() { + return new UnboundRole(RoleDefinition.hostedSupporter); + } + /** Returns a {@link RoleDefinition#everyone} for the current system. */ public static UnboundRole everyone() { return new UnboundRole(RoleDefinition.everyone); diff --git a/controller-api/src/main/java/com/yahoo/vespa/hosted/controller/api/role/RoleDefinition.java b/controller-api/src/main/java/com/yahoo/vespa/hosted/controller/api/role/RoleDefinition.java index 58d69512feb..848866f7c33 100644 --- a/controller-api/src/main/java/com/yahoo/vespa/hosted/controller/api/role/RoleDefinition.java +++ b/controller-api/src/main/java/com/yahoo/vespa/hosted/controller/api/role/RoleDefinition.java @@ -21,6 +21,9 @@ public enum RoleDefinition { /** Deus ex machina. */ hostedOperator(Policy.operator), + /** Machina autem exspiravit. */ + hostedSupporter(Policy.supporter), + /** Base role which every user is part of. */ everyone(Policy.classifiedRead, Policy.classifiedApiRead, diff --git a/controller-api/src/test/java/com/yahoo/vespa/hosted/controller/api/integration/user/RolesTest.java b/controller-api/src/test/java/com/yahoo/vespa/hosted/controller/api/integration/user/RolesTest.java index cfb5462e50a..22baedd16b4 100644 --- a/controller-api/src/test/java/com/yahoo/vespa/hosted/controller/api/integration/user/RolesTest.java +++ b/controller-api/src/test/java/com/yahoo/vespa/hosted/controller/api/integration/user/RolesTest.java @@ -27,6 +27,8 @@ public class RolesTest { assertEquals(Role.hostedOperator(), Roles.toRole("hostedOperator")); + assertEquals(Role.hostedSupporter(), + Roles.toRole("hostedSupporter")); assertEquals(Role.tenantOperator(tenant), Roles.toRole("my-tenant.tenantOperator")); assertEquals(Role.applicationReader(tenant, application), diff --git a/controller-api/src/test/java/com/yahoo/vespa/hosted/controller/api/role/RoleTest.java b/controller-api/src/test/java/com/yahoo/vespa/hosted/controller/api/role/RoleTest.java index d153e218640..da2f64f2893 100644 --- a/controller-api/src/test/java/com/yahoo/vespa/hosted/controller/api/role/RoleTest.java +++ b/controller-api/src/test/java/com/yahoo/vespa/hosted/controller/api/role/RoleTest.java @@ -33,6 +33,27 @@ public class RoleTest { } @Test + public void supporter_membership() { + Role role = Role.hostedSupporter(); + + // No create update or delete + assertFalse(mainEnforcer.allows(role, Action.create, URI.create("/not/explicitly/defined"))); + assertFalse(mainEnforcer.allows(role, Action.create, URI.create("/controller/v1/foo"))); + assertFalse(mainEnforcer.allows(role, Action.update, URI.create("/os/v1/bar"))); + assertFalse(mainEnforcer.allows(role, Action.update, URI.create("/application/v4/tenant/t1/application/a1"))); + assertFalse(mainEnforcer.allows(role, Action.update, URI.create("/application/v4/tenant/t2/application/a2"))); + assertFalse(mainEnforcer.allows(role, Action.delete, URI.create("/application/v4/tenant/t8/application/a6/instance/i1/environment/dev/region/r1"))); + + // But reads is ok (but still only for valid paths) + assertFalse(mainEnforcer.allows(role, Action.read, URI.create("/not/explicitly/defined"))); + assertTrue(mainEnforcer.allows(role, Action.read, URI.create("/controller/v1/foo"))); + assertTrue(mainEnforcer.allows(role, Action.read, URI.create("/os/v1/bar"))); + assertTrue(mainEnforcer.allows(role, Action.read, URI.create("/application/v4/tenant/t1/application/a1"))); + assertTrue(mainEnforcer.allows(role, Action.read, URI.create("/application/v4/tenant/t2/application/a2"))); + assertFalse(mainEnforcer.allows(role, Action.delete, URI.create("/application/v4/tenant/t8/application/a6/instance/i1/environment/dev/region/r1"))); + } + + @Test public void tenant_membership() { Role role = Role.athenzTenantAdmin(TenantName.from("t1")); assertFalse(mainEnforcer.allows(role, Action.create, URI.create("/not/explicitly/defined"))); @@ -133,12 +154,14 @@ public class RoleTest { Action action = Action.update; assertTrue(mainEnforcer.allows(Role.systemFlagsDeployer(), action, deployUri)); assertTrue(mainEnforcer.allows(Role.hostedOperator(), action, deployUri)); + assertFalse(mainEnforcer.allows(Role.hostedSupporter(), action, deployUri)); assertFalse(mainEnforcer.allows(Role.systemFlagsDryrunner(), action, deployUri)); assertFalse(mainEnforcer.allows(Role.everyone(), action, deployUri)); URI dryrunUri = URI.create("/system-flags/v1/dryrun"); assertTrue(mainEnforcer.allows(Role.systemFlagsDeployer(), action, dryrunUri)); assertTrue(mainEnforcer.allows(Role.hostedOperator(), action, dryrunUri)); + assertFalse(mainEnforcer.allows(Role.hostedSupporter(), action, dryrunUri)); assertTrue(mainEnforcer.allows(Role.systemFlagsDryrunner(), action, dryrunUri)); assertFalse(mainEnforcer.allows(Role.everyone(), action, dryrunUri)); } diff --git a/controller-server/src/main/java/com/yahoo/vespa/hosted/controller/athenz/impl/AthenzFacade.java b/controller-server/src/main/java/com/yahoo/vespa/hosted/controller/athenz/impl/AthenzFacade.java index 7ace62ab44d..628d7f48c85 100644 --- a/controller-server/src/main/java/com/yahoo/vespa/hosted/controller/athenz/impl/AthenzFacade.java +++ b/controller-server/src/main/java/com/yahoo/vespa/hosted/controller/athenz/impl/AthenzFacade.java @@ -215,6 +215,10 @@ public class AthenzFacade implements AccessControl { return hasAccess("modify", service.getDomain().getName() + ":hosted-vespa", identity); } + public boolean hasHostedSupporterAccess(AthenzIdentity identity) { + return hasAccess("read", service.getDomain().getName() + ":hosted-vespa", identity); + } + public boolean canLaunch(AthenzIdentity principal, AthenzService service) { return hasAccess("launch", service.getDomain().getName() + ":service."+service.getName(), principal); } diff --git a/controller-server/src/main/java/com/yahoo/vespa/hosted/controller/restapi/filter/AthenzRoleFilter.java b/controller-server/src/main/java/com/yahoo/vespa/hosted/controller/restapi/filter/AthenzRoleFilter.java index 1aaecb58a8d..ba974521278 100644 --- a/controller-server/src/main/java/com/yahoo/vespa/hosted/controller/restapi/filter/AthenzRoleFilter.java +++ b/controller-server/src/main/java/com/yahoo/vespa/hosted/controller/restapi/filter/AthenzRoleFilter.java @@ -87,6 +87,9 @@ public class AthenzRoleFilter extends JsonSecurityRequestFilterBase { if (athenz.hasHostedOperatorAccess(identity)) roleMemberships.add(Role.hostedOperator()); + if (athenz.hasHostedSupporterAccess(identity)) + roleMemberships.add(Role.hostedSupporter()); + // Add all tenants that are accessible for this request athenz.accessibleTenants(tenants.asList(), new Credentials(principal)) .forEach(accessibleTenant -> roleMemberships.add(Role.athenzTenantAdmin(accessibleTenant.name()))); diff --git a/controller-server/src/main/java/com/yahoo/vespa/hosted/controller/restapi/user/UserApiHandler.java b/controller-server/src/main/java/com/yahoo/vespa/hosted/controller/restapi/user/UserApiHandler.java index d9ffe8a251c..847a6c96a53 100644 --- a/controller-server/src/main/java/com/yahoo/vespa/hosted/controller/restapi/user/UserApiHandler.java +++ b/controller-server/src/main/java/com/yahoo/vespa/hosted/controller/restapi/user/UserApiHandler.java @@ -134,10 +134,11 @@ public class UserApiHandler extends LoggingRequestHandler { // List of operator roles, currently only one available, but possible to extend List<Role> operatorRoles = roles.stream() - .filter(role -> role.definition().equals(RoleDefinition.hostedOperator)) + .filter(role -> role.definition().equals(RoleDefinition.hostedOperator) || + role.definition().equals(RoleDefinition.hostedSupporter)) + .sorted(Comparator.comparing(Role::definition)) .collect(Collectors.toList()); - Slime slime = new Slime(); Cursor root = slime.setObject(); diff --git a/controller-server/src/test/java/com/yahoo/vespa/hosted/controller/restapi/filter/AthenzRoleFilterTest.java b/controller-server/src/test/java/com/yahoo/vespa/hosted/controller/restapi/filter/AthenzRoleFilterTest.java index 82b97a5b144..bef27f7a2f5 100644 --- a/controller-server/src/test/java/com/yahoo/vespa/hosted/controller/restapi/filter/AthenzRoleFilterTest.java +++ b/controller-server/src/test/java/com/yahoo/vespa/hosted/controller/restapi/filter/AthenzRoleFilterTest.java @@ -73,13 +73,13 @@ public class AthenzRoleFilterTest { public void testTranslations() { // Hosted operators are always members of the hostedOperator role. - assertEquals(Set.of(Role.hostedOperator(), Role.systemFlagsDeployer(), Role.systemFlagsDryrunner()), + assertEquals(Set.of(Role.hostedOperator(), Role.systemFlagsDeployer(), Role.systemFlagsDryrunner(), Role.hostedSupporter()), filter.roles(HOSTED_OPERATOR, NO_CONTEXT_PATH)); - assertEquals(Set.of(Role.hostedOperator(), Role.systemFlagsDeployer(), Role.systemFlagsDryrunner()), + assertEquals(Set.of(Role.hostedOperator(), Role.systemFlagsDeployer(), Role.systemFlagsDryrunner(), Role.hostedSupporter()), filter.roles(HOSTED_OPERATOR, TENANT_CONTEXT_PATH)); - assertEquals(Set.of(Role.hostedOperator(), Role.systemFlagsDeployer(), Role.systemFlagsDryrunner()), + assertEquals(Set.of(Role.hostedOperator(), Role.systemFlagsDeployer(), Role.systemFlagsDryrunner(), Role.hostedSupporter()), filter.roles(HOSTED_OPERATOR, APPLICATION_CONTEXT_PATH)); // Tenant admins are members of the athenzTenantAdmin role within their tenant subtree. diff --git a/controller-server/src/test/java/com/yahoo/vespa/hosted/controller/restapi/filter/ControllerAuthorizationFilterTest.java b/controller-server/src/test/java/com/yahoo/vespa/hosted/controller/restapi/filter/ControllerAuthorizationFilterTest.java index a5520b42459..c95691fc120 100644 --- a/controller-server/src/test/java/com/yahoo/vespa/hosted/controller/restapi/filter/ControllerAuthorizationFilterTest.java +++ b/controller-server/src/test/java/com/yahoo/vespa/hosted/controller/restapi/filter/ControllerAuthorizationFilterTest.java @@ -43,6 +43,16 @@ public class ControllerAuthorizationFilterTest { } @Test + public void supporter() { + ControllerTester tester = new ControllerTester(); + SecurityContext securityContext = new SecurityContext(() -> "operator", Set.of(Role.hostedSupporter())); + ControllerAuthorizationFilter filter = createFilter(tester); + + assertIsForbidden(invokeFilter(filter, createRequest(Method.POST, "/zone/v2/path", securityContext))); + assertIsAllowed(invokeFilter(filter, createRequest(Method.GET, "/zone/v1/path", securityContext))); + } + + @Test public void unprivileged() { ControllerTester tester = new ControllerTester(); SecurityContext securityContext = new SecurityContext(() -> "user", Set.of(Role.everyone())); diff --git a/controller-server/src/test/java/com/yahoo/vespa/hosted/controller/restapi/user/UserApiTest.java b/controller-server/src/test/java/com/yahoo/vespa/hosted/controller/restapi/user/UserApiTest.java index d1dd50cfb4c..d70a09414bb 100644 --- a/controller-server/src/test/java/com/yahoo/vespa/hosted/controller/restapi/user/UserApiTest.java +++ b/controller-server/src/test/java/com/yahoo/vespa/hosted/controller/restapi/user/UserApiTest.java @@ -203,7 +203,7 @@ public class UserApiTest extends ControllerContainerCloudTest { public void userMetadataTest() { ContainerTester tester = new ContainerTester(container, responseFiles); ControllerTester controller = new ControllerTester(tester); - Set<Role> operator = Set.of(Role.hostedOperator()); + Set<Role> operator = Set.of(Role.hostedOperator(), Role.hostedSupporter()); User user = new User("dev@domail", "Joe Developer", "dev", null); tester.assertResponse(request("/api/user/v1/user") diff --git a/controller-server/src/test/java/com/yahoo/vespa/hosted/controller/restapi/user/responses/user-without-applications.json b/controller-server/src/test/java/com/yahoo/vespa/hosted/controller/restapi/user/responses/user-without-applications.json index 17489bb15d8..400fe8d4d9b 100644 --- a/controller-server/src/test/java/com/yahoo/vespa/hosted/controller/restapi/user/responses/user-without-applications.json +++ b/controller-server/src/test/java/com/yahoo/vespa/hosted/controller/restapi/user/responses/user-without-applications.json @@ -7,6 +7,7 @@ }, "tenants": {}, "operator": [ - "hostedOperator" + "hostedOperator", + "hostedSupporter" ] } diff --git a/fbench/src/httpclient/httpclient.cpp b/fbench/src/httpclient/httpclient.cpp index 002d2770dcd..99134a6e297 100644 --- a/fbench/src/httpclient/httpclient.cpp +++ b/fbench/src/httpclient/httpclient.cpp @@ -1,5 +1,6 @@ // Copyright 2017 Yahoo Holdings. Licensed under the terms of the Apache 2.0 license. See LICENSE in the project root. #include "httpclient.h" +#include <vespa/vespalib/net/socket_spec.h> #include <cassert> #include <cstring> @@ -69,7 +70,8 @@ HTTPClient::connect_socket() if (!handle.valid()) { return false; } - _socket = vespalib::SyncCryptoSocket::create(*_engine, std::move(handle), false); + _socket = vespalib::SyncCryptoSocket::create_client(*_engine, std::move(handle), + vespalib::SocketSpec::from_host_port(_hostname, _port)); return bool(_socket); } diff --git a/fnet/src/tests/connect/connect_test.cpp b/fnet/src/tests/connect/connect_test.cpp index b70b3fa8b01..d94b6759077 100644 --- a/fnet/src/tests/connect/connect_test.cpp +++ b/fnet/src/tests/connect/connect_test.cpp @@ -65,7 +65,11 @@ struct BlockingCryptoEngine : public CryptoEngine { Gate handshake_work_enter; Gate handshake_work_exit; Gate handshake_socket_deleted; - CryptoSocket::UP create_crypto_socket(SocketHandle socket, bool) override { + CryptoSocket::UP create_client_crypto_socket(SocketHandle socket, const SocketSpec &) override { + return std::make_unique<BlockingCryptoSocket>(std::move(socket), + handshake_work_enter, handshake_work_exit, handshake_socket_deleted); + } + CryptoSocket::UP create_server_crypto_socket(SocketHandle socket) override { return std::make_unique<BlockingCryptoSocket>(std::move(socket), handshake_work_enter, handshake_work_exit, handshake_socket_deleted); } diff --git a/fnet/src/vespa/fnet/connection.cpp b/fnet/src/vespa/fnet/connection.cpp index 5f7adb32af0..c5afd627a5a 100644 --- a/fnet/src/vespa/fnet/connection.cpp +++ b/fnet/src/vespa/fnet/connection.cpp @@ -9,6 +9,7 @@ #include "config.h" #include "transport_thread.h" #include "transport.h" +#include <vespa/vespalib/net/socket_spec.h> #include <vespa/log/log.h> LOG_SETUP(".fnet"); @@ -472,7 +473,7 @@ FNET_Connection::FNET_Connection(FNET_TransportThread *owner, _streamer(streamer), _serverAdapter(serverAdapter), _adminChannel(nullptr), - _socket(owner->owner().create_crypto_socket(std::move(socket), true)), + _socket(owner->owner().create_server_crypto_socket(std::move(socket))), _resolve_handler(nullptr), _context(), _state(FNET_CONNECTING), @@ -579,7 +580,7 @@ FNET_Connection::handle_add_event() { if (_resolve_handler) { auto tweak = [this](vespalib::SocketHandle &handle) { return Owner()->tune(handle); }; - _socket = Owner()->owner().create_crypto_socket(_resolve_handler->address.connect(tweak), false); + _socket = Owner()->owner().create_client_crypto_socket(_resolve_handler->address.connect(tweak), vespalib::SocketSpec(GetSpec())); _ioc_socket_fd = _socket->get_fd(); _resolve_handler.reset(); } diff --git a/fnet/src/vespa/fnet/transport.cpp b/fnet/src/vespa/fnet/transport.cpp index 28e645d9e03..d3b52969c8c 100644 --- a/fnet/src/vespa/fnet/transport.cpp +++ b/fnet/src/vespa/fnet/transport.cpp @@ -54,9 +54,15 @@ FNET_Transport::resolve_async(const vespalib::string &spec, } vespalib::CryptoSocket::UP -FNET_Transport::create_crypto_socket(vespalib::SocketHandle socket, bool is_server) +FNET_Transport::create_client_crypto_socket(vespalib::SocketHandle socket, const vespalib::SocketSpec &spec) { - return _crypto_engine->create_crypto_socket(std::move(socket), is_server); + return _crypto_engine->create_client_crypto_socket(std::move(socket), spec); +} + +vespalib::CryptoSocket::UP +FNET_Transport::create_server_crypto_socket(vespalib::SocketHandle socket) +{ + return _crypto_engine->create_server_crypto_socket(std::move(socket)); } FNET_TransportThread * diff --git a/fnet/src/vespa/fnet/transport.h b/fnet/src/vespa/fnet/transport.h index 8d1ba48c1b0..02ef22c7fb6 100644 --- a/fnet/src/vespa/fnet/transport.h +++ b/fnet/src/vespa/fnet/transport.h @@ -79,17 +79,25 @@ public: vespalib::AsyncResolver::ResultHandler::WP result_handler); /** - * Wrap a plain socket endpoint in a CryptoSocket. The + * Wrap a plain socket endpoint (client side) in a CryptoSocket. The * implementation will be determined by the CryptoEngine used by * this Transport. * * @return socket abstraction able to perform encryption and decryption * @param socket low-level socket - * @param is_server which end of the connection the socket - * represents. This is needed to support - * asymmetrical handshaking. + * @param spec who we are connecting to **/ - vespalib::CryptoSocket::UP create_crypto_socket(vespalib::SocketHandle socket, bool is_server); + vespalib::CryptoSocket::UP create_client_crypto_socket(vespalib::SocketHandle socket, const vespalib::SocketSpec &spec); + + /** + * Wrap a plain socket endpoint (server side) in a CryptoSocket. The + * implementation will be determined by the CryptoEngine used by + * this Transport. + * + * @return socket abstraction able to perform encryption and decryption + * @param socket low-level socket + **/ + vespalib::CryptoSocket::UP create_server_crypto_socket(vespalib::SocketHandle socket); /** * Select one of the underlying transport threads. The selection diff --git a/logserver/bin/logserver-start.sh b/logserver/bin/logserver-start.sh index 9f55e218140..913cdb78327 100755 --- a/logserver/bin/logserver-start.sh +++ b/logserver/bin/logserver-start.sh @@ -78,7 +78,7 @@ ROOT=${VESPA_HOME%/} export ROOT cd $ROOT || { echo "Cannot cd to $ROOT" 1>&2; exit 1; } -addopts="-server -Xms32m -Xmx256m -XX:MaxDirectMemorySize=76m -XX:MaxJavaStackTraceDepth=1000000" +addopts="-server -Xms32m -Xmx256m -XX:CompressedClassSpaceSize=32m -XX:MaxDirectMemorySize=32m -XX:ThreadStackSize=256 -XX:MaxJavaStackTraceDepth=1000 -XX:ActiveProcessorCount=2" oomopt="-XX:+ExitOnOutOfMemoryError" diff --git a/metrics-proxy/src/main/java/ai/vespa/metricsproxy/core/MetricsManager.java b/metrics-proxy/src/main/java/ai/vespa/metricsproxy/core/MetricsManager.java index 4c4015220bc..53a05ef88f0 100644 --- a/metrics-proxy/src/main/java/ai/vespa/metricsproxy/core/MetricsManager.java +++ b/metrics-proxy/src/main/java/ai/vespa/metricsproxy/core/MetricsManager.java @@ -79,6 +79,16 @@ public class MetricsManager { * @return Metrics for all matching services. */ public List<MetricsPacket> getMetrics(List<VespaService> services, Instant startTime) { + return getMetricsAsBuilders(services, startTime).stream() + .map(MetricsPacket.Builder::build) + .collect(Collectors.toList()); + } + + /** + * Returns the metrics for the given services, in mutable state for further processing. + * NOTE: Use {@link #getMetrics(List, Instant)} instead, unless further processing of the metrics is necessary. + */ + public List<MetricsPacket.Builder> getMetricsAsBuilders(List<VespaService> services, Instant startTime) { if (services.isEmpty()) return Collections.emptyList(); log.log(DEBUG, () -> "Updating services prior to fetching metrics, number of services= " + services.size()); @@ -99,7 +109,6 @@ public class MetricsManager { .map(builder -> builder.putDimensionsIfAbsent(getGlobalDimensions())) .map(builder -> builder.putDimensionsIfAbsent(extraDimensions)) .map(builder -> adjustTimestamp(builder, startTime)) - .map(MetricsPacket.Builder::build) .collect(Collectors.toList()); } diff --git a/node-repository/src/main/java/com/yahoo/vespa/hosted/provision/NodeRepository.java b/node-repository/src/main/java/com/yahoo/vespa/hosted/provision/NodeRepository.java index 48a53104f7f..4af68fa702c 100644 --- a/node-repository/src/main/java/com/yahoo/vespa/hosted/provision/NodeRepository.java +++ b/node-repository/src/main/java/com/yahoo/vespa/hosted/provision/NodeRepository.java @@ -215,7 +215,7 @@ public class NodeRepository extends AbstractComponent { /** * Returns the ACL for the node (trusted nodes, networks and ports) */ - private NodeAcl getNodeAcl(Node node, NodeList candidates, LoadBalancerList loadBalancers) { + private NodeAcl getNodeAcl(Node node, NodeList candidates) { Set<Node> trustedNodes = new TreeSet<>(Comparator.comparing(Node::hostname)); Set<Integer> trustedPorts = new LinkedHashSet<>(); Set<String> trustedNetworks = new LinkedHashSet<>(); @@ -232,10 +232,10 @@ public class NodeRepository extends AbstractComponent { candidates.parentOf(node).ifPresent(trustedNodes::add); node.allocation().ifPresent(allocation -> { trustedNodes.addAll(candidates.owner(allocation.owner()).asList()); - loadBalancers.asList().stream() - .map(LoadBalancer::instance) - .map(LoadBalancerInstance::networks) - .forEach(trustedNetworks::addAll); + loadBalancers(allocation.owner()).asList().stream() + .map(LoadBalancer::instance) + .map(LoadBalancerInstance::networks) + .forEach(trustedNetworks::addAll); }); switch (node.type()) { @@ -304,18 +304,12 @@ public class NodeRepository extends AbstractComponent { */ public List<NodeAcl> getNodeAcls(Node node, boolean children) { NodeList candidates = list(); - LoadBalancerList loadBalancers; - if (node.allocation().isPresent()) { - loadBalancers = loadBalancers(node.allocation().get().owner()); - } else { - loadBalancers = LoadBalancerList.EMPTY; - } if (children) { return candidates.childrenOf(node).asList().stream() - .map(childNode -> getNodeAcl(childNode, candidates, loadBalancers)) + .map(childNode -> getNodeAcl(childNode, candidates)) .collect(Collectors.collectingAndThen(Collectors.toList(), Collections::unmodifiableList)); } - return Collections.singletonList(getNodeAcl(node, candidates, loadBalancers)); + return Collections.singletonList(getNodeAcl(node, candidates)); } public NodeFlavors getAvailableFlavors() { diff --git a/node-repository/src/main/java/com/yahoo/vespa/hosted/provision/lb/LoadBalancerList.java b/node-repository/src/main/java/com/yahoo/vespa/hosted/provision/lb/LoadBalancerList.java index 479fd328162..bad16bf7d12 100644 --- a/node-repository/src/main/java/com/yahoo/vespa/hosted/provision/lb/LoadBalancerList.java +++ b/node-repository/src/main/java/com/yahoo/vespa/hosted/provision/lb/LoadBalancerList.java @@ -15,8 +15,6 @@ import java.util.stream.Stream; */ public class LoadBalancerList implements Iterable<LoadBalancer> { - public static LoadBalancerList EMPTY = new LoadBalancerList(List.of()); - private final List<LoadBalancer> loadBalancers; private LoadBalancerList(Collection<LoadBalancer> loadBalancers) { diff --git a/node-repository/src/test/java/com/yahoo/vespa/hosted/provision/provisioning/AclProvisioningTest.java b/node-repository/src/test/java/com/yahoo/vespa/hosted/provision/provisioning/AclProvisioningTest.java index 92d066e5f16..8995897769c 100644 --- a/node-repository/src/test/java/com/yahoo/vespa/hosted/provision/provisioning/AclProvisioningTest.java +++ b/node-repository/src/test/java/com/yahoo/vespa/hosted/provision/provisioning/AclProvisioningTest.java @@ -164,12 +164,33 @@ public class AclProvisioningTest { @Test public void trusted_nodes_for_application_with_load_balancer() { - // Populate repo - tester.makeReadyNodes(10, nodeResources); + // Provision hosts and containers + var hosts = tester.makeReadyNodes(2, "default", NodeType.host); + tester.deployZoneApp(); + for (var host : hosts) { + tester.makeReadyVirtualDockerNodes(2, new NodeResources(2, 8, 50, 1), + host.hostname()); + } - // Allocate 2 nodes - List<Node> activeNodes = deploy(2); + // Deploy application + var application = tester.makeApplicationId(); + List<Node> activeNodes = deploy(application, 2); assertEquals(2, activeNodes.size()); + + // Load balancer is allocated to application + var loadBalancers = tester.nodeRepository().loadBalancers(application); + assertEquals(1, loadBalancers.asList().size()); + var lbNetworks = loadBalancers.asList().get(0).instance().networks(); + assertEquals(2, lbNetworks.size()); + + // ACL for nodes with allocation trust their respective load balancer networks, if any + for (var host : hosts) { + var acls = tester.nodeRepository().getNodeAcls(host, true); + assertEquals(2, acls.size()); + assertEquals(Set.of(), acls.get(0).trustedNetworks()); + assertEquals(application, acls.get(1).node().allocation().get().owner()); + assertEquals(lbNetworks, acls.get(1).trustedNetworks()); + } } @Test diff --git a/storage/src/tests/frameworkimpl/status/statustest.cpp b/storage/src/tests/frameworkimpl/status/statustest.cpp index 81d91e2f08a..7c259f00899 100644 --- a/storage/src/tests/frameworkimpl/status/statustest.cpp +++ b/storage/src/tests/frameworkimpl/status/statustest.cpp @@ -19,7 +19,7 @@ vespalib::string fetch(int port, const vespalib::string &path) { auto crypto = vespalib::CryptoEngine::get_default(); auto socket = vespalib::SocketSpec::from_port(port).client_address().connect(); assert(socket.valid()); - auto conn = vespalib::SyncCryptoSocket::create(*crypto, std::move(socket), false); + auto conn = vespalib::SyncCryptoSocket::create_client(*crypto, std::move(socket), vespalib::SocketSpec::from_host_port("localhost", port)); vespalib::string http_req = vespalib::make_string("GET %s HTTP/1.1\r\n" "Host: localhost:%d\r\n" "\r\n", path.c_str(), port); diff --git a/vbench/src/vbench/core/socket.cpp b/vbench/src/vbench/core/socket.cpp index 822b96b2c07..0431b6889a8 100644 --- a/vbench/src/vbench/core/socket.cpp +++ b/vbench/src/vbench/core/socket.cpp @@ -29,7 +29,8 @@ Socket::Socket(SyncCryptoSocket::UP socket) } Socket::Socket(CryptoEngine &crypto, const string &host, int port) - : _socket(SyncCryptoSocket::create(crypto, connect(host, port), false)), + : _socket(SyncCryptoSocket::create_client(crypto, connect(host, port), + vespalib::SocketSpec::from_host_port(host, port))), _input(), _output(), _taint(), diff --git a/vbench/src/vbench/core/socket.h b/vbench/src/vbench/core/socket.h index 0e8848e8292..4b5721c0fb7 100644 --- a/vbench/src/vbench/core/socket.h +++ b/vbench/src/vbench/core/socket.h @@ -52,7 +52,7 @@ struct ServerSocket { Stream::UP accept(CryptoEngine &crypto) { vespalib::SocketHandle handle = server_socket.accept(); if (handle.valid()) { - return std::make_unique<Socket>(SyncCryptoSocket::create(crypto, std::move(handle), true)); + return std::make_unique<Socket>(SyncCryptoSocket::create_server(crypto, std::move(handle))); } else { return Stream::UP(); } diff --git a/vespalib/src/tests/net/crypto_socket/crypto_socket_test.cpp b/vespalib/src/tests/net/crypto_socket/crypto_socket_test.cpp index 62bad716597..e938e15f4e6 100644 --- a/vespalib/src/tests/net/crypto_socket/crypto_socket_test.cpp +++ b/vespalib/src/tests/net/crypto_socket/crypto_socket_test.cpp @@ -17,6 +17,7 @@ #include <fcntl.h> using namespace vespalib; +using namespace vespalib::test; struct SocketPair { SocketHandle client; @@ -204,7 +205,9 @@ void verify_crypto_socket(SocketPair &sockets, CryptoEngine &engine, bool is_ser SocketHandle &my_handle = is_server ? sockets.server : sockets.client; my_handle.set_blocking(false); SmartBuffer read_buffer(4096); - CryptoSocket::UP my_socket = engine.create_crypto_socket(std::move(my_handle), is_server); + CryptoSocket::UP my_socket = is_server + ? engine.create_server_crypto_socket(std::move(my_handle)) + : engine.create_client_crypto_socket(std::move(my_handle), local_spec); TEST_DO(verify_handshake(*my_socket)); drain(*my_socket, read_buffer); TEST_DO(verify_socket_io(*my_socket, read_buffer, is_server)); @@ -226,19 +229,19 @@ TEST_MT_FFF("require that encrypted async socket io works with XorCryptoEngine", } TEST_MT_FFF("require that encrypted async socket io works with TlsCryptoEngine", - 2, SocketPair(), TlsCryptoEngine(vespalib::test::make_tls_options_for_testing()), TimeBomb(60)) + 2, SocketPair(), TlsCryptoEngine(make_tls_options_for_testing()), TimeBomb(60)) { TEST_DO(verify_crypto_socket(f1, f2, (thread_id == 0))); } TEST_MT_FFF("require that encrypted async socket io works with MaybeTlsCryptoEngine(true)", - 2, SocketPair(), MaybeTlsCryptoEngine(std::make_shared<TlsCryptoEngine>(vespalib::test::make_tls_options_for_testing()), true), TimeBomb(60)) + 2, SocketPair(), MaybeTlsCryptoEngine(std::make_shared<TlsCryptoEngine>(make_tls_options_for_testing()), true), TimeBomb(60)) { TEST_DO(verify_crypto_socket(f1, f2, (thread_id == 0))); } TEST_MT_FFF("require that encrypted async socket io works with MaybeTlsCryptoEngine(false)", - 2, SocketPair(), MaybeTlsCryptoEngine(std::make_shared<TlsCryptoEngine>(vespalib::test::make_tls_options_for_testing()), false), TimeBomb(60)) + 2, SocketPair(), MaybeTlsCryptoEngine(std::make_shared<TlsCryptoEngine>(make_tls_options_for_testing()), false), TimeBomb(60)) { TEST_DO(verify_crypto_socket(f1, f2, (thread_id == 0))); } diff --git a/vespalib/src/tests/net/socket_spec/socket_spec_test.cpp b/vespalib/src/tests/net/socket_spec/socket_spec_test.cpp index 0c2b92bbb53..f2da6b70bf3 100644 --- a/vespalib/src/tests/net/socket_spec/socket_spec_test.cpp +++ b/vespalib/src/tests/net/socket_spec/socket_spec_test.cpp @@ -123,4 +123,8 @@ TEST("require that replace_host gives invalid spec when used with less than 2 ho TEST_DO(verify_invalid(SocketSpec("ipc/name:my_socket").replace_host("foo"))); } +TEST("require that invalid socket spec is not valid") { + EXPECT_FALSE(SocketSpec::invalid.valid()); +} + TEST_MAIN() { TEST_RUN_ALL(); } diff --git a/vespalib/src/tests/net/sync_crypto_socket/sync_crypto_socket_test.cpp b/vespalib/src/tests/net/sync_crypto_socket/sync_crypto_socket_test.cpp index 76ecd9453b6..56767051dad 100644 --- a/vespalib/src/tests/net/sync_crypto_socket/sync_crypto_socket_test.cpp +++ b/vespalib/src/tests/net/sync_crypto_socket/sync_crypto_socket_test.cpp @@ -17,6 +17,7 @@ #include <fcntl.h> using namespace vespalib; +using namespace vespalib::test; struct SocketPair { SocketHandle client; @@ -97,7 +98,9 @@ void verify_socket_io(SyncCryptoSocket &socket, bool is_server) { void verify_crypto_socket(SocketPair &sockets, CryptoEngine &engine, bool is_server) { SocketHandle &my_handle = is_server ? sockets.server : sockets.client; my_handle.set_blocking(false); - SyncCryptoSocket::UP my_socket = SyncCryptoSocket::create(engine, std::move(my_handle), is_server); + SyncCryptoSocket::UP my_socket = is_server + ? SyncCryptoSocket::create_server(engine, std::move(my_handle)) + : SyncCryptoSocket::create_client(engine, std::move(my_handle), local_spec); ASSERT_TRUE(my_socket); TEST_DO(verify_socket_io(*my_socket, is_server)); TEST_DO(verify_graceful_shutdown(*my_socket, is_server)); @@ -118,19 +121,19 @@ TEST_MT_FFF("require that encrypted sync socket io works with XorCryptoEngine", } TEST_MT_FFF("require that encrypted sync socket io works with TlsCryptoEngine", - 2, SocketPair(), TlsCryptoEngine(vespalib::test::make_tls_options_for_testing()), TimeBomb(60)) + 2, SocketPair(), TlsCryptoEngine(make_tls_options_for_testing()), TimeBomb(60)) { TEST_DO(verify_crypto_socket(f1, f2, (thread_id == 0))); } TEST_MT_FFF("require that encrypted sync socket io works with MaybeTlsCryptoEngine(true)", - 2, SocketPair(), MaybeTlsCryptoEngine(std::make_shared<TlsCryptoEngine>(vespalib::test::make_tls_options_for_testing()), true), TimeBomb(60)) + 2, SocketPair(), MaybeTlsCryptoEngine(std::make_shared<TlsCryptoEngine>(make_tls_options_for_testing()), true), TimeBomb(60)) { TEST_DO(verify_crypto_socket(f1, f2, (thread_id == 0))); } TEST_MT_FFF("require that encrypted sync socket io works with MaybeTlsCryptoEngine(false)", - 2, SocketPair(), MaybeTlsCryptoEngine(std::make_shared<TlsCryptoEngine>(vespalib::test::make_tls_options_for_testing()), false), TimeBomb(60)) + 2, SocketPair(), MaybeTlsCryptoEngine(std::make_shared<TlsCryptoEngine>(make_tls_options_for_testing()), false), TimeBomb(60)) { TEST_DO(verify_crypto_socket(f1, f2, (thread_id == 0))); } diff --git a/vespalib/src/tests/portal/portal_test.cpp b/vespalib/src/tests/portal/portal_test.cpp index e54700306fe..0bd029c0c3a 100644 --- a/vespalib/src/tests/portal/portal_test.cpp +++ b/vespalib/src/tests/portal/portal_test.cpp @@ -14,13 +14,14 @@ #include <vespa/vespalib/util/latch.h> using namespace vespalib; +using namespace vespalib::test; //----------------------------------------------------------------------------- vespalib::string do_http(int port, CryptoEngine::SP crypto, const vespalib::string &method, const vespalib::string &uri, bool send_host = true) { auto socket = SocketSpec::from_port(port).client_address().connect(); ASSERT_TRUE(socket.valid()); - auto conn = SyncCryptoSocket::create(*crypto, std::move(socket), false); + auto conn = SyncCryptoSocket::create_client(*crypto, std::move(socket), local_spec); vespalib::string http_req = vespalib::make_string("%s %s HTTP/1.1\r\n" "My-Header: my value\r\n" "%s" @@ -75,7 +76,7 @@ Encryption::~Encryption() = default; auto null_crypto() { return std::make_shared<NullCryptoEngine>(); } auto xor_crypto() { return std::make_shared<XorCryptoEngine>(); } -auto tls_crypto() { return std::make_shared<TlsCryptoEngine>(vespalib::test::make_tls_options_for_testing()); } +auto tls_crypto() { return std::make_shared<TlsCryptoEngine>(make_tls_options_for_testing()); } auto maybe_tls_crypto(bool client_tls) { return std::make_shared<MaybeTlsCryptoEngine>(tls_crypto(), client_tls); } std::vector<Encryption> crypto_list = {{"no encryption", null_crypto()}, @@ -260,18 +261,18 @@ TEST("require that connection errors do not block shutdown by leaking resources" auto bound = portal->bind("/test", handler); { // close before sending anything auto socket = SocketSpec::from_port(portal->listen_port()).client_address().connect(); - auto conn = SyncCryptoSocket::create(*crypto.engine, std::move(socket), false); + auto conn = SyncCryptoSocket::create_client(*crypto.engine, std::move(socket), local_spec); } { // send partial request then close connection auto socket = SocketSpec::from_port(portal->listen_port()).client_address().connect(); - auto conn = SyncCryptoSocket::create(*crypto.engine, std::move(socket), false); + auto conn = SyncCryptoSocket::create_client(*crypto.engine, std::move(socket), local_spec); vespalib::string req = "GET /test HTTP/1.1\r\n" "Host: local"; ASSERT_EQUAL(conn->write(req.data(), req.size()), ssize_t(req.size())); } { // send request then close without reading response auto socket = SocketSpec::from_port(portal->listen_port()).client_address().connect(); - auto conn = SyncCryptoSocket::create(*crypto.engine, std::move(socket), false); + auto conn = SyncCryptoSocket::create_client(*crypto.engine, std::move(socket), local_spec); vespalib::string req = "GET /test HTTP/1.1\r\n" "Host: localhost\r\n" "\r\n"; diff --git a/vespalib/src/vespa/vespalib/net/crypto_engine.cpp b/vespalib/src/vespa/vespalib/net/crypto_engine.cpp index a52d4eeb690..a92b0e06bbe 100644 --- a/vespalib/src/vespa/vespalib/net/crypto_engine.cpp +++ b/vespalib/src/vespa/vespalib/net/crypto_engine.cpp @@ -250,16 +250,29 @@ CryptoEngine::get_default() } CryptoSocket::UP -NullCryptoEngine::create_crypto_socket(SocketHandle socket, bool is_server) +NullCryptoEngine::create_client_crypto_socket(SocketHandle socket, const SocketSpec &) { - net::tls::ConnectionStatistics::get(is_server).inc_insecure_connections(); + net::tls::ConnectionStatistics::get(false).inc_insecure_connections(); return std::make_unique<NullCryptoSocket>(std::move(socket)); } CryptoSocket::UP -XorCryptoEngine::create_crypto_socket(SocketHandle socket, bool is_server) +NullCryptoEngine::create_server_crypto_socket(SocketHandle socket) { - return std::make_unique<XorCryptoSocket>(std::move(socket), is_server); + net::tls::ConnectionStatistics::get(true).inc_insecure_connections(); + return std::make_unique<NullCryptoSocket>(std::move(socket)); +} + +CryptoSocket::UP +XorCryptoEngine::create_client_crypto_socket(SocketHandle socket, const SocketSpec &) +{ + return std::make_unique<XorCryptoSocket>(std::move(socket), false); +} + +CryptoSocket::UP +XorCryptoEngine::create_server_crypto_socket(SocketHandle socket) +{ + return std::make_unique<XorCryptoSocket>(std::move(socket), true); } } // namespace vespalib diff --git a/vespalib/src/vespa/vespalib/net/crypto_engine.h b/vespalib/src/vespa/vespalib/net/crypto_engine.h index 1cb1305e039..4deacf9a6c7 100644 --- a/vespalib/src/vespa/vespalib/net/crypto_engine.h +++ b/vespalib/src/vespa/vespalib/net/crypto_engine.h @@ -9,6 +9,8 @@ namespace vespalib { +class SocketSpec; + /** * Component responsible for wrapping low-level sockets into * appropriate CryptoSocket instances. This is the top-level interface @@ -17,7 +19,8 @@ namespace vespalib { **/ struct CryptoEngine { using SP = std::shared_ptr<CryptoEngine>; - virtual CryptoSocket::UP create_crypto_socket(SocketHandle socket, bool is_server) = 0; + virtual CryptoSocket::UP create_client_crypto_socket(SocketHandle socket, const SocketSpec &spec) = 0; + virtual CryptoSocket::UP create_server_crypto_socket(SocketHandle socket) = 0; virtual ~CryptoEngine(); static CryptoEngine::SP get_default(); }; @@ -26,7 +29,8 @@ struct CryptoEngine { * Crypto engine without encryption. **/ struct NullCryptoEngine : public CryptoEngine { - CryptoSocket::UP create_crypto_socket(SocketHandle socket, bool is_server) override; + CryptoSocket::UP create_client_crypto_socket(SocketHandle socket, const SocketSpec &spec) override; + CryptoSocket::UP create_server_crypto_socket(SocketHandle socket) override; }; /** @@ -35,7 +39,8 @@ struct NullCryptoEngine : public CryptoEngine { * from TLS. **/ struct XorCryptoEngine : public CryptoEngine { - CryptoSocket::UP create_crypto_socket(SocketHandle socket, bool is_server) override; + CryptoSocket::UP create_client_crypto_socket(SocketHandle socket, const SocketSpec &spec) override; + CryptoSocket::UP create_server_crypto_socket(SocketHandle socket) override; }; } // namespace vespalib diff --git a/vespalib/src/vespa/vespalib/net/socket_spec.cpp b/vespalib/src/vespa/vespalib/net/socket_spec.cpp index d1376ce1dd7..06682086670 100644 --- a/vespalib/src/vespa/vespalib/net/socket_spec.cpp +++ b/vespalib/src/vespa/vespalib/net/socket_spec.cpp @@ -41,6 +41,8 @@ SocketSpec::address(bool server) const return SocketAddress(); } +SocketSpec SocketSpec::invalid; + SocketSpec::SocketSpec(const vespalib::string &spec) : SocketSpec() { diff --git a/vespalib/src/vespa/vespalib/net/socket_spec.h b/vespalib/src/vespa/vespalib/net/socket_spec.h index f28b14573ac..01af382d638 100644 --- a/vespalib/src/vespa/vespalib/net/socket_spec.h +++ b/vespalib/src/vespa/vespalib/net/socket_spec.h @@ -24,6 +24,7 @@ private: : _type(type), _node(node), _port(port) {} SocketAddress address(bool server) const; public: + static SocketSpec invalid; explicit SocketSpec(const vespalib::string &spec); vespalib::string spec() const; SocketSpec replace_host(const vespalib::string &new_host) const; diff --git a/vespalib/src/vespa/vespalib/net/sync_crypto_socket.cpp b/vespalib/src/vespa/vespalib/net/sync_crypto_socket.cpp index 29388035bda..3aa2d3b0683 100644 --- a/vespalib/src/vespa/vespalib/net/sync_crypto_socket.cpp +++ b/vespalib/src/vespa/vespalib/net/sync_crypto_socket.cpp @@ -29,6 +29,25 @@ void set_blocking(int fd) { } // namespace vespalib::<unnamed> +SyncCryptoSocket::UP +SyncCryptoSocket::create(CryptoSocket::UP socket) +{ + set_blocking(socket->get_fd()); + for (;;) { + switch (socket->handshake()) { + case CryptoSocket::HandshakeResult::FAIL: + return std::unique_ptr<SyncCryptoSocket>(nullptr); + case CryptoSocket::HandshakeResult::DONE: + return UP(new SyncCryptoSocket(std::move(socket))); + case CryptoSocket::HandshakeResult::NEED_READ: + case CryptoSocket::HandshakeResult::NEED_WRITE: + break; + case CryptoSocket::HandshakeResult::NEED_WORK: + socket->do_handshake_work(); + } + } +} + SyncCryptoSocket::~SyncCryptoSocket() = default; ssize_t @@ -90,23 +109,15 @@ SyncCryptoSocket::half_close() } SyncCryptoSocket::UP -SyncCryptoSocket::create(CryptoEngine &engine, SocketHandle socket, bool is_server) +SyncCryptoSocket::create_client(CryptoEngine &engine, SocketHandle socket, const SocketSpec &spec) { - auto crypto_socket = engine.create_crypto_socket(std::move(socket), is_server); - set_blocking(crypto_socket->get_fd()); - for (;;) { - switch (crypto_socket->handshake()) { - case CryptoSocket::HandshakeResult::FAIL: - return std::unique_ptr<SyncCryptoSocket>(nullptr); - case CryptoSocket::HandshakeResult::DONE: - return UP(new SyncCryptoSocket(std::move(crypto_socket))); - case CryptoSocket::HandshakeResult::NEED_READ: - case CryptoSocket::HandshakeResult::NEED_WRITE: - break; - case CryptoSocket::HandshakeResult::NEED_WORK: - crypto_socket->do_handshake_work(); - } - } + return create(engine.create_client_crypto_socket(std::move(socket), spec)); +} + +SyncCryptoSocket::UP +SyncCryptoSocket::create_server(CryptoEngine &engine, SocketHandle socket) +{ + return create(engine.create_server_crypto_socket(std::move(socket))); } } // namespace vespalib diff --git a/vespalib/src/vespa/vespalib/net/sync_crypto_socket.h b/vespalib/src/vespa/vespalib/net/sync_crypto_socket.h index 00d6cbca0db..36fcfe12ed9 100644 --- a/vespalib/src/vespa/vespalib/net/sync_crypto_socket.h +++ b/vespalib/src/vespa/vespalib/net/sync_crypto_socket.h @@ -19,17 +19,20 @@ namespace vespalib { **/ class SyncCryptoSocket { +public: + using UP = std::unique_ptr<SyncCryptoSocket>; private: CryptoSocket::UP _socket; SmartBuffer _buffer; SyncCryptoSocket(CryptoSocket::UP socket) : _socket(std::move(socket)), _buffer(0) {} + static UP create(CryptoSocket::UP socket); public: - using UP = std::unique_ptr<SyncCryptoSocket>; ~SyncCryptoSocket(); ssize_t read(char *buf, size_t len); ssize_t write(const char *buf, size_t len); ssize_t half_close(); - static UP create(CryptoEngine &engine, SocketHandle socket, bool is_server); + static UP create_client(CryptoEngine &engine, SocketHandle socket, const SocketSpec &spec); + static UP create_server(CryptoEngine &engine, SocketHandle socket); }; } // namespace vespalib diff --git a/vespalib/src/vespa/vespalib/net/tls/auto_reloading_tls_crypto_engine.cpp b/vespalib/src/vespa/vespalib/net/tls/auto_reloading_tls_crypto_engine.cpp index 5f20280e0e2..c425ab75ce8 100644 --- a/vespalib/src/vespa/vespalib/net/tls/auto_reloading_tls_crypto_engine.cpp +++ b/vespalib/src/vespa/vespalib/net/tls/auto_reloading_tls_crypto_engine.cpp @@ -91,13 +91,22 @@ AutoReloadingTlsCryptoEngine::EngineSP AutoReloadingTlsCryptoEngine::acquire_cur return _current_engine; } -CryptoSocket::UP AutoReloadingTlsCryptoEngine::create_crypto_socket(SocketHandle socket, bool is_server) { - return acquire_current_engine()->create_crypto_socket(std::move(socket), is_server); +CryptoSocket::UP AutoReloadingTlsCryptoEngine::create_client_crypto_socket(SocketHandle socket, const SocketSpec &spec) { + return acquire_current_engine()->create_client_crypto_socket(std::move(socket), spec); +} + +CryptoSocket::UP AutoReloadingTlsCryptoEngine::create_server_crypto_socket(SocketHandle socket) { + return acquire_current_engine()->create_server_crypto_socket(std::move(socket)); +} + +std::unique_ptr<TlsCryptoSocket> +AutoReloadingTlsCryptoEngine::create_tls_client_crypto_socket(SocketHandle socket, const SocketSpec &spec) { + return acquire_current_engine()->create_tls_client_crypto_socket(std::move(socket), spec); } std::unique_ptr<TlsCryptoSocket> -AutoReloadingTlsCryptoEngine::create_tls_crypto_socket(SocketHandle socket, bool is_server) { - return acquire_current_engine()->create_tls_crypto_socket(std::move(socket), is_server); +AutoReloadingTlsCryptoEngine::create_tls_server_crypto_socket(SocketHandle socket) { + return acquire_current_engine()->create_tls_server_crypto_socket(std::move(socket)); } } diff --git a/vespalib/src/vespa/vespalib/net/tls/auto_reloading_tls_crypto_engine.h b/vespalib/src/vespa/vespalib/net/tls/auto_reloading_tls_crypto_engine.h index 6287fdd4f63..e268cbc8f1a 100644 --- a/vespalib/src/vespa/vespalib/net/tls/auto_reloading_tls_crypto_engine.h +++ b/vespalib/src/vespa/vespalib/net/tls/auto_reloading_tls_crypto_engine.h @@ -45,8 +45,10 @@ public: EngineSP acquire_current_engine() const; - CryptoSocket::UP create_crypto_socket(SocketHandle socket, bool is_server) override; - std::unique_ptr<TlsCryptoSocket> create_tls_crypto_socket(SocketHandle socket, bool is_server) override; + CryptoSocket::UP create_client_crypto_socket(SocketHandle socket, const SocketSpec &spec) override; + CryptoSocket::UP create_server_crypto_socket(SocketHandle socket) override; + std::unique_ptr<TlsCryptoSocket> create_tls_client_crypto_socket(SocketHandle socket, const SocketSpec &spec) override; + std::unique_ptr<TlsCryptoSocket> create_tls_server_crypto_socket(SocketHandle socket) override; }; } diff --git a/vespalib/src/vespa/vespalib/net/tls/maybe_tls_crypto_engine.cpp b/vespalib/src/vespa/vespalib/net/tls/maybe_tls_crypto_engine.cpp index 891f8cdab23..f7f0284bded 100644 --- a/vespalib/src/vespa/vespalib/net/tls/maybe_tls_crypto_engine.cpp +++ b/vespalib/src/vespa/vespalib/net/tls/maybe_tls_crypto_engine.cpp @@ -6,15 +6,19 @@ namespace vespalib { CryptoSocket::UP -MaybeTlsCryptoEngine::create_crypto_socket(SocketHandle socket, bool is_server) +MaybeTlsCryptoEngine::create_client_crypto_socket(SocketHandle socket, const SocketSpec &spec) { - if (is_server) { - return std::make_unique<MaybeTlsCryptoSocket>(std::move(socket), _tls_engine); - } else if (_use_tls_when_client) { - return _tls_engine->create_crypto_socket(std::move(socket), false); + if (_use_tls_when_client) { + return _tls_engine->create_client_crypto_socket(std::move(socket), spec); } else { - return _null_engine->create_crypto_socket(std::move(socket), false); + return _null_engine->create_client_crypto_socket(std::move(socket), spec); } } +CryptoSocket::UP +MaybeTlsCryptoEngine::create_server_crypto_socket(SocketHandle socket) +{ + return std::make_unique<MaybeTlsCryptoSocket>(std::move(socket), _tls_engine); +} + } // namespace vespalib diff --git a/vespalib/src/vespa/vespalib/net/tls/maybe_tls_crypto_engine.h b/vespalib/src/vespa/vespalib/net/tls/maybe_tls_crypto_engine.h index 29909fa115d..147a770bc8f 100644 --- a/vespalib/src/vespa/vespalib/net/tls/maybe_tls_crypto_engine.h +++ b/vespalib/src/vespa/vespalib/net/tls/maybe_tls_crypto_engine.h @@ -28,7 +28,8 @@ public: : _null_engine(std::make_shared<NullCryptoEngine>()), _tls_engine(std::move(tls_engine)), _use_tls_when_client(use_tls_when_client) {} - CryptoSocket::UP create_crypto_socket(SocketHandle socket, bool is_server) override; + CryptoSocket::UP create_client_crypto_socket(SocketHandle socket, const SocketSpec &spec) override; + CryptoSocket::UP create_server_crypto_socket(SocketHandle socket) override; }; } // namespace vespalib diff --git a/vespalib/src/vespa/vespalib/net/tls/maybe_tls_crypto_socket.cpp b/vespalib/src/vespa/vespalib/net/tls/maybe_tls_crypto_socket.cpp index 9af6703acbc..8ab6adad2e5 100644 --- a/vespalib/src/vespa/vespalib/net/tls/maybe_tls_crypto_socket.cpp +++ b/vespalib/src/vespa/vespalib/net/tls/maybe_tls_crypto_socket.cpp @@ -50,7 +50,7 @@ public: } if (looksLikeTlsToMe(src.data)) { CryptoSocket::UP &self = _self; // need copy due to self destruction - auto tls_socket = _factory->create_tls_crypto_socket(std::move(_socket), true); + auto tls_socket = _factory->create_tls_server_crypto_socket(std::move(_socket)); tls_socket->inject_read_data(src.data, src.size); self = std::move(tls_socket); return self->handshake(); diff --git a/vespalib/src/vespa/vespalib/net/tls/tls_crypto_engine.cpp b/vespalib/src/vespa/vespalib/net/tls/tls_crypto_engine.cpp index 58d99cc7108..d0475f3e88d 100644 --- a/vespalib/src/vespa/vespalib/net/tls/tls_crypto_engine.cpp +++ b/vespalib/src/vespa/vespalib/net/tls/tls_crypto_engine.cpp @@ -12,9 +12,17 @@ TlsCryptoEngine::TlsCryptoEngine(net::tls::TransportSecurityOptions tls_opts, ne } std::unique_ptr<TlsCryptoSocket> -TlsCryptoEngine::create_tls_crypto_socket(SocketHandle socket, bool is_server) +TlsCryptoEngine::create_tls_client_crypto_socket(SocketHandle socket, const SocketSpec &) { - auto mode = is_server ? net::tls::CryptoCodec::Mode::Server : net::tls::CryptoCodec::Mode::Client; + auto mode = net::tls::CryptoCodec::Mode::Client; + auto codec = net::tls::CryptoCodec::create_default_codec(_tls_ctx, SocketAddress::peer_address(socket.get()), mode); + return std::make_unique<net::tls::CryptoCodecAdapter>(std::move(socket), std::move(codec)); +} + +std::unique_ptr<TlsCryptoSocket> +TlsCryptoEngine::create_tls_server_crypto_socket(SocketHandle socket) +{ + auto mode = net::tls::CryptoCodec::Mode::Server; auto codec = net::tls::CryptoCodec::create_default_codec(_tls_ctx, SocketAddress::peer_address(socket.get()), mode); return std::make_unique<net::tls::CryptoCodecAdapter>(std::move(socket), std::move(codec)); } diff --git a/vespalib/src/vespa/vespalib/net/tls/tls_crypto_engine.h b/vespalib/src/vespa/vespalib/net/tls/tls_crypto_engine.h index dc7d7eaf9ce..5e760cf5585 100644 --- a/vespalib/src/vespa/vespalib/net/tls/tls_crypto_engine.h +++ b/vespalib/src/vespa/vespalib/net/tls/tls_crypto_engine.h @@ -11,7 +11,8 @@ namespace vespalib { class AbstractTlsCryptoEngine : public CryptoEngine { public: - virtual std::unique_ptr<TlsCryptoSocket> create_tls_crypto_socket(SocketHandle socket, bool is_server) = 0; + virtual std::unique_ptr<TlsCryptoSocket> create_tls_client_crypto_socket(SocketHandle socket, const SocketSpec &spec) = 0; + virtual std::unique_ptr<TlsCryptoSocket> create_tls_server_crypto_socket(SocketHandle socket) = 0; }; /** @@ -24,9 +25,13 @@ private: public: explicit TlsCryptoEngine(net::tls::TransportSecurityOptions tls_opts, net::tls::AuthorizationMode authz_mode = net::tls::AuthorizationMode::Enforce); - std::unique_ptr<TlsCryptoSocket> create_tls_crypto_socket(SocketHandle socket, bool is_server) override; - CryptoSocket::UP create_crypto_socket(SocketHandle socket, bool is_server) override { - return create_tls_crypto_socket(std::move(socket), is_server); + std::unique_ptr<TlsCryptoSocket> create_tls_client_crypto_socket(SocketHandle socket, const SocketSpec &spec) override; + std::unique_ptr<TlsCryptoSocket> create_tls_server_crypto_socket(SocketHandle socket) override; + CryptoSocket::UP create_client_crypto_socket(SocketHandle socket, const SocketSpec &spec) override { + return create_tls_client_crypto_socket(std::move(socket), spec); + } + CryptoSocket::UP create_server_crypto_socket(SocketHandle socket) override { + return create_tls_server_crypto_socket(std::move(socket)); } std::shared_ptr<net::tls::TlsContext> tls_context() const noexcept { return _tls_ctx; }; diff --git a/vespalib/src/vespa/vespalib/portal/portal.cpp b/vespalib/src/vespa/vespalib/portal/portal.cpp index 47719ea4c69..a6d44348e5e 100644 --- a/vespalib/src/vespa/vespalib/portal/portal.cpp +++ b/vespalib/src/vespa/vespalib/portal/portal.cpp @@ -143,7 +143,7 @@ Portal::handle_accept(portal::HandleGuard guard, SocketHandle socket) { socket.set_blocking(false); socket.set_keepalive(true); - new HttpConnection(std::move(guard), _reactor, _crypto->create_crypto_socket(std::move(socket), true), + new HttpConnection(std::move(guard), _reactor, _crypto->create_server_crypto_socket(std::move(socket)), [this](HttpConnection *conn) { handle_http(conn); diff --git a/vespalib/src/vespa/vespalib/test/make_tls_options_for_testing.cpp b/vespalib/src/vespa/vespalib/test/make_tls_options_for_testing.cpp index c685bffc23e..dcd2ced8036 100644 --- a/vespalib/src/vespa/vespalib/test/make_tls_options_for_testing.cpp +++ b/vespalib/src/vespa/vespalib/test/make_tls_options_for_testing.cpp @@ -67,6 +67,8 @@ npxYSKVCyo3a/Vo33V8/H0WgOXioKEZJxA== namespace vespalib::test { +SocketSpec local_spec("tcp/localhost:123"); + vespalib::net::tls::TransportSecurityOptions make_tls_options_for_testing() { return vespalib::net::tls::TransportSecurityOptions(ca_pem, cert_pem, key_pem); } diff --git a/vespalib/src/vespa/vespalib/test/make_tls_options_for_testing.h b/vespalib/src/vespa/vespalib/test/make_tls_options_for_testing.h index a1f1d5958f9..41e5d7cc86d 100644 --- a/vespalib/src/vespa/vespalib/test/make_tls_options_for_testing.h +++ b/vespalib/src/vespa/vespalib/test/make_tls_options_for_testing.h @@ -2,11 +2,19 @@ #pragma once +#include <vespa/vespalib/net/socket_spec.h> #include <vespa/vespalib/net/tls/transport_security_options.h> namespace vespalib::test { /** + * A socket spec representing "tcp/localhost:123". Used by unit tests + * performing hostname verification against the tls options created + * below. + **/ +extern SocketSpec local_spec; + +/** * Make security options allowing you to talk to yourself using * TLS. This is intended for testing purposes only. **/ |