From 3506973761972df391cabef40b9858e6c05239f0 Mon Sep 17 00:00:00 2001 From: Craig Perkins Date: Thu, 30 May 2024 16:33:24 -0400 Subject: [PATCH 01/65] Create ExecutionContext and show example with ActionPluginProxy Signed-off-by: Craig Perkins --- .../util/concurrent/ExecutionContext.java | 25 ++++++++++ .../common/util/concurrent/ThreadContext.java | 14 ++++++ .../main/java/org/opensearch/node/Node.java | 6 ++- .../opensearch/plugins/ActionPluginProxy.java | 49 +++++++++++++++++++ 4 files changed, 93 insertions(+), 1 deletion(-) create mode 100644 server/src/main/java/org/opensearch/common/util/concurrent/ExecutionContext.java create mode 100644 server/src/main/java/org/opensearch/plugins/ActionPluginProxy.java diff --git a/server/src/main/java/org/opensearch/common/util/concurrent/ExecutionContext.java b/server/src/main/java/org/opensearch/common/util/concurrent/ExecutionContext.java new file mode 100644 index 0000000000000..bff824173df65 --- /dev/null +++ b/server/src/main/java/org/opensearch/common/util/concurrent/ExecutionContext.java @@ -0,0 +1,25 @@ +/* + * SPDX-License-Identifier: Apache-2.0 + * + * The OpenSearch Contributors require contributions made to + * this file be licensed under the Apache-2.0 license or a + * compatible open source license. + */ + +package org.opensearch.common.util.concurrent; + +public class ExecutionContext { + private final ThreadLocal context = new ThreadLocal<>(); + + public void set(String value) { + context.set(value); + } + + public String get() { + return context.get(); + } + + public void clear() { + context.remove(); + } +} diff --git a/server/src/main/java/org/opensearch/common/util/concurrent/ThreadContext.java b/server/src/main/java/org/opensearch/common/util/concurrent/ThreadContext.java index 6580b0e0085ef..1505be8d8f891 100644 --- a/server/src/main/java/org/opensearch/common/util/concurrent/ThreadContext.java +++ b/server/src/main/java/org/opensearch/common/util/concurrent/ThreadContext.java @@ -115,6 +115,7 @@ public final class ThreadContext implements Writeable { private static final ThreadContextStruct DEFAULT_CONTEXT = new ThreadContextStruct(); private final Map defaultHeader; private final ThreadLocal threadLocal; + private final ExecutionContext executionContext; private final int maxWarningHeaderCount; private final long maxWarningHeaderSize; private final List propagators; @@ -126,6 +127,7 @@ public final class ThreadContext implements Writeable { public ThreadContext(Settings settings) { this.defaultHeader = buildDefaultHeaders(settings); this.threadLocal = ThreadLocal.withInitial(() -> DEFAULT_CONTEXT); + this.executionContext = new ExecutionContext(); this.maxWarningHeaderCount = SETTING_HTTP_MAX_WARNING_HEADER_COUNT.get(settings); this.maxWarningHeaderSize = SETTING_HTTP_MAX_WARNING_HEADER_SIZE.get(settings).getBytes(); this.propagators = new CopyOnWriteArrayList<>(List.of(new TaskThreadContextStatePropagator())); @@ -139,6 +141,18 @@ public void unregisterThreadContextStatePropagator(final ThreadContextStatePropa propagators.remove(Objects.requireNonNull(propagator)); } + public void setExecutionContext(String pluginName) { + this.executionContext.set(pluginName); + } + + public String getExecutionContext() { + return this.executionContext.get(); + } + + public void clearExecutionContext() { + this.executionContext.clear(); + } + /** * Removes the current context and resets a default context. The removed context can be * restored by closing the returned {@link StoredContext}. diff --git a/server/src/main/java/org/opensearch/node/Node.java b/server/src/main/java/org/opensearch/node/Node.java index 04bd31e6a5809..d10b4d38720fd 100644 --- a/server/src/main/java/org/opensearch/node/Node.java +++ b/server/src/main/java/org/opensearch/node/Node.java @@ -185,6 +185,7 @@ import org.opensearch.persistent.PersistentTasksExecutorRegistry; import org.opensearch.persistent.PersistentTasksService; import org.opensearch.plugins.ActionPlugin; +import org.opensearch.plugins.ActionPluginProxy; import org.opensearch.plugins.AnalysisPlugin; import org.opensearch.plugins.CachePlugin; import org.opensearch.plugins.CircuitBreakerPlugin; @@ -979,7 +980,10 @@ protected Node( settingsModule.getClusterSettings(), settingsModule.getSettingsFilter(), threadPool, - pluginsService.filterPlugins(ActionPlugin.class), + pluginsService.filterPlugins(ActionPlugin.class) + .stream() + .map(p -> ActionPluginProxy.newInstance(p, threadPool)) + .collect(Collectors.toList()), client, circuitBreakerService, usageService, diff --git a/server/src/main/java/org/opensearch/plugins/ActionPluginProxy.java b/server/src/main/java/org/opensearch/plugins/ActionPluginProxy.java new file mode 100644 index 0000000000000..93027af54d66c --- /dev/null +++ b/server/src/main/java/org/opensearch/plugins/ActionPluginProxy.java @@ -0,0 +1,49 @@ +/* + * SPDX-License-Identifier: Apache-2.0 + * + * The OpenSearch Contributors require contributions made to + * this file be licensed under the Apache-2.0 license or a + * compatible open source license. + */ + +package org.opensearch.plugins; + +import org.opensearch.threadpool.ThreadPool; + +import java.lang.reflect.InvocationHandler; +import java.lang.reflect.InvocationTargetException; +import java.lang.reflect.Method; +import java.lang.reflect.Proxy; + +public class ActionPluginProxy implements InvocationHandler { + private final ActionPlugin actionPlugin; + private final ThreadPool threadPool; + + public static ActionPlugin newInstance(ActionPlugin obj, ThreadPool threadPool) { + return (ActionPlugin) Proxy.newProxyInstance( + obj.getClass().getClassLoader(), + new Class[] { ActionPlugin.class }, + new ActionPluginProxy(obj, threadPool) + ); + } + + private ActionPluginProxy(ActionPlugin actionPlugin, ThreadPool threadPool) { + this.actionPlugin = actionPlugin; + this.threadPool = threadPool; + } + + @Override + public Object invoke(Object proxy, Method m, Object[] args) throws Throwable { + Object result; + try { + threadPool.getThreadContext().setExecutionContext(((Plugin) actionPlugin).getClass().getName()); + result = m.invoke(actionPlugin, args); + threadPool.getThreadContext().clearExecutionContext(); + } catch (InvocationTargetException e) { + throw e.getTargetException(); + } catch (Exception e) { + throw new RuntimeException("unexpected invocation exception: " + e.getMessage()); + } + return result; + } +} From f8cf238079ba58969c01cdfdd6a9c5c977f6ec2c Mon Sep 17 00:00:00 2001 From: Craig Perkins Date: Thu, 30 May 2024 16:46:45 -0400 Subject: [PATCH 02/65] Only allow core to set the ExecutionContext Signed-off-by: Craig Perkins --- .../opensearch/common/util/concurrent/ExecutionContext.java | 3 +++ 1 file changed, 3 insertions(+) diff --git a/server/src/main/java/org/opensearch/common/util/concurrent/ExecutionContext.java b/server/src/main/java/org/opensearch/common/util/concurrent/ExecutionContext.java index bff824173df65..251454d8ec868 100644 --- a/server/src/main/java/org/opensearch/common/util/concurrent/ExecutionContext.java +++ b/server/src/main/java/org/opensearch/common/util/concurrent/ExecutionContext.java @@ -12,6 +12,9 @@ public class ExecutionContext { private final ThreadLocal context = new ThreadLocal<>(); public void set(String value) { + if (context.get() != null) { + throw new IllegalArgumentException("ExecutionContext already present"); + } context.set(value); } From b6b2a1939427dfe248d1540907fc261703235673 Mon Sep 17 00:00:00 2001 From: Craig Perkins Date: Fri, 31 May 2024 12:35:55 -0400 Subject: [PATCH 03/65] WIP on plugin aware thread context Signed-off-by: Craig Perkins --- .../http/ExecutionContextPluginIT.java | 79 ++++++++++++++++ .../http/TestExecutionContextPlugin.java | 91 +++++++++++++++++++ .../http/TestExecutionContextRestAction.java | 72 +++++++++++++++ .../org/opensearch/action/ActionModule.java | 4 +- .../org/opensearch/rest/RestHandlerProxy.java | 53 +++++++++++ 5 files changed, 298 insertions(+), 1 deletion(-) create mode 100644 qa/smoke-test-http/src/test/java/org/opensearch/http/ExecutionContextPluginIT.java create mode 100644 qa/smoke-test-http/src/test/java/org/opensearch/http/TestExecutionContextPlugin.java create mode 100644 qa/smoke-test-http/src/test/java/org/opensearch/http/TestExecutionContextRestAction.java create mode 100644 server/src/main/java/org/opensearch/rest/RestHandlerProxy.java diff --git a/qa/smoke-test-http/src/test/java/org/opensearch/http/ExecutionContextPluginIT.java b/qa/smoke-test-http/src/test/java/org/opensearch/http/ExecutionContextPluginIT.java new file mode 100644 index 0000000000000..aa777a2f005d5 --- /dev/null +++ b/qa/smoke-test-http/src/test/java/org/opensearch/http/ExecutionContextPluginIT.java @@ -0,0 +1,79 @@ +/* + * SPDX-License-Identifier: Apache-2.0 + * + * The OpenSearch Contributors require contributions made to + * this file be licensed under the Apache-2.0 license or a + * compatible open source license. + */ + +/* + * Licensed to Elasticsearch under one or more contributor + * license agreements. See the NOTICE file distributed with + * this work for additional information regarding copyright + * ownership. Elasticsearch licenses this file to you under + * the Apache License, Version 2.0 (the "License"); you may + * not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, + * software distributed under the License is distributed on an + * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY + * KIND, either express or implied. See the License for the + * specific language governing permissions and limitations + * under the License. + */ +/* + * Modifications Copyright OpenSearch Contributors. See + * GitHub history for details. + */ + +package org.opensearch.http; + +import org.opensearch.client.Request; +import org.opensearch.client.RequestOptions; +import org.opensearch.client.Response; +import org.opensearch.client.ResponseException; +import org.opensearch.plugins.Plugin; +import org.opensearch.test.OpenSearchIntegTestCase.ClusterScope; +import org.opensearch.test.OpenSearchIntegTestCase.Scope; + +import java.io.IOException; +import java.nio.charset.StandardCharsets; +import java.util.ArrayList; +import java.util.Collection; + +import static org.hamcrest.Matchers.equalTo; + +/** + * Test a rest action that sets special response headers + */ +@ClusterScope(scope = Scope.SUITE, supportsDedicatedMasters = false, numDataNodes = 1) +public class ExecutionContextPluginIT extends HttpSmokeTestCase { + + @Override + protected boolean addMockHttpTransport() { + return false; // enable http + } + + @Override + protected Collection> nodePlugins() { + ArrayList> plugins = new ArrayList<>(super.nodePlugins()); + plugins.add(TestExecutionContextPlugin.class); + return plugins; + } + + public void testThatSettingHeadersWorks() throws IOException { + ensureGreen(); + try { + Response response = getRestClient().performRequest(new Request("GET", "/_execution_context")); + System.out.println("Response body: " + new String(response.getEntity().getContent().readAllBytes(), StandardCharsets.UTF_8)); +// fail("request should have failed"); + } catch(ResponseException e) { + Response response = e.getResponse(); + assertThat(response.getStatusLine().getStatusCode(), equalTo(401)); + assertThat(response.getHeader("Secret"), equalTo("required")); + } + } +} diff --git a/qa/smoke-test-http/src/test/java/org/opensearch/http/TestExecutionContextPlugin.java b/qa/smoke-test-http/src/test/java/org/opensearch/http/TestExecutionContextPlugin.java new file mode 100644 index 0000000000000..5fa301a271308 --- /dev/null +++ b/qa/smoke-test-http/src/test/java/org/opensearch/http/TestExecutionContextPlugin.java @@ -0,0 +1,91 @@ +/* + * SPDX-License-Identifier: Apache-2.0 + * + * The OpenSearch Contributors require contributions made to + * this file be licensed under the Apache-2.0 license or a + * compatible open source license. + */ + +/* + * Licensed to Elasticsearch under one or more contributor + * license agreements. See the NOTICE file distributed with + * this work for additional information regarding copyright + * ownership. Elasticsearch licenses this file to you under + * the Apache License, Version 2.0 (the "License"); you may + * not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, + * software distributed under the License is distributed on an + * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY + * KIND, either express or implied. See the License for the + * specific language governing permissions and limitations + * under the License. + */ + +/* + * Modifications Copyright OpenSearch Contributors. See + * GitHub history for details. + */ + +package org.opensearch.http; + +import org.opensearch.client.Client; +import org.opensearch.cluster.metadata.IndexNameExpressionResolver; +import org.opensearch.cluster.node.DiscoveryNodes; +import org.opensearch.cluster.service.ClusterService; +import org.opensearch.common.settings.ClusterSettings; +import org.opensearch.common.settings.IndexScopedSettings; +import org.opensearch.common.settings.Settings; +import org.opensearch.common.settings.SettingsFilter; +import org.opensearch.core.common.io.stream.NamedWriteableRegistry; +import org.opensearch.core.xcontent.NamedXContentRegistry; +import org.opensearch.env.Environment; +import org.opensearch.env.NodeEnvironment; +import org.opensearch.plugins.ActionPlugin; +import org.opensearch.plugins.Plugin; +import org.opensearch.repositories.RepositoriesService; +import org.opensearch.rest.RestController; +import org.opensearch.rest.RestHandler; +import org.opensearch.script.ScriptService; +import org.opensearch.threadpool.ThreadPool; +import org.opensearch.watcher.ResourceWatcherService; + +import java.util.Collection; +import java.util.Collections; +import java.util.List; +import java.util.function.Supplier; + +import static java.util.Collections.singletonList; + +public class TestExecutionContextPlugin extends Plugin implements ActionPlugin { + + private ThreadPool threadPool; + + @Override + public Collection createComponents( + Client client, + ClusterService clusterService, + ThreadPool threadPool, + ResourceWatcherService resourceWatcherService, + ScriptService scriptService, + NamedXContentRegistry xContentRegistry, + Environment environment, + NodeEnvironment nodeEnvironment, + NamedWriteableRegistry namedWriteableRegistry, + IndexNameExpressionResolver expressionResolver, + Supplier repositoriesServiceSupplier + ) { + this.threadPool = threadPool; + return Collections.emptyList(); + } + + @Override + public List getRestHandlers(Settings settings, RestController restController, ClusterSettings clusterSettings, + IndexScopedSettings indexScopedSettings, SettingsFilter settingsFilter, IndexNameExpressionResolver indexNameExpressionResolver, + Supplier nodesInCluster) { + return singletonList(new TestExecutionContextRestAction(threadPool)); + } +} diff --git a/qa/smoke-test-http/src/test/java/org/opensearch/http/TestExecutionContextRestAction.java b/qa/smoke-test-http/src/test/java/org/opensearch/http/TestExecutionContextRestAction.java new file mode 100644 index 0000000000000..a2562c8efa027 --- /dev/null +++ b/qa/smoke-test-http/src/test/java/org/opensearch/http/TestExecutionContextRestAction.java @@ -0,0 +1,72 @@ +/* + * SPDX-License-Identifier: Apache-2.0 + * + * The OpenSearch Contributors require contributions made to + * this file be licensed under the Apache-2.0 license or a + * compatible open source license. + */ + +/* + * Licensed to Elasticsearch under one or more contributor + * license agreements. See the NOTICE file distributed with + * this work for additional information regarding copyright + * ownership. Elasticsearch licenses this file to you under + * the Apache License, Version 2.0 (the "License"); you may + * not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, + * software distributed under the License is distributed on an + * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY + * KIND, either express or implied. See the License for the + * specific language governing permissions and limitations + * under the License. + */ +/* + * Modifications Copyright OpenSearch Contributors. See + * GitHub history for details. + */ + +package org.opensearch.http; + +import org.opensearch.client.node.NodeClient; +import org.opensearch.core.rest.RestStatus; +import org.opensearch.rest.BaseRestHandler; +import org.opensearch.rest.BytesRestResponse; +import org.opensearch.rest.RestRequest; +import org.opensearch.rest.RestResponse; +import org.opensearch.threadpool.ThreadPool; + +import java.util.List; + +import static java.util.Collections.singletonList; +import static org.opensearch.rest.RestRequest.Method.GET; + +public class TestExecutionContextRestAction extends BaseRestHandler { + + private final ThreadPool threadPool; + + public TestExecutionContextRestAction(ThreadPool threadPool) { + this.threadPool = threadPool; + } + + @Override + public List routes() { + return singletonList(new Route(GET, "/_execution_context")); + } + + @Override + public String getName() { + return "test_execution_context_action"; + } + + @Override + public RestChannelConsumer prepareRequest(RestRequest request, NodeClient client) { + System.out.println("Plugin execution context: " + threadPool.getThreadContext().getExecutionContext()); + threadPool.getThreadContext().setExecutionContext("should-not-allow-plugin-to-set-execution-context"); + RestResponse response = new BytesRestResponse(RestStatus.OK, "Should not happen"); + return channel -> channel.sendResponse(response); + } +} diff --git a/server/src/main/java/org/opensearch/action/ActionModule.java b/server/src/main/java/org/opensearch/action/ActionModule.java index 5e2b62614fc47..893dadd432f8f 100644 --- a/server/src/main/java/org/opensearch/action/ActionModule.java +++ b/server/src/main/java/org/opensearch/action/ActionModule.java @@ -322,6 +322,7 @@ import org.opensearch.rest.NamedRoute; import org.opensearch.rest.RestController; import org.opensearch.rest.RestHandler; +import org.opensearch.rest.RestHandlerProxy; import org.opensearch.rest.RestHeaderDefinition; import org.opensearch.rest.action.RestFieldCapabilitiesAction; import org.opensearch.rest.action.RestMainAction; @@ -993,7 +994,8 @@ public void initRestHandlers(Supplier nodesInCluster) { indexNameExpressionResolver, nodesInCluster )) { - registerHandler.accept(handler); + RestHandler handlerProxy = RestHandlerProxy.newInstance(handler, threadPool, plugin); + registerHandler.accept(handlerProxy); } } registerHandler.accept(new RestCatAction(catActions)); diff --git a/server/src/main/java/org/opensearch/rest/RestHandlerProxy.java b/server/src/main/java/org/opensearch/rest/RestHandlerProxy.java new file mode 100644 index 0000000000000..f1c3081214e6e --- /dev/null +++ b/server/src/main/java/org/opensearch/rest/RestHandlerProxy.java @@ -0,0 +1,53 @@ +/* + * SPDX-License-Identifier: Apache-2.0 + * + * The OpenSearch Contributors require contributions made to + * this file be licensed under the Apache-2.0 license or a + * compatible open source license. + */ + +package org.opensearch.rest; + +import org.opensearch.plugins.ActionPlugin; +import org.opensearch.plugins.Plugin; +import org.opensearch.threadpool.ThreadPool; + +import java.lang.reflect.InvocationHandler; +import java.lang.reflect.InvocationTargetException; +import java.lang.reflect.Method; +import java.lang.reflect.Proxy; + +public class RestHandlerProxy implements InvocationHandler { + private final RestHandler restHandler; + private final ThreadPool threadPool; + private final ActionPlugin plugin; + + public static RestHandler newInstance(RestHandler obj, ThreadPool threadPool, ActionPlugin plugin) { + return (RestHandler) Proxy.newProxyInstance( + obj.getClass().getClassLoader(), + new Class[] { RestHandler.class }, + new RestHandlerProxy(obj, threadPool, plugin) + ); + } + + private RestHandlerProxy(RestHandler restHandler, ThreadPool threadPool, ActionPlugin plugin) { + this.restHandler = restHandler; + this.threadPool = threadPool; + this.plugin = plugin; + } + + @Override + public Object invoke(Object proxy, Method m, Object[] args) throws Throwable { + Object result; + try { + threadPool.getThreadContext().setExecutionContext(Proxy.getInvocationHandler(plugin).getClass().getName()); + result = m.invoke(restHandler, args); + threadPool.getThreadContext().clearExecutionContext(); + } catch (InvocationTargetException e) { + throw e.getTargetException(); + } catch (Exception e) { + throw new RuntimeException("unexpected invocation exception: " + e.getMessage()); + } + return result; + } +} From 8165f05d401ba0b8ec7acd824c6bdd03c714e673 Mon Sep 17 00:00:00 2001 From: Craig Perkins Date: Fri, 31 May 2024 15:09:32 -0400 Subject: [PATCH 04/65] Plugin Aware API Handling Signed-off-by: Craig Perkins --- .../opensearch/http/ExecutionContextPluginIT.java | 12 +++++++----- server/src/main/java/org/opensearch/node/Node.java | 6 +----- .../java/org/opensearch/rest/RestHandlerProxy.java | 3 +-- 3 files changed, 9 insertions(+), 12 deletions(-) diff --git a/qa/smoke-test-http/src/test/java/org/opensearch/http/ExecutionContextPluginIT.java b/qa/smoke-test-http/src/test/java/org/opensearch/http/ExecutionContextPluginIT.java index aa777a2f005d5..f6c6e82888bff 100644 --- a/qa/smoke-test-http/src/test/java/org/opensearch/http/ExecutionContextPluginIT.java +++ b/qa/smoke-test-http/src/test/java/org/opensearch/http/ExecutionContextPluginIT.java @@ -44,6 +44,8 @@ import java.util.ArrayList; import java.util.Collection; +import static org.hamcrest.Matchers.contains; +import static org.hamcrest.Matchers.containsString; import static org.hamcrest.Matchers.equalTo; /** @@ -64,16 +66,16 @@ protected Collection> nodePlugins() { return plugins; } - public void testThatSettingHeadersWorks() throws IOException { + public void testThatPluginCannotOverrideExecutionContext() throws IOException { ensureGreen(); try { Response response = getRestClient().performRequest(new Request("GET", "/_execution_context")); - System.out.println("Response body: " + new String(response.getEntity().getContent().readAllBytes(), StandardCharsets.UTF_8)); -// fail("request should have failed"); + fail("request should have failed"); } catch(ResponseException e) { Response response = e.getResponse(); - assertThat(response.getStatusLine().getStatusCode(), equalTo(401)); - assertThat(response.getHeader("Secret"), equalTo("required")); + String responseBody = new String(response.getEntity().getContent().readAllBytes(), StandardCharsets.UTF_8); + assertThat(response.getStatusLine().getStatusCode(), equalTo(400)); + assertThat(responseBody, containsString("ExecutionContext already present")); } } } diff --git a/server/src/main/java/org/opensearch/node/Node.java b/server/src/main/java/org/opensearch/node/Node.java index d10b4d38720fd..04bd31e6a5809 100644 --- a/server/src/main/java/org/opensearch/node/Node.java +++ b/server/src/main/java/org/opensearch/node/Node.java @@ -185,7 +185,6 @@ import org.opensearch.persistent.PersistentTasksExecutorRegistry; import org.opensearch.persistent.PersistentTasksService; import org.opensearch.plugins.ActionPlugin; -import org.opensearch.plugins.ActionPluginProxy; import org.opensearch.plugins.AnalysisPlugin; import org.opensearch.plugins.CachePlugin; import org.opensearch.plugins.CircuitBreakerPlugin; @@ -980,10 +979,7 @@ protected Node( settingsModule.getClusterSettings(), settingsModule.getSettingsFilter(), threadPool, - pluginsService.filterPlugins(ActionPlugin.class) - .stream() - .map(p -> ActionPluginProxy.newInstance(p, threadPool)) - .collect(Collectors.toList()), + pluginsService.filterPlugins(ActionPlugin.class), client, circuitBreakerService, usageService, diff --git a/server/src/main/java/org/opensearch/rest/RestHandlerProxy.java b/server/src/main/java/org/opensearch/rest/RestHandlerProxy.java index f1c3081214e6e..945e927c40732 100644 --- a/server/src/main/java/org/opensearch/rest/RestHandlerProxy.java +++ b/server/src/main/java/org/opensearch/rest/RestHandlerProxy.java @@ -9,7 +9,6 @@ package org.opensearch.rest; import org.opensearch.plugins.ActionPlugin; -import org.opensearch.plugins.Plugin; import org.opensearch.threadpool.ThreadPool; import java.lang.reflect.InvocationHandler; @@ -40,7 +39,7 @@ private RestHandlerProxy(RestHandler restHandler, ThreadPool threadPool, ActionP public Object invoke(Object proxy, Method m, Object[] args) throws Throwable { Object result; try { - threadPool.getThreadContext().setExecutionContext(Proxy.getInvocationHandler(plugin).getClass().getName()); + threadPool.getThreadContext().setExecutionContext(plugin.getClass().getName()); result = m.invoke(restHandler, args); threadPool.getThreadContext().clearExecutionContext(); } catch (InvocationTargetException e) { From 5b989d6cd8bdcafee7923d9d467ebf0fcc685f6c Mon Sep 17 00:00:00 2001 From: Craig Perkins Date: Tue, 11 Jun 2024 16:08:40 -0400 Subject: [PATCH 05/65] Add test to verify that ExecutionContext is being populated during RestHandling Signed-off-by: Craig Perkins --- .../http/ExecutionContextPluginGetIT.java | 51 +++++++++++++ ....java => ExecutionContextPluginSetIT.java} | 28 +------- .../http/TestExecutionContextPlugin.java | 26 +------ .../http/TestExecutionContextRestAction.java | 72 ------------------- .../TestGetExecutionContextRestAction.java | 49 +++++++++++++ .../TestSetExecutionContextRestAction.java | 48 +++++++++++++ .../util/concurrent/ExecutionContext.java | 4 ++ .../opensearch/plugins/ActionPluginProxy.java | 49 ------------- .../org/opensearch/rest/RestHandlerProxy.java | 4 ++ 9 files changed, 159 insertions(+), 172 deletions(-) create mode 100644 qa/smoke-test-http/src/test/java/org/opensearch/http/ExecutionContextPluginGetIT.java rename qa/smoke-test-http/src/test/java/org/opensearch/http/{ExecutionContextPluginIT.java => ExecutionContextPluginSetIT.java} (65%) delete mode 100644 qa/smoke-test-http/src/test/java/org/opensearch/http/TestExecutionContextRestAction.java create mode 100644 qa/smoke-test-http/src/test/java/org/opensearch/http/TestGetExecutionContextRestAction.java create mode 100644 qa/smoke-test-http/src/test/java/org/opensearch/http/TestSetExecutionContextRestAction.java delete mode 100644 server/src/main/java/org/opensearch/plugins/ActionPluginProxy.java diff --git a/qa/smoke-test-http/src/test/java/org/opensearch/http/ExecutionContextPluginGetIT.java b/qa/smoke-test-http/src/test/java/org/opensearch/http/ExecutionContextPluginGetIT.java new file mode 100644 index 0000000000000..95f8898862357 --- /dev/null +++ b/qa/smoke-test-http/src/test/java/org/opensearch/http/ExecutionContextPluginGetIT.java @@ -0,0 +1,51 @@ +/* + * SPDX-License-Identifier: Apache-2.0 + * + * The OpenSearch Contributors require contributions made to + * this file be licensed under the Apache-2.0 license or a + * compatible open source license. + */ + +package org.opensearch.http; + +import org.opensearch.client.Request; +import org.opensearch.client.Response; +import org.opensearch.client.ResponseException; +import org.opensearch.plugins.Plugin; +import org.opensearch.test.OpenSearchIntegTestCase.ClusterScope; +import org.opensearch.test.OpenSearchIntegTestCase.Scope; + +import java.io.IOException; +import java.nio.charset.StandardCharsets; +import java.util.ArrayList; +import java.util.Collection; + +import static org.hamcrest.Matchers.containsString; +import static org.hamcrest.Matchers.equalTo; + +/** + * Test a rest action that sets special response headers + */ +@ClusterScope(scope = Scope.SUITE, supportsDedicatedMasters = false, numDataNodes = 1) +public class ExecutionContextPluginGetIT extends HttpSmokeTestCase { + + @Override + protected boolean addMockHttpTransport() { + return false; // enable http + } + + @Override + protected Collection> nodePlugins() { + ArrayList> plugins = new ArrayList<>(super.nodePlugins()); + plugins.add(TestExecutionContextPlugin.class); + return plugins; + } + + public void testGetExecutionContext() throws IOException { + ensureGreen(); + Response response = getRestClient().performRequest(new Request("GET", "/_get_execution_context")); + String responseBody = new String(response.getEntity().getContent().readAllBytes(), StandardCharsets.UTF_8); + assertThat(response.getStatusLine().getStatusCode(), equalTo(200)); + assertThat(responseBody, containsString(TestExecutionContextPlugin.class.getName())); + } +} diff --git a/qa/smoke-test-http/src/test/java/org/opensearch/http/ExecutionContextPluginIT.java b/qa/smoke-test-http/src/test/java/org/opensearch/http/ExecutionContextPluginSetIT.java similarity index 65% rename from qa/smoke-test-http/src/test/java/org/opensearch/http/ExecutionContextPluginIT.java rename to qa/smoke-test-http/src/test/java/org/opensearch/http/ExecutionContextPluginSetIT.java index f6c6e82888bff..8f7ff2702eb4c 100644 --- a/qa/smoke-test-http/src/test/java/org/opensearch/http/ExecutionContextPluginIT.java +++ b/qa/smoke-test-http/src/test/java/org/opensearch/http/ExecutionContextPluginSetIT.java @@ -6,33 +6,9 @@ * compatible open source license. */ -/* - * Licensed to Elasticsearch under one or more contributor - * license agreements. See the NOTICE file distributed with - * this work for additional information regarding copyright - * ownership. Elasticsearch licenses this file to you under - * the Apache License, Version 2.0 (the "License"); you may - * not use this file except in compliance with the License. - * You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, - * software distributed under the License is distributed on an - * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY - * KIND, either express or implied. See the License for the - * specific language governing permissions and limitations - * under the License. - */ -/* - * Modifications Copyright OpenSearch Contributors. See - * GitHub history for details. - */ - package org.opensearch.http; import org.opensearch.client.Request; -import org.opensearch.client.RequestOptions; import org.opensearch.client.Response; import org.opensearch.client.ResponseException; import org.opensearch.plugins.Plugin; @@ -52,7 +28,7 @@ * Test a rest action that sets special response headers */ @ClusterScope(scope = Scope.SUITE, supportsDedicatedMasters = false, numDataNodes = 1) -public class ExecutionContextPluginIT extends HttpSmokeTestCase { +public class ExecutionContextPluginSetIT extends HttpSmokeTestCase { @Override protected boolean addMockHttpTransport() { @@ -69,7 +45,7 @@ protected Collection> nodePlugins() { public void testThatPluginCannotOverrideExecutionContext() throws IOException { ensureGreen(); try { - Response response = getRestClient().performRequest(new Request("GET", "/_execution_context")); + Response response = getRestClient().performRequest(new Request("POST", "/_set_execution_context")); fail("request should have failed"); } catch(ResponseException e) { Response response = e.getResponse(); diff --git a/qa/smoke-test-http/src/test/java/org/opensearch/http/TestExecutionContextPlugin.java b/qa/smoke-test-http/src/test/java/org/opensearch/http/TestExecutionContextPlugin.java index 5fa301a271308..0f1f8eac9ff7c 100644 --- a/qa/smoke-test-http/src/test/java/org/opensearch/http/TestExecutionContextPlugin.java +++ b/qa/smoke-test-http/src/test/java/org/opensearch/http/TestExecutionContextPlugin.java @@ -6,30 +6,6 @@ * compatible open source license. */ -/* - * Licensed to Elasticsearch under one or more contributor - * license agreements. See the NOTICE file distributed with - * this work for additional information regarding copyright - * ownership. Elasticsearch licenses this file to you under - * the Apache License, Version 2.0 (the "License"); you may - * not use this file except in compliance with the License. - * You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, - * software distributed under the License is distributed on an - * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY - * KIND, either express or implied. See the License for the - * specific language governing permissions and limitations - * under the License. - */ - -/* - * Modifications Copyright OpenSearch Contributors. See - * GitHub history for details. - */ - package org.opensearch.http; import org.opensearch.client.Client; @@ -86,6 +62,6 @@ public Collection createComponents( public List getRestHandlers(Settings settings, RestController restController, ClusterSettings clusterSettings, IndexScopedSettings indexScopedSettings, SettingsFilter settingsFilter, IndexNameExpressionResolver indexNameExpressionResolver, Supplier nodesInCluster) { - return singletonList(new TestExecutionContextRestAction(threadPool)); + return List.of(new TestSetExecutionContextRestAction(threadPool), new TestGetExecutionContextRestAction(threadPool)); } } diff --git a/qa/smoke-test-http/src/test/java/org/opensearch/http/TestExecutionContextRestAction.java b/qa/smoke-test-http/src/test/java/org/opensearch/http/TestExecutionContextRestAction.java deleted file mode 100644 index a2562c8efa027..0000000000000 --- a/qa/smoke-test-http/src/test/java/org/opensearch/http/TestExecutionContextRestAction.java +++ /dev/null @@ -1,72 +0,0 @@ -/* - * SPDX-License-Identifier: Apache-2.0 - * - * The OpenSearch Contributors require contributions made to - * this file be licensed under the Apache-2.0 license or a - * compatible open source license. - */ - -/* - * Licensed to Elasticsearch under one or more contributor - * license agreements. See the NOTICE file distributed with - * this work for additional information regarding copyright - * ownership. Elasticsearch licenses this file to you under - * the Apache License, Version 2.0 (the "License"); you may - * not use this file except in compliance with the License. - * You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, - * software distributed under the License is distributed on an - * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY - * KIND, either express or implied. See the License for the - * specific language governing permissions and limitations - * under the License. - */ -/* - * Modifications Copyright OpenSearch Contributors. See - * GitHub history for details. - */ - -package org.opensearch.http; - -import org.opensearch.client.node.NodeClient; -import org.opensearch.core.rest.RestStatus; -import org.opensearch.rest.BaseRestHandler; -import org.opensearch.rest.BytesRestResponse; -import org.opensearch.rest.RestRequest; -import org.opensearch.rest.RestResponse; -import org.opensearch.threadpool.ThreadPool; - -import java.util.List; - -import static java.util.Collections.singletonList; -import static org.opensearch.rest.RestRequest.Method.GET; - -public class TestExecutionContextRestAction extends BaseRestHandler { - - private final ThreadPool threadPool; - - public TestExecutionContextRestAction(ThreadPool threadPool) { - this.threadPool = threadPool; - } - - @Override - public List routes() { - return singletonList(new Route(GET, "/_execution_context")); - } - - @Override - public String getName() { - return "test_execution_context_action"; - } - - @Override - public RestChannelConsumer prepareRequest(RestRequest request, NodeClient client) { - System.out.println("Plugin execution context: " + threadPool.getThreadContext().getExecutionContext()); - threadPool.getThreadContext().setExecutionContext("should-not-allow-plugin-to-set-execution-context"); - RestResponse response = new BytesRestResponse(RestStatus.OK, "Should not happen"); - return channel -> channel.sendResponse(response); - } -} diff --git a/qa/smoke-test-http/src/test/java/org/opensearch/http/TestGetExecutionContextRestAction.java b/qa/smoke-test-http/src/test/java/org/opensearch/http/TestGetExecutionContextRestAction.java new file mode 100644 index 0000000000000..3e796bf7a14da --- /dev/null +++ b/qa/smoke-test-http/src/test/java/org/opensearch/http/TestGetExecutionContextRestAction.java @@ -0,0 +1,49 @@ +/* + * SPDX-License-Identifier: Apache-2.0 + * + * The OpenSearch Contributors require contributions made to + * this file be licensed under the Apache-2.0 license or a + * compatible open source license. + */ + +package org.opensearch.http; + +import org.opensearch.client.node.NodeClient; +import org.opensearch.core.rest.RestStatus; +import org.opensearch.rest.BaseRestHandler; +import org.opensearch.rest.BytesRestResponse; +import org.opensearch.rest.RestRequest; +import org.opensearch.rest.RestResponse; +import org.opensearch.threadpool.ThreadPool; + +import java.util.List; + +import static java.util.Collections.singletonList; +import static org.opensearch.rest.RestRequest.Method.GET; +import static org.opensearch.rest.RestRequest.Method.POST; + +public class TestGetExecutionContextRestAction extends BaseRestHandler { + + private final ThreadPool threadPool; + + public TestGetExecutionContextRestAction(ThreadPool threadPool) { + this.threadPool = threadPool; + } + + @Override + public List routes() { + return singletonList(new Route(GET, "/_get_execution_context")); + } + + @Override + public String getName() { + return "test_get_execution_context_action"; + } + + @Override + public RestChannelConsumer prepareRequest(RestRequest request, NodeClient client) { + String pluginMainClass = threadPool.getThreadContext().getExecutionContext(); + RestResponse response = new BytesRestResponse(RestStatus.OK, pluginMainClass); + return channel -> channel.sendResponse(response); + } +} diff --git a/qa/smoke-test-http/src/test/java/org/opensearch/http/TestSetExecutionContextRestAction.java b/qa/smoke-test-http/src/test/java/org/opensearch/http/TestSetExecutionContextRestAction.java new file mode 100644 index 0000000000000..8c33eb8787720 --- /dev/null +++ b/qa/smoke-test-http/src/test/java/org/opensearch/http/TestSetExecutionContextRestAction.java @@ -0,0 +1,48 @@ +/* + * SPDX-License-Identifier: Apache-2.0 + * + * The OpenSearch Contributors require contributions made to + * this file be licensed under the Apache-2.0 license or a + * compatible open source license. + */ + +package org.opensearch.http; + +import org.opensearch.client.node.NodeClient; +import org.opensearch.core.rest.RestStatus; +import org.opensearch.rest.BaseRestHandler; +import org.opensearch.rest.BytesRestResponse; +import org.opensearch.rest.RestRequest; +import org.opensearch.rest.RestResponse; +import org.opensearch.threadpool.ThreadPool; + +import java.util.List; + +import static java.util.Collections.singletonList; +import static org.opensearch.rest.RestRequest.Method.POST; + +public class TestSetExecutionContextRestAction extends BaseRestHandler { + + private final ThreadPool threadPool; + + public TestSetExecutionContextRestAction(ThreadPool threadPool) { + this.threadPool = threadPool; + } + + @Override + public List routes() { + return singletonList(new Route(POST, "/_set_execution_context")); + } + + @Override + public String getName() { + return "test_set_execution_context_action"; + } + + @Override + public RestChannelConsumer prepareRequest(RestRequest request, NodeClient client) { + threadPool.getThreadContext().setExecutionContext("should-not-allow-plugin-to-set-execution-context"); + RestResponse response = new BytesRestResponse(RestStatus.OK, "Should not happen"); + return channel -> channel.sendResponse(response); + } +} diff --git a/server/src/main/java/org/opensearch/common/util/concurrent/ExecutionContext.java b/server/src/main/java/org/opensearch/common/util/concurrent/ExecutionContext.java index 251454d8ec868..b32c7c39ffd27 100644 --- a/server/src/main/java/org/opensearch/common/util/concurrent/ExecutionContext.java +++ b/server/src/main/java/org/opensearch/common/util/concurrent/ExecutionContext.java @@ -8,6 +8,10 @@ package org.opensearch.common.util.concurrent; +/** + * An ExecutionContext is a singular header within ThreadLocal that contains the identity of a plugin that is on + * the path of execution. + */ public class ExecutionContext { private final ThreadLocal context = new ThreadLocal<>(); diff --git a/server/src/main/java/org/opensearch/plugins/ActionPluginProxy.java b/server/src/main/java/org/opensearch/plugins/ActionPluginProxy.java deleted file mode 100644 index 93027af54d66c..0000000000000 --- a/server/src/main/java/org/opensearch/plugins/ActionPluginProxy.java +++ /dev/null @@ -1,49 +0,0 @@ -/* - * SPDX-License-Identifier: Apache-2.0 - * - * The OpenSearch Contributors require contributions made to - * this file be licensed under the Apache-2.0 license or a - * compatible open source license. - */ - -package org.opensearch.plugins; - -import org.opensearch.threadpool.ThreadPool; - -import java.lang.reflect.InvocationHandler; -import java.lang.reflect.InvocationTargetException; -import java.lang.reflect.Method; -import java.lang.reflect.Proxy; - -public class ActionPluginProxy implements InvocationHandler { - private final ActionPlugin actionPlugin; - private final ThreadPool threadPool; - - public static ActionPlugin newInstance(ActionPlugin obj, ThreadPool threadPool) { - return (ActionPlugin) Proxy.newProxyInstance( - obj.getClass().getClassLoader(), - new Class[] { ActionPlugin.class }, - new ActionPluginProxy(obj, threadPool) - ); - } - - private ActionPluginProxy(ActionPlugin actionPlugin, ThreadPool threadPool) { - this.actionPlugin = actionPlugin; - this.threadPool = threadPool; - } - - @Override - public Object invoke(Object proxy, Method m, Object[] args) throws Throwable { - Object result; - try { - threadPool.getThreadContext().setExecutionContext(((Plugin) actionPlugin).getClass().getName()); - result = m.invoke(actionPlugin, args); - threadPool.getThreadContext().clearExecutionContext(); - } catch (InvocationTargetException e) { - throw e.getTargetException(); - } catch (Exception e) { - throw new RuntimeException("unexpected invocation exception: " + e.getMessage()); - } - return result; - } -} diff --git a/server/src/main/java/org/opensearch/rest/RestHandlerProxy.java b/server/src/main/java/org/opensearch/rest/RestHandlerProxy.java index 945e927c40732..be01b000b683d 100644 --- a/server/src/main/java/org/opensearch/rest/RestHandlerProxy.java +++ b/server/src/main/java/org/opensearch/rest/RestHandlerProxy.java @@ -16,6 +16,10 @@ import java.lang.reflect.Method; import java.lang.reflect.Proxy; +/** + * RestHandlerProxy is a wrapper around {@link RestHandler} that populates the ExecutionContext prior + * to delegating execution to a plugin for handling a REST Request + */ public class RestHandlerProxy implements InvocationHandler { private final RestHandler restHandler; private final ThreadPool threadPool; From eec8b96a1b94be99ea9619eb8bc9125b5faed3b6 Mon Sep 17 00:00:00 2001 From: Craig Perkins Date: Tue, 9 Jul 2024 22:37:05 -0400 Subject: [PATCH 06/65] Clear context in a finally block Signed-off-by: Craig Perkins --- server/src/main/java/org/opensearch/rest/RestHandlerProxy.java | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/server/src/main/java/org/opensearch/rest/RestHandlerProxy.java b/server/src/main/java/org/opensearch/rest/RestHandlerProxy.java index be01b000b683d..cda1cdfc8c4d3 100644 --- a/server/src/main/java/org/opensearch/rest/RestHandlerProxy.java +++ b/server/src/main/java/org/opensearch/rest/RestHandlerProxy.java @@ -45,11 +45,12 @@ public Object invoke(Object proxy, Method m, Object[] args) throws Throwable { try { threadPool.getThreadContext().setExecutionContext(plugin.getClass().getName()); result = m.invoke(restHandler, args); - threadPool.getThreadContext().clearExecutionContext(); } catch (InvocationTargetException e) { throw e.getTargetException(); } catch (Exception e) { throw new RuntimeException("unexpected invocation exception: " + e.getMessage()); + } finally { + threadPool.getThreadContext().clearExecutionContext(); } return result; } From 8a986185cf9c46e1349fd0ad2d7058e27898be56 Mon Sep 17 00:00:00 2001 From: Craig Perkins Date: Wed, 10 Jul 2024 17:00:11 -0400 Subject: [PATCH 07/65] Create switchContext method in ThreadContext and make pluginExecutionStack a stack Signed-off-by: Craig Perkins --- .../http/ExecutionContextPluginSetIT.java | 57 ------------------- .../http/TestExecutionContextPlugin.java | 2 +- .../TestGetExecutionContextRestAction.java | 5 +- .../TestSetExecutionContextRestAction.java | 48 ---------------- .../util/concurrent/ExecutionContext.java | 36 ++++++++---- .../common/util/concurrent/ThreadContext.java | 32 +++++++++-- .../org/opensearch/rest/RestHandlerProxy.java | 7 +-- 7 files changed, 60 insertions(+), 127 deletions(-) delete mode 100644 qa/smoke-test-http/src/test/java/org/opensearch/http/ExecutionContextPluginSetIT.java delete mode 100644 qa/smoke-test-http/src/test/java/org/opensearch/http/TestSetExecutionContextRestAction.java diff --git a/qa/smoke-test-http/src/test/java/org/opensearch/http/ExecutionContextPluginSetIT.java b/qa/smoke-test-http/src/test/java/org/opensearch/http/ExecutionContextPluginSetIT.java deleted file mode 100644 index 8f7ff2702eb4c..0000000000000 --- a/qa/smoke-test-http/src/test/java/org/opensearch/http/ExecutionContextPluginSetIT.java +++ /dev/null @@ -1,57 +0,0 @@ -/* - * SPDX-License-Identifier: Apache-2.0 - * - * The OpenSearch Contributors require contributions made to - * this file be licensed under the Apache-2.0 license or a - * compatible open source license. - */ - -package org.opensearch.http; - -import org.opensearch.client.Request; -import org.opensearch.client.Response; -import org.opensearch.client.ResponseException; -import org.opensearch.plugins.Plugin; -import org.opensearch.test.OpenSearchIntegTestCase.ClusterScope; -import org.opensearch.test.OpenSearchIntegTestCase.Scope; - -import java.io.IOException; -import java.nio.charset.StandardCharsets; -import java.util.ArrayList; -import java.util.Collection; - -import static org.hamcrest.Matchers.contains; -import static org.hamcrest.Matchers.containsString; -import static org.hamcrest.Matchers.equalTo; - -/** - * Test a rest action that sets special response headers - */ -@ClusterScope(scope = Scope.SUITE, supportsDedicatedMasters = false, numDataNodes = 1) -public class ExecutionContextPluginSetIT extends HttpSmokeTestCase { - - @Override - protected boolean addMockHttpTransport() { - return false; // enable http - } - - @Override - protected Collection> nodePlugins() { - ArrayList> plugins = new ArrayList<>(super.nodePlugins()); - plugins.add(TestExecutionContextPlugin.class); - return plugins; - } - - public void testThatPluginCannotOverrideExecutionContext() throws IOException { - ensureGreen(); - try { - Response response = getRestClient().performRequest(new Request("POST", "/_set_execution_context")); - fail("request should have failed"); - } catch(ResponseException e) { - Response response = e.getResponse(); - String responseBody = new String(response.getEntity().getContent().readAllBytes(), StandardCharsets.UTF_8); - assertThat(response.getStatusLine().getStatusCode(), equalTo(400)); - assertThat(responseBody, containsString("ExecutionContext already present")); - } - } -} diff --git a/qa/smoke-test-http/src/test/java/org/opensearch/http/TestExecutionContextPlugin.java b/qa/smoke-test-http/src/test/java/org/opensearch/http/TestExecutionContextPlugin.java index 0f1f8eac9ff7c..a38e01602c7e4 100644 --- a/qa/smoke-test-http/src/test/java/org/opensearch/http/TestExecutionContextPlugin.java +++ b/qa/smoke-test-http/src/test/java/org/opensearch/http/TestExecutionContextPlugin.java @@ -62,6 +62,6 @@ public Collection createComponents( public List getRestHandlers(Settings settings, RestController restController, ClusterSettings clusterSettings, IndexScopedSettings indexScopedSettings, SettingsFilter settingsFilter, IndexNameExpressionResolver indexNameExpressionResolver, Supplier nodesInCluster) { - return List.of(new TestSetExecutionContextRestAction(threadPool), new TestGetExecutionContextRestAction(threadPool)); + return List.of(new TestGetExecutionContextRestAction(threadPool)); } } diff --git a/qa/smoke-test-http/src/test/java/org/opensearch/http/TestGetExecutionContextRestAction.java b/qa/smoke-test-http/src/test/java/org/opensearch/http/TestGetExecutionContextRestAction.java index 3e796bf7a14da..a5e394656812c 100644 --- a/qa/smoke-test-http/src/test/java/org/opensearch/http/TestGetExecutionContextRestAction.java +++ b/qa/smoke-test-http/src/test/java/org/opensearch/http/TestGetExecutionContextRestAction.java @@ -17,6 +17,7 @@ import org.opensearch.threadpool.ThreadPool; import java.util.List; +import java.util.Stack; import static java.util.Collections.singletonList; import static org.opensearch.rest.RestRequest.Method.GET; @@ -42,8 +43,8 @@ public String getName() { @Override public RestChannelConsumer prepareRequest(RestRequest request, NodeClient client) { - String pluginMainClass = threadPool.getThreadContext().getExecutionContext(); - RestResponse response = new BytesRestResponse(RestStatus.OK, pluginMainClass); + Stack pluginExecutionStack = threadPool.getThreadContext().getPluginExecutionStack(); + RestResponse response = new BytesRestResponse(RestStatus.OK, pluginExecutionStack.peek()); return channel -> channel.sendResponse(response); } } diff --git a/qa/smoke-test-http/src/test/java/org/opensearch/http/TestSetExecutionContextRestAction.java b/qa/smoke-test-http/src/test/java/org/opensearch/http/TestSetExecutionContextRestAction.java deleted file mode 100644 index 8c33eb8787720..0000000000000 --- a/qa/smoke-test-http/src/test/java/org/opensearch/http/TestSetExecutionContextRestAction.java +++ /dev/null @@ -1,48 +0,0 @@ -/* - * SPDX-License-Identifier: Apache-2.0 - * - * The OpenSearch Contributors require contributions made to - * this file be licensed under the Apache-2.0 license or a - * compatible open source license. - */ - -package org.opensearch.http; - -import org.opensearch.client.node.NodeClient; -import org.opensearch.core.rest.RestStatus; -import org.opensearch.rest.BaseRestHandler; -import org.opensearch.rest.BytesRestResponse; -import org.opensearch.rest.RestRequest; -import org.opensearch.rest.RestResponse; -import org.opensearch.threadpool.ThreadPool; - -import java.util.List; - -import static java.util.Collections.singletonList; -import static org.opensearch.rest.RestRequest.Method.POST; - -public class TestSetExecutionContextRestAction extends BaseRestHandler { - - private final ThreadPool threadPool; - - public TestSetExecutionContextRestAction(ThreadPool threadPool) { - this.threadPool = threadPool; - } - - @Override - public List routes() { - return singletonList(new Route(POST, "/_set_execution_context")); - } - - @Override - public String getName() { - return "test_set_execution_context_action"; - } - - @Override - public RestChannelConsumer prepareRequest(RestRequest request, NodeClient client) { - threadPool.getThreadContext().setExecutionContext("should-not-allow-plugin-to-set-execution-context"); - RestResponse response = new BytesRestResponse(RestStatus.OK, "Should not happen"); - return channel -> channel.sendResponse(response); - } -} diff --git a/server/src/main/java/org/opensearch/common/util/concurrent/ExecutionContext.java b/server/src/main/java/org/opensearch/common/util/concurrent/ExecutionContext.java index b32c7c39ffd27..f708c0abfffaf 100644 --- a/server/src/main/java/org/opensearch/common/util/concurrent/ExecutionContext.java +++ b/server/src/main/java/org/opensearch/common/util/concurrent/ExecutionContext.java @@ -8,25 +8,41 @@ package org.opensearch.common.util.concurrent; +import org.opensearch.plugins.Plugin; + +import java.util.Stack; + /** - * An ExecutionContext is a singular header within ThreadLocal that contains the identity of a plugin that is on - * the path of execution. + * An ExecutionContext is a singular header within ThreadLocal that contains the chain of plugins on the execution path */ public class ExecutionContext { - private final ThreadLocal context = new ThreadLocal<>(); + private final ThreadLocal> context = new ThreadLocal<>(); - public void set(String value) { - if (context.get() != null) { - throw new IllegalArgumentException("ExecutionContext already present"); + public void add(Plugin plugin) { + if (context.get() == null) { + context.set(new Stack<>()); } - context.set(value); + context.get().add(plugin.getClass().getCanonicalName()); } - public String get() { + public Stack get() { + if (context.get() == null) { + return null; + } return context.get(); } - public void clear() { - context.remove(); + public String peek() { + if (context.get() == null || context.get().isEmpty()) { + return null; + } + return context.get().peek(); + } + + public String pop() { + if (context.get() == null || context.get().isEmpty()) { + return null; + } + return context.get().pop(); } } diff --git a/server/src/main/java/org/opensearch/common/util/concurrent/ThreadContext.java b/server/src/main/java/org/opensearch/common/util/concurrent/ThreadContext.java index 6127cfa92061e..6a61a41556470 100644 --- a/server/src/main/java/org/opensearch/common/util/concurrent/ThreadContext.java +++ b/server/src/main/java/org/opensearch/common/util/concurrent/ThreadContext.java @@ -45,6 +45,7 @@ import org.opensearch.core.common.io.stream.StreamOutput; import org.opensearch.core.common.io.stream.Writeable; import org.opensearch.http.HttpTransportSettings; +import org.opensearch.plugins.Plugin; import org.opensearch.tasks.Task; import org.opensearch.tasks.TaskThreadContextStatePropagator; @@ -60,6 +61,7 @@ import java.util.Map; import java.util.Objects; import java.util.Set; +import java.util.Stack; import java.util.concurrent.CopyOnWriteArrayList; import java.util.function.BiConsumer; import java.util.function.BinaryOperator; @@ -110,6 +112,7 @@ public final class ThreadContext implements Writeable { * Name for the {@link #stashWithOrigin origin} attribute. */ public static final String ACTION_ORIGIN_TRANSIENT_NAME = "action.origin"; + private static final String PLUGIN_EXECUTION_CONTEXT_HEADER = "_plugin_execution_context"; private static final Logger logger = LogManager.getLogger(ThreadContext.class); private static final ThreadContextStruct DEFAULT_CONTEXT = new ThreadContextStruct(); @@ -141,16 +144,16 @@ public void unregisterThreadContextStatePropagator(final ThreadContextStatePropa propagators.remove(Objects.requireNonNull(propagator)); } - public void setExecutionContext(String pluginName) { - this.executionContext.set(pluginName); + void delegateExecutionToPlugin(Plugin plugin) { + this.executionContext.add(plugin); } - public String getExecutionContext() { + public Stack getPluginExecutionStack() { return this.executionContext.get(); } - public void clearExecutionContext() { - this.executionContext.clear(); + void returnToCore() { + this.executionContext.pop(); } /** @@ -190,6 +193,25 @@ public StoredContext stashContext() { }; } + /** + * Keeps the current context and also adds an entry into the plugin execution stack with the + * main class name of the plugin being delegated to + */ + public StoredContext switchContext(Plugin plugin) { + final ThreadContextStruct context = threadLocal.get(); + + delegateExecutionToPlugin(plugin); + threadLocal.set(context); + + return () -> { + // If the node and thus the threadLocal get closed while this task + // is still executing, we don't want this runnable to fail with an + // uncaught exception + returnToCore(); + threadLocal.set(context); + }; + } + /** * Captures the current thread context as writeable, allowing it to be serialized out later */ diff --git a/server/src/main/java/org/opensearch/rest/RestHandlerProxy.java b/server/src/main/java/org/opensearch/rest/RestHandlerProxy.java index cda1cdfc8c4d3..74859ff51a978 100644 --- a/server/src/main/java/org/opensearch/rest/RestHandlerProxy.java +++ b/server/src/main/java/org/opensearch/rest/RestHandlerProxy.java @@ -8,7 +8,9 @@ package org.opensearch.rest; +import org.opensearch.common.util.concurrent.ThreadContext; import org.opensearch.plugins.ActionPlugin; +import org.opensearch.plugins.Plugin; import org.opensearch.threadpool.ThreadPool; import java.lang.reflect.InvocationHandler; @@ -42,15 +44,12 @@ private RestHandlerProxy(RestHandler restHandler, ThreadPool threadPool, ActionP @Override public Object invoke(Object proxy, Method m, Object[] args) throws Throwable { Object result; - try { - threadPool.getThreadContext().setExecutionContext(plugin.getClass().getName()); + try (ThreadContext.StoredContext threadContext = threadPool.getThreadContext().switchContext((Plugin) plugin)) { result = m.invoke(restHandler, args); } catch (InvocationTargetException e) { throw e.getTargetException(); } catch (Exception e) { throw new RuntimeException("unexpected invocation exception: " + e.getMessage()); - } finally { - threadPool.getThreadContext().clearExecutionContext(); } return result; } From 6b6e9552cfbb7b7422db616d97f5dfe544a46c82 Mon Sep 17 00:00:00 2001 From: Craig Perkins Date: Fri, 12 Jul 2024 10:12:40 -0400 Subject: [PATCH 08/65] WIP on plugin aware stash context Signed-off-by: Craig Perkins --- .../http/TestExecutionContextPlugin.java | 2 +- .../TestGetExecutionContextRestAction.java | 4 + .../client/node/PluginAwareNodeClient.java | 75 +++++++++++++++++++ .../PluginAwareThreadContextWrapper.java | 26 +++++++ .../common/util/concurrent/ThreadContext.java | 43 ++++++++++- .../concurrent/ThreadContextProxy.java | 52 +++++++++++++ .../main/java/org/opensearch/node/Node.java | 7 +- .../PluginAwareThreadPoolWrapper.java | 27 +++++++ .../threadpool/ThreadPoolProxy.java | 45 +++++++++++ 9 files changed, 278 insertions(+), 3 deletions(-) create mode 100644 server/src/main/java/org/opensearch/client/node/PluginAwareNodeClient.java create mode 100644 server/src/main/java/org/opensearch/common/util/concurrent/PluginAwareThreadContextWrapper.java create mode 100644 server/src/main/java/org/opensearch/concurrent/ThreadContextProxy.java create mode 100644 server/src/main/java/org/opensearch/threadpool/PluginAwareThreadPoolWrapper.java create mode 100644 server/src/main/java/org/opensearch/threadpool/ThreadPoolProxy.java diff --git a/qa/smoke-test-http/src/test/java/org/opensearch/http/TestExecutionContextPlugin.java b/qa/smoke-test-http/src/test/java/org/opensearch/http/TestExecutionContextPlugin.java index a38e01602c7e4..686b4fe23452e 100644 --- a/qa/smoke-test-http/src/test/java/org/opensearch/http/TestExecutionContextPlugin.java +++ b/qa/smoke-test-http/src/test/java/org/opensearch/http/TestExecutionContextPlugin.java @@ -54,7 +54,7 @@ public Collection createComponents( IndexNameExpressionResolver expressionResolver, Supplier repositoriesServiceSupplier ) { - this.threadPool = threadPool; + this.threadPool = client.threadPool(); return Collections.emptyList(); } diff --git a/qa/smoke-test-http/src/test/java/org/opensearch/http/TestGetExecutionContextRestAction.java b/qa/smoke-test-http/src/test/java/org/opensearch/http/TestGetExecutionContextRestAction.java index a5e394656812c..6bcdde306bb33 100644 --- a/qa/smoke-test-http/src/test/java/org/opensearch/http/TestGetExecutionContextRestAction.java +++ b/qa/smoke-test-http/src/test/java/org/opensearch/http/TestGetExecutionContextRestAction.java @@ -9,6 +9,7 @@ package org.opensearch.http; import org.opensearch.client.node.NodeClient; +import org.opensearch.common.util.concurrent.ThreadContext; import org.opensearch.core.rest.RestStatus; import org.opensearch.rest.BaseRestHandler; import org.opensearch.rest.BytesRestResponse; @@ -43,6 +44,9 @@ public String getName() { @Override public RestChannelConsumer prepareRequest(RestRequest request, NodeClient client) { + try (ThreadContext.StoredContext storedContext = threadPool.getThreadContext().stashContext()) { + System.out.println("Stashed the context"); + } Stack pluginExecutionStack = threadPool.getThreadContext().getPluginExecutionStack(); RestResponse response = new BytesRestResponse(RestStatus.OK, pluginExecutionStack.peek()); return channel -> channel.sendResponse(response); diff --git a/server/src/main/java/org/opensearch/client/node/PluginAwareNodeClient.java b/server/src/main/java/org/opensearch/client/node/PluginAwareNodeClient.java new file mode 100644 index 0000000000000..91df2df5100b0 --- /dev/null +++ b/server/src/main/java/org/opensearch/client/node/PluginAwareNodeClient.java @@ -0,0 +1,75 @@ +/* + * SPDX-License-Identifier: Apache-2.0 + * + * The OpenSearch Contributors require contributions made to + * this file be licensed under the Apache-2.0 license or a + * compatible open source license. + */ + +/* + * Licensed to Elasticsearch under one or more contributor + * license agreements. See the NOTICE file distributed with + * this work for additional information regarding copyright + * ownership. Elasticsearch licenses this file to you under + * the Apache License, Version 2.0 (the "License"); you may + * not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, + * software distributed under the License is distributed on an + * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY + * KIND, either express or implied. See the License for the + * specific language governing permissions and limitations + * under the License. + */ + +/* + * Modifications Copyright OpenSearch Contributors. See + * GitHub history for details. + */ + +package org.opensearch.client.node; + +import org.opensearch.action.ActionModule.DynamicActionRegistry; +import org.opensearch.action.ActionRequest; +import org.opensearch.action.ActionType; +import org.opensearch.action.support.TransportAction; +import org.opensearch.client.Client; +import org.opensearch.client.support.AbstractClient; +import org.opensearch.cluster.node.DiscoveryNode; +import org.opensearch.common.annotation.PublicApi; +import org.opensearch.common.settings.Settings; +import org.opensearch.common.util.concurrent.PluginAwareThreadContextWrapper; +import org.opensearch.common.util.concurrent.ThreadContext; +import org.opensearch.core.action.ActionListener; +import org.opensearch.core.action.ActionResponse; +import org.opensearch.core.common.io.stream.NamedWriteableRegistry; +import org.opensearch.plugins.Plugin; +import org.opensearch.tasks.Task; +import org.opensearch.tasks.TaskListener; +import org.opensearch.threadpool.ThreadPool; +import org.opensearch.transport.RemoteClusterService; + +import java.util.function.Supplier; + +/** + * Client that executes actions on the local node. This NodeClient is passed to a plugin in createComponents. + * + * @opensearch.api + */ +@PublicApi(since = "2.16.0") +public class PluginAwareNodeClient extends NodeClient { + + private PluginAwareThreadContextWrapper wrapper; + + public PluginAwareNodeClient(Settings settings, ThreadPool threadPool, Plugin plugin) { + super(settings, threadPool); + this.wrapper = new PluginAwareThreadContextWrapper(threadPool.getThreadContext(), plugin); + } + + public ThreadContext.StoredContext stashContext() { + return wrapper.stashContext(); + } +} diff --git a/server/src/main/java/org/opensearch/common/util/concurrent/PluginAwareThreadContextWrapper.java b/server/src/main/java/org/opensearch/common/util/concurrent/PluginAwareThreadContextWrapper.java new file mode 100644 index 0000000000000..c87c2ecae430c --- /dev/null +++ b/server/src/main/java/org/opensearch/common/util/concurrent/PluginAwareThreadContextWrapper.java @@ -0,0 +1,26 @@ +/* + * SPDX-License-Identifier: Apache-2.0 + * + * The OpenSearch Contributors require contributions made to + * this file be licensed under the Apache-2.0 license or a + * compatible open source license. + */ + +package org.opensearch.common.util.concurrent; + +import org.opensearch.plugins.Plugin; + +public class PluginAwareThreadContextWrapper { + + private ThreadContext threadContext; + private Plugin plugin; + + public PluginAwareThreadContextWrapper(ThreadContext threadContext, Plugin plugin) { + this.threadContext = threadContext; + this.plugin = plugin; + } + + public ThreadContext.StoredContext stashContext() { + return threadContext.stashContext(plugin.getClass()); + } +} diff --git a/server/src/main/java/org/opensearch/common/util/concurrent/ThreadContext.java b/server/src/main/java/org/opensearch/common/util/concurrent/ThreadContext.java index 6a61a41556470..fb95a1678898b 100644 --- a/server/src/main/java/org/opensearch/common/util/concurrent/ThreadContext.java +++ b/server/src/main/java/org/opensearch/common/util/concurrent/ThreadContext.java @@ -112,7 +112,8 @@ public final class ThreadContext implements Writeable { * Name for the {@link #stashWithOrigin origin} attribute. */ public static final String ACTION_ORIGIN_TRANSIENT_NAME = "action.origin"; - private static final String PLUGIN_EXECUTION_CONTEXT_HEADER = "_plugin_execution_context"; + + private static final String PLUGIN_EXECUTION_CONTEXT = "_plugin_execution_context"; private static final Logger logger = LogManager.getLogger(ThreadContext.class); private static final ThreadContextStruct DEFAULT_CONTEXT = new ThreadContextStruct(); @@ -193,6 +194,46 @@ public StoredContext stashContext() { }; } + /** + * Removes the current context and resets a default context. The removed context can be + * restored by closing the returned {@link StoredContext}. + */ + StoredContext stashContext(Class pluginClass) { + System.out.println("Called stashContext with plugin: " + pluginClass); + final ThreadContextStruct context = threadLocal.get(); + /* + X-Opaque-ID should be preserved in a threadContext in order to propagate this across threads. + This is needed so the DeprecationLogger in another thread can see the value of X-Opaque-ID provided by a user. + Otherwise when context is stash, it should be empty. + */ + + ThreadContextStruct threadContextStruct = DEFAULT_CONTEXT.putPersistent(context.persistentHeaders); + + if (context.requestHeaders.containsKey(Task.X_OPAQUE_ID)) { + threadContextStruct = threadContextStruct.putHeaders( + MapBuilder.newMapBuilder() + .put(Task.X_OPAQUE_ID, context.requestHeaders.get(Task.X_OPAQUE_ID)) + .immutableMap() + ); + } + + final Map transientHeaders = propagateTransients(context.transientHeaders, context.isSystemContext); + if (!transientHeaders.isEmpty()) { + threadContextStruct = threadContextStruct.putTransient(transientHeaders); + } + + threadContextStruct.putRequest(PLUGIN_EXECUTION_CONTEXT, pluginClass.getCanonicalName()); + + threadLocal.set(threadContextStruct); + + return () -> { + // If the node and thus the threadLocal get closed while this task + // is still executing, we don't want this runnable to fail with an + // uncaught exception + threadLocal.set(context); + }; + } + /** * Keeps the current context and also adds an entry into the plugin execution stack with the * main class name of the plugin being delegated to diff --git a/server/src/main/java/org/opensearch/concurrent/ThreadContextProxy.java b/server/src/main/java/org/opensearch/concurrent/ThreadContextProxy.java new file mode 100644 index 0000000000000..b1cc041704220 --- /dev/null +++ b/server/src/main/java/org/opensearch/concurrent/ThreadContextProxy.java @@ -0,0 +1,52 @@ +/* + * SPDX-License-Identifier: Apache-2.0 + * + * The OpenSearch Contributors require contributions made to + * this file be licensed under the Apache-2.0 license or a + * compatible open source license. + */ + +package org.opensearch.concurrent; + +import org.opensearch.common.util.concurrent.ThreadContext; +import org.opensearch.plugins.Plugin; + +import java.lang.reflect.InvocationHandler; +import java.lang.reflect.Method; +import java.lang.reflect.Proxy; +import java.util.HashMap; +import java.util.Map; + +public class ThreadContextProxy implements InvocationHandler { + private final ThreadContext threadContext; + private final Plugin plugin; + private static final Map INSTANCES = new HashMap<>(); + + public static ThreadContext getInstance(ThreadContext threadContext, Plugin plugin) { + if (!INSTANCES.containsKey(plugin.getClass().getCanonicalName())) { + ThreadContext threadContextProxy = (ThreadContext) Proxy.newProxyInstance( + threadContext.getClass().getClassLoader(), + new Class[] { ThreadContext.class }, + new ThreadContextProxy(threadContext, plugin) + ); + INSTANCES.put(plugin.getClass().getCanonicalName(), threadContextProxy); + } + return INSTANCES.get(plugin.getClass().getCanonicalName()); + } + + private ThreadContextProxy(ThreadContext threadContext, Plugin plugin) { + this.threadContext = threadContext; + this.plugin = plugin; + } + + @Override + public Object invoke(Object proxy, Method m, Object[] args) throws Throwable { + Object result; + if ("stashContext".equals(m.getName())) { + result = m.invoke(threadContext, plugin.getClass(), args); + } else { + result = m.invoke(threadContext, args); + } + return result; + } +} diff --git a/server/src/main/java/org/opensearch/node/Node.java b/server/src/main/java/org/opensearch/node/Node.java index 96a716af7f1a1..16bd03e4e8ba2 100644 --- a/server/src/main/java/org/opensearch/node/Node.java +++ b/server/src/main/java/org/opensearch/node/Node.java @@ -252,8 +252,10 @@ import org.opensearch.telemetry.tracing.Tracer; import org.opensearch.telemetry.tracing.TracerFactory; import org.opensearch.threadpool.ExecutorBuilder; +import org.opensearch.threadpool.PluginAwareThreadPoolWrapper; import org.opensearch.threadpool.RunnableTaskExecutionListener; import org.opensearch.threadpool.ThreadPool; +import org.opensearch.threadpool.ThreadPoolProxy; import org.opensearch.transport.RemoteClusterService; import org.opensearch.transport.Transport; import org.opensearch.transport.TransportInterceptor; @@ -699,7 +701,10 @@ protected Node( pluginsService.filterPlugins(SystemIndexPlugin.class) .stream() .collect( - Collectors.toMap(plugin -> plugin.getClass().getSimpleName(), plugin -> plugin.getSystemIndexDescriptors(settings)) + Collectors.toMap( + plugin -> plugin.getClass().getCanonicalName(), + plugin -> plugin.getSystemIndexDescriptors(settings) + ) ) ); final SystemIndices systemIndices = new SystemIndices(systemIndexDescriptorMap); diff --git a/server/src/main/java/org/opensearch/threadpool/PluginAwareThreadPoolWrapper.java b/server/src/main/java/org/opensearch/threadpool/PluginAwareThreadPoolWrapper.java new file mode 100644 index 0000000000000..08b8494b8c9ee --- /dev/null +++ b/server/src/main/java/org/opensearch/threadpool/PluginAwareThreadPoolWrapper.java @@ -0,0 +1,27 @@ +/* + * SPDX-License-Identifier: Apache-2.0 + * + * The OpenSearch Contributors require contributions made to + * this file be licensed under the Apache-2.0 license or a + * compatible open source license. + */ + +package org.opensearch.threadpool; + +import org.opensearch.common.util.concurrent.PluginAwareThreadContextWrapper; +import org.opensearch.plugins.Plugin; + +public class PluginAwareThreadPoolWrapper { + + private ThreadPool threadPool; + private Plugin plugin; + + public PluginAwareThreadPoolWrapper(ThreadPool threadPool, Plugin plugin) { + this.threadPool = threadPool; + this.plugin = plugin; + } + + public PluginAwareThreadContextWrapper getPluginAwareThreadContext() { + return new PluginAwareThreadContextWrapper(threadPool.getThreadContext(), plugin); + } +} diff --git a/server/src/main/java/org/opensearch/threadpool/ThreadPoolProxy.java b/server/src/main/java/org/opensearch/threadpool/ThreadPoolProxy.java new file mode 100644 index 0000000000000..3319f32b23528 --- /dev/null +++ b/server/src/main/java/org/opensearch/threadpool/ThreadPoolProxy.java @@ -0,0 +1,45 @@ +/* + * SPDX-License-Identifier: Apache-2.0 + * + * The OpenSearch Contributors require contributions made to + * this file be licensed under the Apache-2.0 license or a + * compatible open source license. + */ + +package org.opensearch.threadpool; + +import org.opensearch.concurrent.ThreadContextProxy; +import org.opensearch.plugins.Plugin; + +import java.lang.reflect.InvocationHandler; +import java.lang.reflect.Method; +import java.lang.reflect.Proxy; + +public class ThreadPoolProxy implements InvocationHandler { + private final ThreadPool threadPool; + private final Plugin plugin; + + public static ThreadPool newInstance(ThreadPool threadPool, Plugin plugin) { + return (ThreadPool) Proxy.newProxyInstance( + threadPool.getClass().getClassLoader(), + new Class[] { ThreadPool.class }, + new ThreadPoolProxy(threadPool, plugin) + ); + } + + private ThreadPoolProxy(ThreadPool threadPool, Plugin plugin) { + this.threadPool = threadPool; + this.plugin = plugin; + } + + @Override + public Object invoke(Object proxy, Method m, Object[] args) throws Throwable { + Object result; + if ("getThreadContext".equals(m.getName())) { + result = ThreadContextProxy.getInstance(threadPool.getThreadContext(), plugin); + } else { + result = m.invoke(threadPool, args); + } + return result; + } +} From 73835edac35ffad741746d3420b6347291c7c10d Mon Sep 17 00:00:00 2001 From: Craig Perkins Date: Fri, 12 Jul 2024 11:05:51 -0400 Subject: [PATCH 09/65] Create class called PluginAwareNodeClient that provides a method called switchContext Signed-off-by: Craig Perkins --- .../http/TestExecutionContextPlugin.java | 7 ++- .../TestGetExecutionContextRestAction.java | 15 ++--- .../org/opensearch/action/ActionModule.java | 4 +- .../client/node/PluginAwareNodeClient.java | 17 +----- .../PluginAwareThreadContextWrapper.java | 4 +- .../common/util/concurrent/ThreadContext.java | 41 +------------- .../concurrent/ThreadContextProxy.java | 52 ----------------- .../main/java/org/opensearch/node/Node.java | 7 +-- .../org/opensearch/rest/RestHandlerProxy.java | 56 ------------------- .../PluginAwareThreadPoolWrapper.java | 27 --------- .../threadpool/ThreadPoolProxy.java | 45 --------------- 11 files changed, 21 insertions(+), 254 deletions(-) delete mode 100644 server/src/main/java/org/opensearch/concurrent/ThreadContextProxy.java delete mode 100644 server/src/main/java/org/opensearch/rest/RestHandlerProxy.java delete mode 100644 server/src/main/java/org/opensearch/threadpool/PluginAwareThreadPoolWrapper.java delete mode 100644 server/src/main/java/org/opensearch/threadpool/ThreadPoolProxy.java diff --git a/qa/smoke-test-http/src/test/java/org/opensearch/http/TestExecutionContextPlugin.java b/qa/smoke-test-http/src/test/java/org/opensearch/http/TestExecutionContextPlugin.java index 686b4fe23452e..a004d31cf4920 100644 --- a/qa/smoke-test-http/src/test/java/org/opensearch/http/TestExecutionContextPlugin.java +++ b/qa/smoke-test-http/src/test/java/org/opensearch/http/TestExecutionContextPlugin.java @@ -9,6 +9,7 @@ package org.opensearch.http; import org.opensearch.client.Client; +import org.opensearch.client.node.PluginAwareNodeClient; import org.opensearch.cluster.metadata.IndexNameExpressionResolver; import org.opensearch.cluster.node.DiscoveryNodes; import org.opensearch.cluster.service.ClusterService; @@ -38,7 +39,7 @@ public class TestExecutionContextPlugin extends Plugin implements ActionPlugin { - private ThreadPool threadPool; + private Client client; @Override public Collection createComponents( @@ -54,7 +55,7 @@ public Collection createComponents( IndexNameExpressionResolver expressionResolver, Supplier repositoriesServiceSupplier ) { - this.threadPool = client.threadPool(); + this.client = client; return Collections.emptyList(); } @@ -62,6 +63,6 @@ public Collection createComponents( public List getRestHandlers(Settings settings, RestController restController, ClusterSettings clusterSettings, IndexScopedSettings indexScopedSettings, SettingsFilter settingsFilter, IndexNameExpressionResolver indexNameExpressionResolver, Supplier nodesInCluster) { - return List.of(new TestGetExecutionContextRestAction(threadPool)); + return List.of(new TestGetExecutionContextRestAction((PluginAwareNodeClient) client)); } } diff --git a/qa/smoke-test-http/src/test/java/org/opensearch/http/TestGetExecutionContextRestAction.java b/qa/smoke-test-http/src/test/java/org/opensearch/http/TestGetExecutionContextRestAction.java index 6bcdde306bb33..203e440e0c87b 100644 --- a/qa/smoke-test-http/src/test/java/org/opensearch/http/TestGetExecutionContextRestAction.java +++ b/qa/smoke-test-http/src/test/java/org/opensearch/http/TestGetExecutionContextRestAction.java @@ -9,6 +9,7 @@ package org.opensearch.http; import org.opensearch.client.node.NodeClient; +import org.opensearch.client.node.PluginAwareNodeClient; import org.opensearch.common.util.concurrent.ThreadContext; import org.opensearch.core.rest.RestStatus; import org.opensearch.rest.BaseRestHandler; @@ -26,10 +27,10 @@ public class TestGetExecutionContextRestAction extends BaseRestHandler { - private final ThreadPool threadPool; + private final PluginAwareNodeClient pluginAwareClient; - public TestGetExecutionContextRestAction(ThreadPool threadPool) { - this.threadPool = threadPool; + public TestGetExecutionContextRestAction(PluginAwareNodeClient pluginAwareClient) { + this.pluginAwareClient = pluginAwareClient; } @Override @@ -44,11 +45,11 @@ public String getName() { @Override public RestChannelConsumer prepareRequest(RestRequest request, NodeClient client) { - try (ThreadContext.StoredContext storedContext = threadPool.getThreadContext().stashContext()) { - System.out.println("Stashed the context"); + String stashedContext; + try (ThreadContext.StoredContext storedContext = pluginAwareClient.switchContext()) { + stashedContext = pluginAwareClient.threadPool().getThreadContext().getHeader(ThreadContext.PLUGIN_EXECUTION_CONTEXT); } - Stack pluginExecutionStack = threadPool.getThreadContext().getPluginExecutionStack(); - RestResponse response = new BytesRestResponse(RestStatus.OK, pluginExecutionStack.peek()); + RestResponse response = new BytesRestResponse(RestStatus.OK, stashedContext); return channel -> channel.sendResponse(response); } } diff --git a/server/src/main/java/org/opensearch/action/ActionModule.java b/server/src/main/java/org/opensearch/action/ActionModule.java index c2aff25837b35..16c15f553951c 100644 --- a/server/src/main/java/org/opensearch/action/ActionModule.java +++ b/server/src/main/java/org/opensearch/action/ActionModule.java @@ -322,7 +322,6 @@ import org.opensearch.rest.NamedRoute; import org.opensearch.rest.RestController; import org.opensearch.rest.RestHandler; -import org.opensearch.rest.RestHandlerProxy; import org.opensearch.rest.RestHeaderDefinition; import org.opensearch.rest.action.RestFieldCapabilitiesAction; import org.opensearch.rest.action.RestMainAction; @@ -996,8 +995,7 @@ public void initRestHandlers(Supplier nodesInCluster) { indexNameExpressionResolver, nodesInCluster )) { - RestHandler handlerProxy = RestHandlerProxy.newInstance(handler, threadPool, plugin); - registerHandler.accept(handlerProxy); + registerHandler.accept(handler); } } registerHandler.accept(new RestCatAction(catActions)); diff --git a/server/src/main/java/org/opensearch/client/node/PluginAwareNodeClient.java b/server/src/main/java/org/opensearch/client/node/PluginAwareNodeClient.java index 91df2df5100b0..deb1021e5ea81 100644 --- a/server/src/main/java/org/opensearch/client/node/PluginAwareNodeClient.java +++ b/server/src/main/java/org/opensearch/client/node/PluginAwareNodeClient.java @@ -32,27 +32,12 @@ package org.opensearch.client.node; -import org.opensearch.action.ActionModule.DynamicActionRegistry; -import org.opensearch.action.ActionRequest; -import org.opensearch.action.ActionType; -import org.opensearch.action.support.TransportAction; -import org.opensearch.client.Client; -import org.opensearch.client.support.AbstractClient; -import org.opensearch.cluster.node.DiscoveryNode; import org.opensearch.common.annotation.PublicApi; import org.opensearch.common.settings.Settings; import org.opensearch.common.util.concurrent.PluginAwareThreadContextWrapper; import org.opensearch.common.util.concurrent.ThreadContext; -import org.opensearch.core.action.ActionListener; -import org.opensearch.core.action.ActionResponse; -import org.opensearch.core.common.io.stream.NamedWriteableRegistry; import org.opensearch.plugins.Plugin; -import org.opensearch.tasks.Task; -import org.opensearch.tasks.TaskListener; import org.opensearch.threadpool.ThreadPool; -import org.opensearch.transport.RemoteClusterService; - -import java.util.function.Supplier; /** * Client that executes actions on the local node. This NodeClient is passed to a plugin in createComponents. @@ -69,7 +54,7 @@ public PluginAwareNodeClient(Settings settings, ThreadPool threadPool, Plugin pl this.wrapper = new PluginAwareThreadContextWrapper(threadPool.getThreadContext(), plugin); } - public ThreadContext.StoredContext stashContext() { + public ThreadContext.StoredContext switchContext() { return wrapper.stashContext(); } } diff --git a/server/src/main/java/org/opensearch/common/util/concurrent/PluginAwareThreadContextWrapper.java b/server/src/main/java/org/opensearch/common/util/concurrent/PluginAwareThreadContextWrapper.java index c87c2ecae430c..46ea3a3038915 100644 --- a/server/src/main/java/org/opensearch/common/util/concurrent/PluginAwareThreadContextWrapper.java +++ b/server/src/main/java/org/opensearch/common/util/concurrent/PluginAwareThreadContextWrapper.java @@ -12,8 +12,8 @@ public class PluginAwareThreadContextWrapper { - private ThreadContext threadContext; - private Plugin plugin; + private final ThreadContext threadContext; + private final Plugin plugin; public PluginAwareThreadContextWrapper(ThreadContext threadContext, Plugin plugin) { this.threadContext = threadContext; diff --git a/server/src/main/java/org/opensearch/common/util/concurrent/ThreadContext.java b/server/src/main/java/org/opensearch/common/util/concurrent/ThreadContext.java index fb95a1678898b..7f924e7ae4dcf 100644 --- a/server/src/main/java/org/opensearch/common/util/concurrent/ThreadContext.java +++ b/server/src/main/java/org/opensearch/common/util/concurrent/ThreadContext.java @@ -45,7 +45,6 @@ import org.opensearch.core.common.io.stream.StreamOutput; import org.opensearch.core.common.io.stream.Writeable; import org.opensearch.http.HttpTransportSettings; -import org.opensearch.plugins.Plugin; import org.opensearch.tasks.Task; import org.opensearch.tasks.TaskThreadContextStatePropagator; @@ -61,7 +60,6 @@ import java.util.Map; import java.util.Objects; import java.util.Set; -import java.util.Stack; import java.util.concurrent.CopyOnWriteArrayList; import java.util.function.BiConsumer; import java.util.function.BinaryOperator; @@ -113,13 +111,12 @@ public final class ThreadContext implements Writeable { */ public static final String ACTION_ORIGIN_TRANSIENT_NAME = "action.origin"; - private static final String PLUGIN_EXECUTION_CONTEXT = "_plugin_execution_context"; + public static final String PLUGIN_EXECUTION_CONTEXT = "_plugin_execution_context"; private static final Logger logger = LogManager.getLogger(ThreadContext.class); private static final ThreadContextStruct DEFAULT_CONTEXT = new ThreadContextStruct(); private final Map defaultHeader; private final ThreadLocal threadLocal; - private final ExecutionContext executionContext; private final int maxWarningHeaderCount; private final long maxWarningHeaderSize; private final List propagators; @@ -131,7 +128,6 @@ public final class ThreadContext implements Writeable { public ThreadContext(Settings settings) { this.defaultHeader = buildDefaultHeaders(settings); this.threadLocal = ThreadLocal.withInitial(() -> DEFAULT_CONTEXT); - this.executionContext = new ExecutionContext(); this.maxWarningHeaderCount = SETTING_HTTP_MAX_WARNING_HEADER_COUNT.get(settings); this.maxWarningHeaderSize = SETTING_HTTP_MAX_WARNING_HEADER_SIZE.get(settings).getBytes(); this.propagators = new CopyOnWriteArrayList<>(List.of(new TaskThreadContextStatePropagator())); @@ -145,18 +141,6 @@ public void unregisterThreadContextStatePropagator(final ThreadContextStatePropa propagators.remove(Objects.requireNonNull(propagator)); } - void delegateExecutionToPlugin(Plugin plugin) { - this.executionContext.add(plugin); - } - - public Stack getPluginExecutionStack() { - return this.executionContext.get(); - } - - void returnToCore() { - this.executionContext.pop(); - } - /** * Removes the current context and resets a default context. The removed context can be * restored by closing the returned {@link StoredContext}. @@ -199,7 +183,6 @@ public StoredContext stashContext() { * restored by closing the returned {@link StoredContext}. */ StoredContext stashContext(Class pluginClass) { - System.out.println("Called stashContext with plugin: " + pluginClass); final ThreadContextStruct context = threadLocal.get(); /* X-Opaque-ID should be preserved in a threadContext in order to propagate this across threads. @@ -222,8 +205,7 @@ StoredContext stashContext(Class pluginClass) { threadContextStruct = threadContextStruct.putTransient(transientHeaders); } - threadContextStruct.putRequest(PLUGIN_EXECUTION_CONTEXT, pluginClass.getCanonicalName()); - + threadContextStruct = threadContextStruct.putRequest(PLUGIN_EXECUTION_CONTEXT, pluginClass.getCanonicalName()); threadLocal.set(threadContextStruct); return () -> { @@ -234,25 +216,6 @@ StoredContext stashContext(Class pluginClass) { }; } - /** - * Keeps the current context and also adds an entry into the plugin execution stack with the - * main class name of the plugin being delegated to - */ - public StoredContext switchContext(Plugin plugin) { - final ThreadContextStruct context = threadLocal.get(); - - delegateExecutionToPlugin(plugin); - threadLocal.set(context); - - return () -> { - // If the node and thus the threadLocal get closed while this task - // is still executing, we don't want this runnable to fail with an - // uncaught exception - returnToCore(); - threadLocal.set(context); - }; - } - /** * Captures the current thread context as writeable, allowing it to be serialized out later */ diff --git a/server/src/main/java/org/opensearch/concurrent/ThreadContextProxy.java b/server/src/main/java/org/opensearch/concurrent/ThreadContextProxy.java deleted file mode 100644 index b1cc041704220..0000000000000 --- a/server/src/main/java/org/opensearch/concurrent/ThreadContextProxy.java +++ /dev/null @@ -1,52 +0,0 @@ -/* - * SPDX-License-Identifier: Apache-2.0 - * - * The OpenSearch Contributors require contributions made to - * this file be licensed under the Apache-2.0 license or a - * compatible open source license. - */ - -package org.opensearch.concurrent; - -import org.opensearch.common.util.concurrent.ThreadContext; -import org.opensearch.plugins.Plugin; - -import java.lang.reflect.InvocationHandler; -import java.lang.reflect.Method; -import java.lang.reflect.Proxy; -import java.util.HashMap; -import java.util.Map; - -public class ThreadContextProxy implements InvocationHandler { - private final ThreadContext threadContext; - private final Plugin plugin; - private static final Map INSTANCES = new HashMap<>(); - - public static ThreadContext getInstance(ThreadContext threadContext, Plugin plugin) { - if (!INSTANCES.containsKey(plugin.getClass().getCanonicalName())) { - ThreadContext threadContextProxy = (ThreadContext) Proxy.newProxyInstance( - threadContext.getClass().getClassLoader(), - new Class[] { ThreadContext.class }, - new ThreadContextProxy(threadContext, plugin) - ); - INSTANCES.put(plugin.getClass().getCanonicalName(), threadContextProxy); - } - return INSTANCES.get(plugin.getClass().getCanonicalName()); - } - - private ThreadContextProxy(ThreadContext threadContext, Plugin plugin) { - this.threadContext = threadContext; - this.plugin = plugin; - } - - @Override - public Object invoke(Object proxy, Method m, Object[] args) throws Throwable { - Object result; - if ("stashContext".equals(m.getName())) { - result = m.invoke(threadContext, plugin.getClass(), args); - } else { - result = m.invoke(threadContext, args); - } - return result; - } -} diff --git a/server/src/main/java/org/opensearch/node/Node.java b/server/src/main/java/org/opensearch/node/Node.java index 16bd03e4e8ba2..37267f1d726fb 100644 --- a/server/src/main/java/org/opensearch/node/Node.java +++ b/server/src/main/java/org/opensearch/node/Node.java @@ -59,6 +59,7 @@ import org.opensearch.bootstrap.BootstrapContext; import org.opensearch.client.Client; import org.opensearch.client.node.NodeClient; +import org.opensearch.client.node.PluginAwareNodeClient; import org.opensearch.cluster.ClusterInfoService; import org.opensearch.cluster.ClusterManagerMetrics; import org.opensearch.cluster.ClusterModule; @@ -252,10 +253,8 @@ import org.opensearch.telemetry.tracing.Tracer; import org.opensearch.telemetry.tracing.TracerFactory; import org.opensearch.threadpool.ExecutorBuilder; -import org.opensearch.threadpool.PluginAwareThreadPoolWrapper; import org.opensearch.threadpool.RunnableTaskExecutionListener; import org.opensearch.threadpool.ThreadPool; -import org.opensearch.threadpool.ThreadPoolProxy; import org.opensearch.transport.RemoteClusterService; import org.opensearch.transport.Transport; import org.opensearch.transport.TransportInterceptor; @@ -936,7 +935,7 @@ protected Node( .stream() .flatMap( p -> p.createComponents( - client, + new PluginAwareNodeClient(settings, threadPool, p), clusterService, threadPool, resourceWatcherService, @@ -955,7 +954,7 @@ protected Node( .stream() .flatMap( p -> p.createComponents( - client, + new PluginAwareNodeClient(settings, threadPool, (Plugin) p), clusterService, threadPool, resourceWatcherService, diff --git a/server/src/main/java/org/opensearch/rest/RestHandlerProxy.java b/server/src/main/java/org/opensearch/rest/RestHandlerProxy.java deleted file mode 100644 index 74859ff51a978..0000000000000 --- a/server/src/main/java/org/opensearch/rest/RestHandlerProxy.java +++ /dev/null @@ -1,56 +0,0 @@ -/* - * SPDX-License-Identifier: Apache-2.0 - * - * The OpenSearch Contributors require contributions made to - * this file be licensed under the Apache-2.0 license or a - * compatible open source license. - */ - -package org.opensearch.rest; - -import org.opensearch.common.util.concurrent.ThreadContext; -import org.opensearch.plugins.ActionPlugin; -import org.opensearch.plugins.Plugin; -import org.opensearch.threadpool.ThreadPool; - -import java.lang.reflect.InvocationHandler; -import java.lang.reflect.InvocationTargetException; -import java.lang.reflect.Method; -import java.lang.reflect.Proxy; - -/** - * RestHandlerProxy is a wrapper around {@link RestHandler} that populates the ExecutionContext prior - * to delegating execution to a plugin for handling a REST Request - */ -public class RestHandlerProxy implements InvocationHandler { - private final RestHandler restHandler; - private final ThreadPool threadPool; - private final ActionPlugin plugin; - - public static RestHandler newInstance(RestHandler obj, ThreadPool threadPool, ActionPlugin plugin) { - return (RestHandler) Proxy.newProxyInstance( - obj.getClass().getClassLoader(), - new Class[] { RestHandler.class }, - new RestHandlerProxy(obj, threadPool, plugin) - ); - } - - private RestHandlerProxy(RestHandler restHandler, ThreadPool threadPool, ActionPlugin plugin) { - this.restHandler = restHandler; - this.threadPool = threadPool; - this.plugin = plugin; - } - - @Override - public Object invoke(Object proxy, Method m, Object[] args) throws Throwable { - Object result; - try (ThreadContext.StoredContext threadContext = threadPool.getThreadContext().switchContext((Plugin) plugin)) { - result = m.invoke(restHandler, args); - } catch (InvocationTargetException e) { - throw e.getTargetException(); - } catch (Exception e) { - throw new RuntimeException("unexpected invocation exception: " + e.getMessage()); - } - return result; - } -} diff --git a/server/src/main/java/org/opensearch/threadpool/PluginAwareThreadPoolWrapper.java b/server/src/main/java/org/opensearch/threadpool/PluginAwareThreadPoolWrapper.java deleted file mode 100644 index 08b8494b8c9ee..0000000000000 --- a/server/src/main/java/org/opensearch/threadpool/PluginAwareThreadPoolWrapper.java +++ /dev/null @@ -1,27 +0,0 @@ -/* - * SPDX-License-Identifier: Apache-2.0 - * - * The OpenSearch Contributors require contributions made to - * this file be licensed under the Apache-2.0 license or a - * compatible open source license. - */ - -package org.opensearch.threadpool; - -import org.opensearch.common.util.concurrent.PluginAwareThreadContextWrapper; -import org.opensearch.plugins.Plugin; - -public class PluginAwareThreadPoolWrapper { - - private ThreadPool threadPool; - private Plugin plugin; - - public PluginAwareThreadPoolWrapper(ThreadPool threadPool, Plugin plugin) { - this.threadPool = threadPool; - this.plugin = plugin; - } - - public PluginAwareThreadContextWrapper getPluginAwareThreadContext() { - return new PluginAwareThreadContextWrapper(threadPool.getThreadContext(), plugin); - } -} diff --git a/server/src/main/java/org/opensearch/threadpool/ThreadPoolProxy.java b/server/src/main/java/org/opensearch/threadpool/ThreadPoolProxy.java deleted file mode 100644 index 3319f32b23528..0000000000000 --- a/server/src/main/java/org/opensearch/threadpool/ThreadPoolProxy.java +++ /dev/null @@ -1,45 +0,0 @@ -/* - * SPDX-License-Identifier: Apache-2.0 - * - * The OpenSearch Contributors require contributions made to - * this file be licensed under the Apache-2.0 license or a - * compatible open source license. - */ - -package org.opensearch.threadpool; - -import org.opensearch.concurrent.ThreadContextProxy; -import org.opensearch.plugins.Plugin; - -import java.lang.reflect.InvocationHandler; -import java.lang.reflect.Method; -import java.lang.reflect.Proxy; - -public class ThreadPoolProxy implements InvocationHandler { - private final ThreadPool threadPool; - private final Plugin plugin; - - public static ThreadPool newInstance(ThreadPool threadPool, Plugin plugin) { - return (ThreadPool) Proxy.newProxyInstance( - threadPool.getClass().getClassLoader(), - new Class[] { ThreadPool.class }, - new ThreadPoolProxy(threadPool, plugin) - ); - } - - private ThreadPoolProxy(ThreadPool threadPool, Plugin plugin) { - this.threadPool = threadPool; - this.plugin = plugin; - } - - @Override - public Object invoke(Object proxy, Method m, Object[] args) throws Throwable { - Object result; - if ("getThreadContext".equals(m.getName())) { - result = ThreadContextProxy.getInstance(threadPool.getThreadContext(), plugin); - } else { - result = m.invoke(threadPool, args); - } - return result; - } -} From 4d048b74267da1ab9702c254c04c3d4c80ef806e Mon Sep 17 00:00:00 2001 From: Craig Perkins Date: Fri, 12 Jul 2024 11:07:19 -0400 Subject: [PATCH 10/65] Remove ExecutionContext class Signed-off-by: Craig Perkins --- .../util/concurrent/ExecutionContext.java | 48 ------------------- 1 file changed, 48 deletions(-) delete mode 100644 server/src/main/java/org/opensearch/common/util/concurrent/ExecutionContext.java diff --git a/server/src/main/java/org/opensearch/common/util/concurrent/ExecutionContext.java b/server/src/main/java/org/opensearch/common/util/concurrent/ExecutionContext.java deleted file mode 100644 index f708c0abfffaf..0000000000000 --- a/server/src/main/java/org/opensearch/common/util/concurrent/ExecutionContext.java +++ /dev/null @@ -1,48 +0,0 @@ -/* - * SPDX-License-Identifier: Apache-2.0 - * - * The OpenSearch Contributors require contributions made to - * this file be licensed under the Apache-2.0 license or a - * compatible open source license. - */ - -package org.opensearch.common.util.concurrent; - -import org.opensearch.plugins.Plugin; - -import java.util.Stack; - -/** - * An ExecutionContext is a singular header within ThreadLocal that contains the chain of plugins on the execution path - */ -public class ExecutionContext { - private final ThreadLocal> context = new ThreadLocal<>(); - - public void add(Plugin plugin) { - if (context.get() == null) { - context.set(new Stack<>()); - } - context.get().add(plugin.getClass().getCanonicalName()); - } - - public Stack get() { - if (context.get() == null) { - return null; - } - return context.get(); - } - - public String peek() { - if (context.get() == null || context.get().isEmpty()) { - return null; - } - return context.get().peek(); - } - - public String pop() { - if (context.get() == null || context.get().isEmpty()) { - return null; - } - return context.get().pop(); - } -} From 70c0c800883701a78ab88bddc29b6c81abd72725 Mon Sep 17 00:00:00 2001 From: Craig Perkins Date: Fri, 12 Jul 2024 11:11:23 -0400 Subject: [PATCH 11/65] Update javadoc Signed-off-by: Craig Perkins --- .../org/opensearch/common/util/concurrent/ThreadContext.java | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/server/src/main/java/org/opensearch/common/util/concurrent/ThreadContext.java b/server/src/main/java/org/opensearch/common/util/concurrent/ThreadContext.java index 7f924e7ae4dcf..9c011b2570731 100644 --- a/server/src/main/java/org/opensearch/common/util/concurrent/ThreadContext.java +++ b/server/src/main/java/org/opensearch/common/util/concurrent/ThreadContext.java @@ -179,8 +179,8 @@ public StoredContext stashContext() { } /** - * Removes the current context and resets a default context. The removed context can be - * restored by closing the returned {@link StoredContext}. + * Removes the current context and resets a default context. Retains information about plugin stashing the context. + * The removed context can be restored by closing the returned {@link StoredContext}. */ StoredContext stashContext(Class pluginClass) { final ThreadContextStruct context = threadLocal.get(); From dc5c5a8ef85e06b76cfc61dab5535272321f287f Mon Sep 17 00:00:00 2001 From: Craig Perkins Date: Fri, 12 Jul 2024 11:20:21 -0400 Subject: [PATCH 12/65] Change createComponents to take in PluginAwareNodeClient Signed-off-by: Craig Perkins --- server/src/main/java/org/opensearch/plugins/Plugin.java | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/server/src/main/java/org/opensearch/plugins/Plugin.java b/server/src/main/java/org/opensearch/plugins/Plugin.java index 33c4155d12c25..15427fb1051c1 100644 --- a/server/src/main/java/org/opensearch/plugins/Plugin.java +++ b/server/src/main/java/org/opensearch/plugins/Plugin.java @@ -33,7 +33,7 @@ package org.opensearch.plugins; import org.opensearch.bootstrap.BootstrapCheck; -import org.opensearch.client.Client; +import org.opensearch.client.node.PluginAwareNodeClient; import org.opensearch.cluster.ClusterState; import org.opensearch.cluster.metadata.IndexNameExpressionResolver; import org.opensearch.cluster.metadata.IndexTemplateMetadata; @@ -140,7 +140,7 @@ public Collection> getGuiceServiceClasses() * is called, but will return the repositories service once the node is initialized. */ public Collection createComponents( - Client client, + PluginAwareNodeClient client, ClusterService clusterService, ThreadPool threadPool, ResourceWatcherService resourceWatcherService, From e26ac6ce7f4f35df483ec2c788325d677041248c Mon Sep 17 00:00:00 2001 From: Craig Perkins Date: Fri, 12 Jul 2024 12:33:46 -0400 Subject: [PATCH 13/65] Update all instances of createComponents Signed-off-by: Craig Perkins --- .../analysis/common/CommonAnalysisModulePlugin.java | 4 ++-- .../java/org/opensearch/painless/PainlessModulePlugin.java | 4 ++-- .../org/opensearch/index/reindex/ReindexModulePlugin.java | 4 ++-- .../index/reindex/ReindexFromRemoteWithAuthTests.java | 4 ++-- .../main/java/org/opensearch/systemd/SystemdModulePlugin.java | 4 ++-- .../plugin/correlation/EventsCorrelationPlugin.java | 4 ++-- .../org/opensearch/plugin/insights/QueryInsightsPlugin.java | 4 ++-- .../opensearch/plugin/insights/QueryInsightsPluginTests.java | 4 ++-- .../org/opensearch/repositories/s3/S3RepositoryPlugin.java | 4 ++-- .../java/org/opensearch/http/TestExecutionContextPlugin.java | 2 +- .../org/opensearch/action/ingest/AsyncIngestProcessorIT.java | 4 ++-- .../java/org/opensearch/cluster/SimpleClusterStateIT.java | 3 ++- .../opensearch/cluster/metadata/TemplateUpgradeServiceIT.java | 4 ++-- .../java/org/opensearch/index/FinalPipelineIT.java | 4 ++-- .../util/concurrent/PluginAwareThreadContextWrapper.java | 4 ++++ .../java/org/opensearch/plugins/TelemetryAwarePlugin.java | 4 ++-- server/src/test/java/org/opensearch/node/NodeTests.java | 4 ++-- 17 files changed, 35 insertions(+), 30 deletions(-) diff --git a/modules/analysis-common/src/main/java/org/opensearch/analysis/common/CommonAnalysisModulePlugin.java b/modules/analysis-common/src/main/java/org/opensearch/analysis/common/CommonAnalysisModulePlugin.java index cf2736a8583d2..dc0f84cea9ccf 100644 --- a/modules/analysis-common/src/main/java/org/opensearch/analysis/common/CommonAnalysisModulePlugin.java +++ b/modules/analysis-common/src/main/java/org/opensearch/analysis/common/CommonAnalysisModulePlugin.java @@ -125,7 +125,7 @@ import org.apache.lucene.analysis.tr.TurkishAnalyzer; import org.apache.lucene.analysis.util.ElisionFilter; import org.opensearch.Version; -import org.opensearch.client.Client; +import org.opensearch.client.node.PluginAwareNodeClient; import org.opensearch.cluster.metadata.IndexNameExpressionResolver; import org.opensearch.cluster.service.ClusterService; import org.opensearch.common.SetOnce; @@ -177,7 +177,7 @@ public class CommonAnalysisModulePlugin extends Plugin implements AnalysisPlugin @Override public Collection createComponents( - Client client, + PluginAwareNodeClient client, ClusterService clusterService, ThreadPool threadPool, ResourceWatcherService resourceWatcherService, diff --git a/modules/lang-painless/src/main/java/org/opensearch/painless/PainlessModulePlugin.java b/modules/lang-painless/src/main/java/org/opensearch/painless/PainlessModulePlugin.java index 55dc23f665d2e..246eb3fc68182 100644 --- a/modules/lang-painless/src/main/java/org/opensearch/painless/PainlessModulePlugin.java +++ b/modules/lang-painless/src/main/java/org/opensearch/painless/PainlessModulePlugin.java @@ -33,7 +33,7 @@ package org.opensearch.painless; import org.opensearch.action.ActionRequest; -import org.opensearch.client.Client; +import org.opensearch.client.node.PluginAwareNodeClient; import org.opensearch.cluster.metadata.IndexNameExpressionResolver; import org.opensearch.cluster.node.DiscoveryNodes; import org.opensearch.cluster.service.ClusterService; @@ -136,7 +136,7 @@ public ScriptEngine getScriptEngine(Settings settings, Collection createComponents( - Client client, + PluginAwareNodeClient client, ClusterService clusterService, ThreadPool threadPool, ResourceWatcherService resourceWatcherService, diff --git a/modules/reindex/src/main/java/org/opensearch/index/reindex/ReindexModulePlugin.java b/modules/reindex/src/main/java/org/opensearch/index/reindex/ReindexModulePlugin.java index aa48da4cb2421..92447d96dc051 100644 --- a/modules/reindex/src/main/java/org/opensearch/index/reindex/ReindexModulePlugin.java +++ b/modules/reindex/src/main/java/org/opensearch/index/reindex/ReindexModulePlugin.java @@ -35,7 +35,7 @@ import org.apache.logging.log4j.LogManager; import org.apache.logging.log4j.Logger; import org.opensearch.action.ActionRequest; -import org.opensearch.client.Client; +import org.opensearch.client.node.PluginAwareNodeClient; import org.opensearch.cluster.metadata.IndexNameExpressionResolver; import org.opensearch.cluster.node.DiscoveryNodes; import org.opensearch.cluster.service.ClusterService; @@ -112,7 +112,7 @@ public List getRestHandlers( @Override public Collection createComponents( - Client client, + PluginAwareNodeClient client, ClusterService clusterService, ThreadPool threadPool, ResourceWatcherService resourceWatcherService, diff --git a/modules/reindex/src/test/java/org/opensearch/index/reindex/ReindexFromRemoteWithAuthTests.java b/modules/reindex/src/test/java/org/opensearch/index/reindex/ReindexFromRemoteWithAuthTests.java index 0d3cf208aabfb..4bc09cdc2ec36 100644 --- a/modules/reindex/src/test/java/org/opensearch/index/reindex/ReindexFromRemoteWithAuthTests.java +++ b/modules/reindex/src/test/java/org/opensearch/index/reindex/ReindexFromRemoteWithAuthTests.java @@ -40,7 +40,7 @@ import org.opensearch.action.support.ActionFilter; import org.opensearch.action.support.ActionFilterChain; import org.opensearch.action.support.WriteRequest.RefreshPolicy; -import org.opensearch.client.Client; +import org.opensearch.client.node.PluginAwareNodeClient; import org.opensearch.cluster.metadata.IndexNameExpressionResolver; import org.opensearch.cluster.service.ClusterService; import org.opensearch.common.SetOnce; @@ -176,7 +176,7 @@ public static class TestPlugin extends Plugin implements ActionPlugin { @Override public Collection createComponents( - Client client, + PluginAwareNodeClient client, ClusterService clusterService, ThreadPool threadPool, ResourceWatcherService resourceWatcherService, diff --git a/modules/systemd/src/main/java/org/opensearch/systemd/SystemdModulePlugin.java b/modules/systemd/src/main/java/org/opensearch/systemd/SystemdModulePlugin.java index 6e291027fa35f..a63b62c892741 100644 --- a/modules/systemd/src/main/java/org/opensearch/systemd/SystemdModulePlugin.java +++ b/modules/systemd/src/main/java/org/opensearch/systemd/SystemdModulePlugin.java @@ -34,7 +34,7 @@ import org.apache.logging.log4j.LogManager; import org.apache.logging.log4j.Logger; -import org.opensearch.client.Client; +import org.opensearch.client.node.PluginAwareNodeClient; import org.opensearch.cluster.metadata.IndexNameExpressionResolver; import org.opensearch.cluster.service.ClusterService; import org.opensearch.common.SetOnce; @@ -90,7 +90,7 @@ Scheduler.Cancellable extender() { @Override public Collection createComponents( - final Client client, + final PluginAwareNodeClient client, final ClusterService clusterService, final ThreadPool threadPool, final ResourceWatcherService resourceWatcherService, diff --git a/plugins/events-correlation-engine/src/main/java/org/opensearch/plugin/correlation/EventsCorrelationPlugin.java b/plugins/events-correlation-engine/src/main/java/org/opensearch/plugin/correlation/EventsCorrelationPlugin.java index 9637042974d03..0a95b8863bdd5 100644 --- a/plugins/events-correlation-engine/src/main/java/org/opensearch/plugin/correlation/EventsCorrelationPlugin.java +++ b/plugins/events-correlation-engine/src/main/java/org/opensearch/plugin/correlation/EventsCorrelationPlugin.java @@ -9,7 +9,7 @@ package org.opensearch.plugin.correlation; import org.opensearch.action.ActionRequest; -import org.opensearch.client.Client; +import org.opensearch.client.node.PluginAwareNodeClient; import org.opensearch.cluster.metadata.IndexNameExpressionResolver; import org.opensearch.cluster.node.DiscoveryNodes; import org.opensearch.cluster.service.ClusterService; @@ -77,7 +77,7 @@ public EventsCorrelationPlugin() {} @Override public Collection createComponents( - Client client, + PluginAwareNodeClient client, ClusterService clusterService, ThreadPool threadPool, ResourceWatcherService resourceWatcherService, diff --git a/plugins/query-insights/src/main/java/org/opensearch/plugin/insights/QueryInsightsPlugin.java b/plugins/query-insights/src/main/java/org/opensearch/plugin/insights/QueryInsightsPlugin.java index bba676436c39a..a1542d2146f4f 100644 --- a/plugins/query-insights/src/main/java/org/opensearch/plugin/insights/QueryInsightsPlugin.java +++ b/plugins/query-insights/src/main/java/org/opensearch/plugin/insights/QueryInsightsPlugin.java @@ -9,7 +9,7 @@ package org.opensearch.plugin.insights; import org.opensearch.action.ActionRequest; -import org.opensearch.client.Client; +import org.opensearch.client.node.PluginAwareNodeClient; import org.opensearch.cluster.metadata.IndexNameExpressionResolver; import org.opensearch.cluster.node.DiscoveryNodes; import org.opensearch.cluster.service.ClusterService; @@ -57,7 +57,7 @@ public QueryInsightsPlugin() {} @Override public Collection createComponents( - final Client client, + final PluginAwareNodeClient client, final ClusterService clusterService, final ThreadPool threadPool, final ResourceWatcherService resourceWatcherService, diff --git a/plugins/query-insights/src/test/java/org/opensearch/plugin/insights/QueryInsightsPluginTests.java b/plugins/query-insights/src/test/java/org/opensearch/plugin/insights/QueryInsightsPluginTests.java index 2efe9085a39ee..7260508f1ab9c 100644 --- a/plugins/query-insights/src/test/java/org/opensearch/plugin/insights/QueryInsightsPluginTests.java +++ b/plugins/query-insights/src/test/java/org/opensearch/plugin/insights/QueryInsightsPluginTests.java @@ -9,7 +9,7 @@ package org.opensearch.plugin.insights; import org.opensearch.action.ActionRequest; -import org.opensearch.client.Client; +import org.opensearch.client.node.PluginAwareNodeClient; import org.opensearch.cluster.service.ClusterService; import org.opensearch.common.settings.ClusterSettings; import org.opensearch.common.settings.Settings; @@ -37,7 +37,7 @@ public class QueryInsightsPluginTests extends OpenSearchTestCase { private QueryInsightsPlugin queryInsightsPlugin; - private final Client client = mock(Client.class); + private final PluginAwareNodeClient client = mock(PluginAwareNodeClient.class); private ClusterService clusterService; private final ThreadPool threadPool = mock(ThreadPool.class); diff --git a/plugins/repository-s3/src/main/java/org/opensearch/repositories/s3/S3RepositoryPlugin.java b/plugins/repository-s3/src/main/java/org/opensearch/repositories/s3/S3RepositoryPlugin.java index 110d91bfbd822..0099200e209ce 100644 --- a/plugins/repository-s3/src/main/java/org/opensearch/repositories/s3/S3RepositoryPlugin.java +++ b/plugins/repository-s3/src/main/java/org/opensearch/repositories/s3/S3RepositoryPlugin.java @@ -32,7 +32,7 @@ package org.opensearch.repositories.s3; -import org.opensearch.client.Client; +import org.opensearch.client.node.PluginAwareNodeClient; import org.opensearch.cluster.metadata.IndexNameExpressionResolver; import org.opensearch.cluster.metadata.RepositoryMetadata; import org.opensearch.cluster.service.ClusterService; @@ -201,7 +201,7 @@ private static int normalPoolCount(Settings settings) { @Override public Collection createComponents( - final Client client, + final PluginAwareNodeClient client, final ClusterService clusterService, final ThreadPool threadPool, final ResourceWatcherService resourceWatcherService, diff --git a/qa/smoke-test-http/src/test/java/org/opensearch/http/TestExecutionContextPlugin.java b/qa/smoke-test-http/src/test/java/org/opensearch/http/TestExecutionContextPlugin.java index a004d31cf4920..62e72a32b4b35 100644 --- a/qa/smoke-test-http/src/test/java/org/opensearch/http/TestExecutionContextPlugin.java +++ b/qa/smoke-test-http/src/test/java/org/opensearch/http/TestExecutionContextPlugin.java @@ -43,7 +43,7 @@ public class TestExecutionContextPlugin extends Plugin implements ActionPlugin { @Override public Collection createComponents( - Client client, + PluginAwareNodeClient client, ClusterService clusterService, ThreadPool threadPool, ResourceWatcherService resourceWatcherService, diff --git a/server/src/internalClusterTest/java/org/opensearch/action/ingest/AsyncIngestProcessorIT.java b/server/src/internalClusterTest/java/org/opensearch/action/ingest/AsyncIngestProcessorIT.java index aefabcb9bc14f..d124f2d8ab459 100644 --- a/server/src/internalClusterTest/java/org/opensearch/action/ingest/AsyncIngestProcessorIT.java +++ b/server/src/internalClusterTest/java/org/opensearch/action/ingest/AsyncIngestProcessorIT.java @@ -36,7 +36,7 @@ import org.opensearch.action.get.GetRequest; import org.opensearch.action.get.GetResponse; import org.opensearch.action.index.IndexRequest; -import org.opensearch.client.Client; +import org.opensearch.client.node.PluginAwareNodeClient; import org.opensearch.cluster.metadata.IndexNameExpressionResolver; import org.opensearch.cluster.service.ClusterService; import org.opensearch.core.common.bytes.BytesArray; @@ -110,7 +110,7 @@ public static class TestPlugin extends Plugin implements IngestPlugin { @Override public Collection createComponents( - Client client, + PluginAwareNodeClient client, ClusterService clusterService, ThreadPool threadPool, ResourceWatcherService resourceWatcherService, diff --git a/server/src/internalClusterTest/java/org/opensearch/cluster/SimpleClusterStateIT.java b/server/src/internalClusterTest/java/org/opensearch/cluster/SimpleClusterStateIT.java index af5900b1cba6c..a07a82c9b1f45 100644 --- a/server/src/internalClusterTest/java/org/opensearch/cluster/SimpleClusterStateIT.java +++ b/server/src/internalClusterTest/java/org/opensearch/cluster/SimpleClusterStateIT.java @@ -38,6 +38,7 @@ import org.opensearch.action.support.IndicesOptions; import org.opensearch.client.Client; import org.opensearch.client.Requests; +import org.opensearch.client.node.PluginAwareNodeClient; import org.opensearch.cluster.metadata.IndexMetadata; import org.opensearch.cluster.metadata.IndexNameExpressionResolver; import org.opensearch.cluster.metadata.MappingMetadata; @@ -459,7 +460,7 @@ public List getNamedWriteables() { @Override public Collection createComponents( - final Client client, + final PluginAwareNodeClient client, final ClusterService clusterService, final ThreadPool threadPool, final ResourceWatcherService resourceWatcherService, diff --git a/server/src/internalClusterTest/java/org/opensearch/cluster/metadata/TemplateUpgradeServiceIT.java b/server/src/internalClusterTest/java/org/opensearch/cluster/metadata/TemplateUpgradeServiceIT.java index ba1679d873bf4..9dc80210d6b7b 100644 --- a/server/src/internalClusterTest/java/org/opensearch/cluster/metadata/TemplateUpgradeServiceIT.java +++ b/server/src/internalClusterTest/java/org/opensearch/cluster/metadata/TemplateUpgradeServiceIT.java @@ -34,7 +34,7 @@ import org.apache.logging.log4j.LogManager; import org.apache.logging.log4j.Logger; -import org.opensearch.client.Client; +import org.opensearch.client.node.PluginAwareNodeClient; import org.opensearch.cluster.service.ClusterService; import org.opensearch.common.settings.Setting; import org.opensearch.common.settings.Settings; @@ -87,7 +87,7 @@ public TestPlugin(Settings settings) { @Override public Collection createComponents( - Client client, + PluginAwareNodeClient client, ClusterService clusterService, ThreadPool threadPool, ResourceWatcherService resourceWatcherService, diff --git a/server/src/internalClusterTest/java/org/opensearch/index/FinalPipelineIT.java b/server/src/internalClusterTest/java/org/opensearch/index/FinalPipelineIT.java index 03b8fb5ff7afc..d5eef4209376f 100644 --- a/server/src/internalClusterTest/java/org/opensearch/index/FinalPipelineIT.java +++ b/server/src/internalClusterTest/java/org/opensearch/index/FinalPipelineIT.java @@ -42,7 +42,7 @@ import org.opensearch.action.ingest.PutPipelineRequest; import org.opensearch.action.search.SearchResponse; import org.opensearch.action.support.WriteRequest; -import org.opensearch.client.Client; +import org.opensearch.client.node.PluginAwareNodeClient; import org.opensearch.cluster.metadata.IndexNameExpressionResolver; import org.opensearch.cluster.service.ClusterService; import org.opensearch.common.settings.Settings; @@ -363,7 +363,7 @@ public static class TestPlugin extends Plugin implements IngestPlugin { @Override public Collection createComponents( - final Client client, + final PluginAwareNodeClient client, final ClusterService clusterService, final ThreadPool threadPool, final ResourceWatcherService resourceWatcherService, diff --git a/server/src/main/java/org/opensearch/common/util/concurrent/PluginAwareThreadContextWrapper.java b/server/src/main/java/org/opensearch/common/util/concurrent/PluginAwareThreadContextWrapper.java index 46ea3a3038915..d66b05868c692 100644 --- a/server/src/main/java/org/opensearch/common/util/concurrent/PluginAwareThreadContextWrapper.java +++ b/server/src/main/java/org/opensearch/common/util/concurrent/PluginAwareThreadContextWrapper.java @@ -10,6 +10,10 @@ import org.opensearch.plugins.Plugin; +/** + * Wrapper class around the ThreadContext that is used within {@link org.opensearch.client.node.PluginAwareNodeClient} + * to enable retaining information about the plugin when switching out an authenticated user context + */ public class PluginAwareThreadContextWrapper { private final ThreadContext threadContext; diff --git a/server/src/main/java/org/opensearch/plugins/TelemetryAwarePlugin.java b/server/src/main/java/org/opensearch/plugins/TelemetryAwarePlugin.java index 42cab326f88bf..471b334846160 100644 --- a/server/src/main/java/org/opensearch/plugins/TelemetryAwarePlugin.java +++ b/server/src/main/java/org/opensearch/plugins/TelemetryAwarePlugin.java @@ -8,7 +8,7 @@ package org.opensearch.plugins; -import org.opensearch.client.Client; +import org.opensearch.client.node.PluginAwareNodeClient; import org.opensearch.cluster.metadata.IndexNameExpressionResolver; import org.opensearch.cluster.service.ClusterService; import org.opensearch.common.annotation.ExperimentalApi; @@ -61,7 +61,7 @@ public interface TelemetryAwarePlugin { * @param metricsRegistry the registry for metrics instrumentation. */ default Collection createComponents( - Client client, + PluginAwareNodeClient client, ClusterService clusterService, ThreadPool threadPool, ResourceWatcherService resourceWatcherService, diff --git a/server/src/test/java/org/opensearch/node/NodeTests.java b/server/src/test/java/org/opensearch/node/NodeTests.java index 0093091f61a1c..45328769d8b29 100644 --- a/server/src/test/java/org/opensearch/node/NodeTests.java +++ b/server/src/test/java/org/opensearch/node/NodeTests.java @@ -34,7 +34,7 @@ import org.apache.lucene.tests.util.LuceneTestCase; import org.opensearch.bootstrap.BootstrapCheck; import org.opensearch.bootstrap.BootstrapContext; -import org.opensearch.client.Client; +import org.opensearch.client.node.PluginAwareNodeClient; import org.opensearch.cluster.ClusterName; import org.opensearch.cluster.metadata.IndexNameExpressionResolver; import org.opensearch.cluster.node.DiscoveryNodeRole; @@ -466,7 +466,7 @@ public MetricsRegistry getMetricsRegistry() { public static class MockTelemetryAwarePlugin extends Plugin implements TelemetryAwarePlugin { @Override public Collection createComponents( - Client client, + PluginAwareNodeClient client, ClusterService clusterService, ThreadPool threadPool, ResourceWatcherService resourceWatcherService, From c2e0a645ebe2eeebc2e8b753f9aa884a8fa28040 Mon Sep 17 00:00:00 2001 From: Craig Perkins Date: Fri, 12 Jul 2024 13:46:41 -0400 Subject: [PATCH 14/65] Initialize clients Signed-off-by: Craig Perkins --- .../main/java/org/opensearch/node/Node.java | 56 +++++++++++-------- 1 file changed, 33 insertions(+), 23 deletions(-) diff --git a/server/src/main/java/org/opensearch/node/Node.java b/server/src/main/java/org/opensearch/node/Node.java index 37267f1d726fb..063d3741812c3 100644 --- a/server/src/main/java/org/opensearch/node/Node.java +++ b/server/src/main/java/org/opensearch/node/Node.java @@ -931,30 +931,32 @@ protected Node( final ViewService viewService = new ViewService(clusterService, client, null); - Collection pluginComponents = pluginsService.filterPlugins(Plugin.class) - .stream() - .flatMap( - p -> p.createComponents( - new PluginAwareNodeClient(settings, threadPool, p), - clusterService, - threadPool, - resourceWatcherService, - scriptService, - xContentRegistry, - environment, - nodeEnvironment, - namedWriteableRegistry, - clusterModule.getIndexNameExpressionResolver(), - repositoriesServiceReference::get - ).stream() - ) - .collect(Collectors.toList()); + List pluginNodeClients = new ArrayList<>(); + Collection pluginComponents = pluginsService.filterPlugins(Plugin.class).stream().flatMap(p -> { + PluginAwareNodeClient pluginClient = new PluginAwareNodeClient(settings, threadPool, p); + pluginNodeClients.add(pluginClient); + return p.createComponents( + pluginClient, + clusterService, + threadPool, + resourceWatcherService, + scriptService, + xContentRegistry, + environment, + nodeEnvironment, + namedWriteableRegistry, + clusterModule.getIndexNameExpressionResolver(), + repositoriesServiceReference::get + ).stream(); + }).collect(Collectors.toList()); Collection telemetryAwarePluginComponents = pluginsService.filterPlugins(TelemetryAwarePlugin.class) .stream() - .flatMap( - p -> p.createComponents( - new PluginAwareNodeClient(settings, threadPool, (Plugin) p), + .flatMap(p -> { + PluginAwareNodeClient pluginClient = new PluginAwareNodeClient(settings, threadPool, (Plugin) p); + pluginNodeClients.add(pluginClient); + return p.createComponents( + pluginClient, clusterService, threadPool, resourceWatcherService, @@ -967,8 +969,8 @@ protected Node( repositoriesServiceReference::get, tracer, metricsRegistry - ).stream() - ) + ).stream(); + }) .collect(Collectors.toList()); // Add the telemetryAwarePlugin components to the existing pluginComponents collection. @@ -1430,6 +1432,14 @@ protected Node( transportService.getRemoteClusterService(), namedWriteableRegistry ); + for (PluginAwareNodeClient pluginClient : pluginNodeClients) { + pluginClient.initialize( + dynamicActionRegistry, + () -> clusterService.localNode().getId(), + transportService.getRemoteClusterService(), + namedWriteableRegistry + ); + } this.namedWriteableRegistry = namedWriteableRegistry; logger.debug("initializing HTTP handlers ..."); From 1d7df430a657a37b937f6281f73be12deb54e130 Mon Sep 17 00:00:00 2001 From: Craig Perkins Date: Tue, 16 Jul 2024 09:04:50 -0400 Subject: [PATCH 15/65] Remove casting Signed-off-by: Craig Perkins --- .../java/org/opensearch/http/TestExecutionContextPlugin.java | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/qa/smoke-test-http/src/test/java/org/opensearch/http/TestExecutionContextPlugin.java b/qa/smoke-test-http/src/test/java/org/opensearch/http/TestExecutionContextPlugin.java index 62e72a32b4b35..093fb7e3e90a2 100644 --- a/qa/smoke-test-http/src/test/java/org/opensearch/http/TestExecutionContextPlugin.java +++ b/qa/smoke-test-http/src/test/java/org/opensearch/http/TestExecutionContextPlugin.java @@ -39,7 +39,7 @@ public class TestExecutionContextPlugin extends Plugin implements ActionPlugin { - private Client client; + private PluginAwareNodeClient client; @Override public Collection createComponents( @@ -63,6 +63,6 @@ public Collection createComponents( public List getRestHandlers(Settings settings, RestController restController, ClusterSettings clusterSettings, IndexScopedSettings indexScopedSettings, SettingsFilter settingsFilter, IndexNameExpressionResolver indexNameExpressionResolver, Supplier nodesInCluster) { - return List.of(new TestGetExecutionContextRestAction((PluginAwareNodeClient) client)); + return List.of(new TestGetExecutionContextRestAction(client)); } } From 711d5428e587e45ab7d086d958de00f33d41aef0 Mon Sep 17 00:00:00 2001 From: Craig Perkins Date: Thu, 18 Jul 2024 14:04:06 -0400 Subject: [PATCH 16/65] WIP on notion of ContextSwitcher Signed-off-by: Craig Perkins --- .../common/CommonAnalysisModulePlugin.java | 8 ++- .../PredicateTokenScriptFilterTests.java | 2 +- .../ScriptedConditionTokenFilterTests.java | 2 +- .../painless/PainlessModulePlugin.java | 8 ++- .../index/reindex/ReindexModulePlugin.java | 8 ++- .../ReindexFromRemoteWithAuthTests.java | 8 ++- .../RemoteScrollableHitSourceTests.java | 2 - .../systemd/SystemdModulePlugin.java | 8 ++- .../systemd/SystemdModulePluginTests.java | 6 +- .../correlation/EventsCorrelationPlugin.java | 8 ++- .../repositories/s3/S3RepositoryPlugin.java | 8 ++- .../common/logging/JsonLoggerTests.java | 9 +-- .../http/TestExecutionContextPlugin.java | 19 +++--- .../TestGetExecutionContextRestAction.java | 16 ++--- .../action/ingest/AsyncIngestProcessorIT.java | 8 ++- .../cluster/SimpleClusterStateIT.java | 7 +- .../metadata/TemplateUpgradeServiceIT.java | 11 ++-- .../org/opensearch/index/FinalPipelineIT.java | 8 ++- .../opensearch/action/SystemIndexFilter.java | 66 +++++++++++++++++++ .../client/node/PluginAwareNodeClient.java | 60 ----------------- .../service/ClusterApplierService.java | 5 +- .../cluster/service/MasterService.java | 5 +- .../util/concurrent/ContextSwitcher.java | 35 ++++++++++ .../concurrent/InternalContextSwitcher.java | 31 +++++++++ .../PluginAwareThreadContextWrapper.java | 30 --------- .../common/util/concurrent/ThreadContext.java | 4 +- .../http/AbstractHttpServerTransport.java | 5 +- .../seqno/GlobalCheckpointSyncAction.java | 5 +- .../RetentionLeaseBackgroundSyncAction.java | 6 +- .../index/seqno/RetentionLeaseSyncAction.java | 6 +- .../opensearch/index/shard/IndexShard.java | 2 +- .../index/shard/RefreshListeners.java | 14 ++-- .../checkpoint/PublishCheckpointAction.java | 5 +- .../main/java/org/opensearch/node/Node.java | 27 +++----- .../java/org/opensearch/plugins/Plugin.java | 29 ++++---- .../plugins/TelemetryAwarePlugin.java | 8 ++- .../transport/NativeMessageHandler.java | 5 +- .../opensearch/transport/OutboundHandler.java | 5 +- .../transport/RemoteClusterConnection.java | 5 +- .../transport/SniffConnectionStrategy.java | 5 +- .../action/bulk/BulkProcessorTests.java | 5 +- .../opensearch/action/bulk/RetryTests.java | 2 +- .../ContextPreservingActionListenerTests.java | 28 +++++--- .../metadata/TemplateUpgradeServiceTests.java | 5 +- .../service/ClusterApplierServiceTests.java | 5 +- .../cluster/service/MasterServiceTests.java | 5 +- .../index/shard/RefreshListenersTests.java | 13 ++-- .../java/org/opensearch/node/NodeTests.java | 4 +- .../indices/RestValidateQueryActionTests.java | 7 -- ...ContextBasedTracerContextStorageTests.java | 27 +++++--- .../FakeThreadPoolClusterManagerService.java | 5 +- .../opensearch/test/OpenSearchTestCase.java | 2 +- 52 files changed, 367 insertions(+), 250 deletions(-) create mode 100644 server/src/main/java/org/opensearch/action/SystemIndexFilter.java delete mode 100644 server/src/main/java/org/opensearch/client/node/PluginAwareNodeClient.java create mode 100644 server/src/main/java/org/opensearch/common/util/concurrent/ContextSwitcher.java create mode 100644 server/src/main/java/org/opensearch/common/util/concurrent/InternalContextSwitcher.java delete mode 100644 server/src/main/java/org/opensearch/common/util/concurrent/PluginAwareThreadContextWrapper.java diff --git a/modules/analysis-common/src/main/java/org/opensearch/analysis/common/CommonAnalysisModulePlugin.java b/modules/analysis-common/src/main/java/org/opensearch/analysis/common/CommonAnalysisModulePlugin.java index dc0f84cea9ccf..8d12af5224aff 100644 --- a/modules/analysis-common/src/main/java/org/opensearch/analysis/common/CommonAnalysisModulePlugin.java +++ b/modules/analysis-common/src/main/java/org/opensearch/analysis/common/CommonAnalysisModulePlugin.java @@ -125,13 +125,14 @@ import org.apache.lucene.analysis.tr.TurkishAnalyzer; import org.apache.lucene.analysis.util.ElisionFilter; import org.opensearch.Version; -import org.opensearch.client.node.PluginAwareNodeClient; +import org.opensearch.client.Client; import org.opensearch.cluster.metadata.IndexNameExpressionResolver; import org.opensearch.cluster.service.ClusterService; import org.opensearch.common.SetOnce; import org.opensearch.common.logging.DeprecationLogger; import org.opensearch.common.regex.Regex; import org.opensearch.common.settings.Settings; +import org.opensearch.common.util.concurrent.ContextSwitcher; import org.opensearch.core.common.io.stream.NamedWriteableRegistry; import org.opensearch.core.xcontent.NamedXContentRegistry; import org.opensearch.env.Environment; @@ -177,7 +178,7 @@ public class CommonAnalysisModulePlugin extends Plugin implements AnalysisPlugin @Override public Collection createComponents( - PluginAwareNodeClient client, + Client client, ClusterService clusterService, ThreadPool threadPool, ResourceWatcherService resourceWatcherService, @@ -187,7 +188,8 @@ public Collection createComponents( NodeEnvironment nodeEnvironment, NamedWriteableRegistry namedWriteableRegistry, IndexNameExpressionResolver expressionResolver, - Supplier repositoriesServiceSupplier + Supplier repositoriesServiceSupplier, + ContextSwitcher contextSwitcher ) { this.scriptService.set(scriptService); return Collections.emptyList(); diff --git a/modules/analysis-common/src/test/java/org/opensearch/analysis/common/PredicateTokenScriptFilterTests.java b/modules/analysis-common/src/test/java/org/opensearch/analysis/common/PredicateTokenScriptFilterTests.java index d88b5bc93c28f..451f0e8dd3afb 100644 --- a/modules/analysis-common/src/test/java/org/opensearch/analysis/common/PredicateTokenScriptFilterTests.java +++ b/modules/analysis-common/src/test/java/org/opensearch/analysis/common/PredicateTokenScriptFilterTests.java @@ -82,7 +82,7 @@ public FactoryType compile(Script script, ScriptContext FactoryType compile(Script script, ScriptContext createComponents( - PluginAwareNodeClient client, + Client client, ClusterService clusterService, ThreadPool threadPool, ResourceWatcherService resourceWatcherService, @@ -146,7 +147,8 @@ public Collection createComponents( NodeEnvironment nodeEnvironment, NamedWriteableRegistry namedWriteableRegistry, IndexNameExpressionResolver expressionResolver, - Supplier repositoriesServiceSupplier + Supplier repositoriesServiceSupplier, + ContextSwitcher contextSwitcher ) { // this is a hack to bind the painless script engine in guice (all components are added to guice), so that // the painless context api. this is a temporary measure until transport actions do no require guice diff --git a/modules/reindex/src/main/java/org/opensearch/index/reindex/ReindexModulePlugin.java b/modules/reindex/src/main/java/org/opensearch/index/reindex/ReindexModulePlugin.java index 92447d96dc051..11a968b99c3b6 100644 --- a/modules/reindex/src/main/java/org/opensearch/index/reindex/ReindexModulePlugin.java +++ b/modules/reindex/src/main/java/org/opensearch/index/reindex/ReindexModulePlugin.java @@ -35,7 +35,7 @@ import org.apache.logging.log4j.LogManager; import org.apache.logging.log4j.Logger; import org.opensearch.action.ActionRequest; -import org.opensearch.client.node.PluginAwareNodeClient; +import org.opensearch.client.Client; import org.opensearch.cluster.metadata.IndexNameExpressionResolver; import org.opensearch.cluster.node.DiscoveryNodes; import org.opensearch.cluster.service.ClusterService; @@ -44,6 +44,7 @@ import org.opensearch.common.settings.Setting; import org.opensearch.common.settings.Settings; import org.opensearch.common.settings.SettingsFilter; +import org.opensearch.common.util.concurrent.ContextSwitcher; import org.opensearch.core.action.ActionResponse; import org.opensearch.core.common.io.stream.NamedWriteableRegistry; import org.opensearch.core.xcontent.NamedXContentRegistry; @@ -112,7 +113,7 @@ public List getRestHandlers( @Override public Collection createComponents( - PluginAwareNodeClient client, + Client client, ClusterService clusterService, ThreadPool threadPool, ResourceWatcherService resourceWatcherService, @@ -122,7 +123,8 @@ public Collection createComponents( NodeEnvironment nodeEnvironment, NamedWriteableRegistry namedWriteableRegistry, IndexNameExpressionResolver expressionResolver, - Supplier repositoriesServiceSupplier + Supplier repositoriesServiceSupplier, + ContextSwitcher contextSwitcher ) { return Collections.singletonList(new ReindexSslConfig(environment.settings(), environment, resourceWatcherService)); } diff --git a/modules/reindex/src/test/java/org/opensearch/index/reindex/ReindexFromRemoteWithAuthTests.java b/modules/reindex/src/test/java/org/opensearch/index/reindex/ReindexFromRemoteWithAuthTests.java index 4bc09cdc2ec36..62ed9c6da4cda 100644 --- a/modules/reindex/src/test/java/org/opensearch/index/reindex/ReindexFromRemoteWithAuthTests.java +++ b/modules/reindex/src/test/java/org/opensearch/index/reindex/ReindexFromRemoteWithAuthTests.java @@ -40,12 +40,13 @@ import org.opensearch.action.support.ActionFilter; import org.opensearch.action.support.ActionFilterChain; import org.opensearch.action.support.WriteRequest.RefreshPolicy; -import org.opensearch.client.node.PluginAwareNodeClient; +import org.opensearch.client.Client; import org.opensearch.cluster.metadata.IndexNameExpressionResolver; import org.opensearch.cluster.service.ClusterService; import org.opensearch.common.SetOnce; import org.opensearch.common.network.NetworkModule; import org.opensearch.common.settings.Settings; +import org.opensearch.common.util.concurrent.ContextSwitcher; import org.opensearch.common.util.concurrent.ThreadContext; import org.opensearch.core.action.ActionListener; import org.opensearch.core.action.ActionResponse; @@ -176,7 +177,7 @@ public static class TestPlugin extends Plugin implements ActionPlugin { @Override public Collection createComponents( - PluginAwareNodeClient client, + Client client, ClusterService clusterService, ThreadPool threadPool, ResourceWatcherService resourceWatcherService, @@ -186,7 +187,8 @@ public Collection createComponents( NodeEnvironment nodeEnvironment, NamedWriteableRegistry namedWriteableRegistry, IndexNameExpressionResolver expressionResolver, - Supplier repositoriesServiceSupplier + Supplier repositoriesServiceSupplier, + ContextSwitcher contextSwitcher ) { testFilter.set(new ReindexFromRemoteWithAuthTests.TestFilter(threadPool)); return Collections.emptyList(); diff --git a/modules/reindex/src/test/java/org/opensearch/index/reindex/remote/RemoteScrollableHitSourceTests.java b/modules/reindex/src/test/java/org/opensearch/index/reindex/remote/RemoteScrollableHitSourceTests.java index 8aa66fc3cfd8c..325de0cef1f8c 100644 --- a/modules/reindex/src/test/java/org/opensearch/index/reindex/remote/RemoteScrollableHitSourceTests.java +++ b/modules/reindex/src/test/java/org/opensearch/index/reindex/remote/RemoteScrollableHitSourceTests.java @@ -606,8 +606,6 @@ protected Future doExecute( FutureCallback callback ) { try { - // Throw away the current thread context to simulate running async httpclient's thread pool - threadPool.getThreadContext().stashContext(); ClassicHttpRequest request = getRequest(requestProducer); URL resource = resources[responseCount]; String path = paths[responseCount++]; diff --git a/modules/systemd/src/main/java/org/opensearch/systemd/SystemdModulePlugin.java b/modules/systemd/src/main/java/org/opensearch/systemd/SystemdModulePlugin.java index a63b62c892741..967852c682b45 100644 --- a/modules/systemd/src/main/java/org/opensearch/systemd/SystemdModulePlugin.java +++ b/modules/systemd/src/main/java/org/opensearch/systemd/SystemdModulePlugin.java @@ -34,11 +34,12 @@ import org.apache.logging.log4j.LogManager; import org.apache.logging.log4j.Logger; -import org.opensearch.client.node.PluginAwareNodeClient; +import org.opensearch.client.Client; import org.opensearch.cluster.metadata.IndexNameExpressionResolver; import org.opensearch.cluster.service.ClusterService; import org.opensearch.common.SetOnce; import org.opensearch.common.unit.TimeValue; +import org.opensearch.common.util.concurrent.ContextSwitcher; import org.opensearch.core.common.io.stream.NamedWriteableRegistry; import org.opensearch.core.xcontent.NamedXContentRegistry; import org.opensearch.env.Environment; @@ -90,7 +91,7 @@ Scheduler.Cancellable extender() { @Override public Collection createComponents( - final PluginAwareNodeClient client, + final Client client, final ClusterService clusterService, final ThreadPool threadPool, final ResourceWatcherService resourceWatcherService, @@ -100,7 +101,8 @@ public Collection createComponents( final NodeEnvironment nodeEnvironment, final NamedWriteableRegistry namedWriteableRegistry, final IndexNameExpressionResolver expressionResolver, - final Supplier repositoriesServiceSupplier + final Supplier repositoriesServiceSupplier, + ContextSwitcher contextSwitcher ) { if (enabled == false) { extender.set(null); diff --git a/modules/systemd/src/test/java/org/opensearch/systemd/SystemdModulePluginTests.java b/modules/systemd/src/test/java/org/opensearch/systemd/SystemdModulePluginTests.java index 532d47cd009e0..1148be0577a0e 100644 --- a/modules/systemd/src/test/java/org/opensearch/systemd/SystemdModulePluginTests.java +++ b/modules/systemd/src/test/java/org/opensearch/systemd/SystemdModulePluginTests.java @@ -68,14 +68,14 @@ public class SystemdModulePluginTests extends OpenSearchTestCase { public void testIsImplicitlyNotEnabled() { final SystemdModulePlugin plugin = new SystemdModulePlugin(null); - plugin.createComponents(null, null, threadPool, null, null, null, null, null, null, null, null); + plugin.createComponents(null, null, threadPool, null, null, null, null, null, null, null, null, null); assertFalse(plugin.isEnabled()); assertNull(plugin.extender()); } public void testIsExplicitlyNotEnabled() { final SystemdModulePlugin plugin = new SystemdModulePlugin(Boolean.FALSE.toString()); - plugin.createComponents(null, null, threadPool, null, null, null, null, null, null, null, null); + plugin.createComponents(null, null, threadPool, null, null, null, null, null, null, null, null, null); assertFalse(plugin.isEnabled()); assertNull(plugin.extender()); } @@ -167,7 +167,7 @@ int sd_notify(final int unset_environment, final String state) { } }; - plugin.createComponents(null, null, threadPool, null, null, null, null, null, null, null, null); + plugin.createComponents(null, null, threadPool, null, null, null, null, null, null, null, null, null); if (Boolean.TRUE.toString().equals(esSDNotify)) { assertNotNull(plugin.extender()); } else { diff --git a/plugins/events-correlation-engine/src/main/java/org/opensearch/plugin/correlation/EventsCorrelationPlugin.java b/plugins/events-correlation-engine/src/main/java/org/opensearch/plugin/correlation/EventsCorrelationPlugin.java index 0a95b8863bdd5..c73d619f5ad8c 100644 --- a/plugins/events-correlation-engine/src/main/java/org/opensearch/plugin/correlation/EventsCorrelationPlugin.java +++ b/plugins/events-correlation-engine/src/main/java/org/opensearch/plugin/correlation/EventsCorrelationPlugin.java @@ -9,7 +9,7 @@ package org.opensearch.plugin.correlation; import org.opensearch.action.ActionRequest; -import org.opensearch.client.node.PluginAwareNodeClient; +import org.opensearch.client.Client; import org.opensearch.cluster.metadata.IndexNameExpressionResolver; import org.opensearch.cluster.node.DiscoveryNodes; import org.opensearch.cluster.service.ClusterService; @@ -18,6 +18,7 @@ import org.opensearch.common.settings.Setting; import org.opensearch.common.settings.Settings; import org.opensearch.common.settings.SettingsFilter; +import org.opensearch.common.util.concurrent.ContextSwitcher; import org.opensearch.core.action.ActionResponse; import org.opensearch.core.common.io.stream.NamedWriteableRegistry; import org.opensearch.core.xcontent.NamedXContentRegistry; @@ -77,7 +78,7 @@ public EventsCorrelationPlugin() {} @Override public Collection createComponents( - PluginAwareNodeClient client, + Client client, ClusterService clusterService, ThreadPool threadPool, ResourceWatcherService resourceWatcherService, @@ -87,7 +88,8 @@ public Collection createComponents( NodeEnvironment nodeEnvironment, NamedWriteableRegistry namedWriteableRegistry, IndexNameExpressionResolver indexNameExpressionResolver, - Supplier repositoriesServiceSupplier + Supplier repositoriesServiceSupplier, + ContextSwitcher contextSwitcher ) { correlationRuleIndices = new CorrelationRuleIndices(client, clusterService); return List.of(correlationRuleIndices); diff --git a/plugins/repository-s3/src/main/java/org/opensearch/repositories/s3/S3RepositoryPlugin.java b/plugins/repository-s3/src/main/java/org/opensearch/repositories/s3/S3RepositoryPlugin.java index 0099200e209ce..d5f29503cb325 100644 --- a/plugins/repository-s3/src/main/java/org/opensearch/repositories/s3/S3RepositoryPlugin.java +++ b/plugins/repository-s3/src/main/java/org/opensearch/repositories/s3/S3RepositoryPlugin.java @@ -32,13 +32,14 @@ package org.opensearch.repositories.s3; -import org.opensearch.client.node.PluginAwareNodeClient; +import org.opensearch.client.Client; import org.opensearch.cluster.metadata.IndexNameExpressionResolver; import org.opensearch.cluster.metadata.RepositoryMetadata; import org.opensearch.cluster.service.ClusterService; import org.opensearch.common.settings.Setting; import org.opensearch.common.settings.Settings; import org.opensearch.common.unit.TimeValue; +import org.opensearch.common.util.concurrent.ContextSwitcher; import org.opensearch.common.util.concurrent.OpenSearchExecutors; import org.opensearch.core.common.io.stream.NamedWriteableRegistry; import org.opensearch.core.common.unit.ByteSizeUnit; @@ -201,7 +202,7 @@ private static int normalPoolCount(Settings settings) { @Override public Collection createComponents( - final PluginAwareNodeClient client, + final Client client, final ClusterService clusterService, final ThreadPool threadPool, final ResourceWatcherService resourceWatcherService, @@ -211,7 +212,8 @@ public Collection createComponents( final NodeEnvironment nodeEnvironment, final NamedWriteableRegistry namedWriteableRegistry, final IndexNameExpressionResolver expressionResolver, - final Supplier repositoriesServiceSupplier + final Supplier repositoriesServiceSupplier, + ContextSwitcher contextSwitcher ) { int urgentEventLoopThreads = urgentPoolCount(clusterService.getSettings()); int priorityEventLoopThreads = priorityPoolCount(clusterService.getSettings()); diff --git a/qa/logging-config/src/test/java/org/opensearch/common/logging/JsonLoggerTests.java b/qa/logging-config/src/test/java/org/opensearch/common/logging/JsonLoggerTests.java index 7fbfd6929ebdf..3a1d699aee863 100644 --- a/qa/logging-config/src/test/java/org/opensearch/common/logging/JsonLoggerTests.java +++ b/qa/logging-config/src/test/java/org/opensearch/common/logging/JsonLoggerTests.java @@ -408,11 +408,8 @@ protected List featureValueOf(JsonLogLine actual) { private void withThreadContext(CheckedConsumer consumer) throws Exception { final ThreadContext threadContext = new ThreadContext(Settings.EMPTY); - try (ThreadContext.StoredContext ignore = threadContext.stashContext()) { - HeaderWarning.setThreadContext(threadContext); - consumer.accept(threadContext); - } finally { - HeaderWarning.removeThreadContext(threadContext); - } + HeaderWarning.setThreadContext(threadContext); + consumer.accept(threadContext); + HeaderWarning.removeThreadContext(threadContext); } } diff --git a/qa/smoke-test-http/src/test/java/org/opensearch/http/TestExecutionContextPlugin.java b/qa/smoke-test-http/src/test/java/org/opensearch/http/TestExecutionContextPlugin.java index 093fb7e3e90a2..316e2104ed7f0 100644 --- a/qa/smoke-test-http/src/test/java/org/opensearch/http/TestExecutionContextPlugin.java +++ b/qa/smoke-test-http/src/test/java/org/opensearch/http/TestExecutionContextPlugin.java @@ -9,7 +9,6 @@ package org.opensearch.http; import org.opensearch.client.Client; -import org.opensearch.client.node.PluginAwareNodeClient; import org.opensearch.cluster.metadata.IndexNameExpressionResolver; import org.opensearch.cluster.node.DiscoveryNodes; import org.opensearch.cluster.service.ClusterService; @@ -27,6 +26,7 @@ import org.opensearch.rest.RestController; import org.opensearch.rest.RestHandler; import org.opensearch.script.ScriptService; +import org.opensearch.common.util.concurrent.ContextSwitcher; import org.opensearch.threadpool.ThreadPool; import org.opensearch.watcher.ResourceWatcherService; @@ -35,15 +35,14 @@ import java.util.List; import java.util.function.Supplier; -import static java.util.Collections.singletonList; - public class TestExecutionContextPlugin extends Plugin implements ActionPlugin { - private PluginAwareNodeClient client; + private ContextSwitcher contextSwitcher; + private ThreadPool threadPool; @Override public Collection createComponents( - PluginAwareNodeClient client, + Client client, ClusterService clusterService, ThreadPool threadPool, ResourceWatcherService resourceWatcherService, @@ -53,9 +52,11 @@ public Collection createComponents( NodeEnvironment nodeEnvironment, NamedWriteableRegistry namedWriteableRegistry, IndexNameExpressionResolver expressionResolver, - Supplier repositoriesServiceSupplier - ) { - this.client = client; + Supplier repositoriesServiceSupplier, + ContextSwitcher contextSwitcher) { + // TODO Fix this + this.contextSwitcher = null; + this.threadPool = threadPool; return Collections.emptyList(); } @@ -63,6 +64,6 @@ public Collection createComponents( public List getRestHandlers(Settings settings, RestController restController, ClusterSettings clusterSettings, IndexScopedSettings indexScopedSettings, SettingsFilter settingsFilter, IndexNameExpressionResolver indexNameExpressionResolver, Supplier nodesInCluster) { - return List.of(new TestGetExecutionContextRestAction(client)); + return List.of(new TestGetExecutionContextRestAction(contextSwitcher, threadPool)); } } diff --git a/qa/smoke-test-http/src/test/java/org/opensearch/http/TestGetExecutionContextRestAction.java b/qa/smoke-test-http/src/test/java/org/opensearch/http/TestGetExecutionContextRestAction.java index 203e440e0c87b..0fa3861226cdf 100644 --- a/qa/smoke-test-http/src/test/java/org/opensearch/http/TestGetExecutionContextRestAction.java +++ b/qa/smoke-test-http/src/test/java/org/opensearch/http/TestGetExecutionContextRestAction.java @@ -9,28 +9,28 @@ package org.opensearch.http; import org.opensearch.client.node.NodeClient; -import org.opensearch.client.node.PluginAwareNodeClient; import org.opensearch.common.util.concurrent.ThreadContext; import org.opensearch.core.rest.RestStatus; import org.opensearch.rest.BaseRestHandler; import org.opensearch.rest.BytesRestResponse; import org.opensearch.rest.RestRequest; import org.opensearch.rest.RestResponse; +import org.opensearch.common.util.concurrent.ContextSwitcher; import org.opensearch.threadpool.ThreadPool; import java.util.List; -import java.util.Stack; import static java.util.Collections.singletonList; import static org.opensearch.rest.RestRequest.Method.GET; -import static org.opensearch.rest.RestRequest.Method.POST; public class TestGetExecutionContextRestAction extends BaseRestHandler { - private final PluginAwareNodeClient pluginAwareClient; + private final ContextSwitcher contextSwitcher; + private final ThreadPool threadPool; - public TestGetExecutionContextRestAction(PluginAwareNodeClient pluginAwareClient) { - this.pluginAwareClient = pluginAwareClient; + public TestGetExecutionContextRestAction(ContextSwitcher contextSwitcher, ThreadPool threadPool) { + this.contextSwitcher = contextSwitcher; + this.threadPool = threadPool; } @Override @@ -46,8 +46,8 @@ public String getName() { @Override public RestChannelConsumer prepareRequest(RestRequest request, NodeClient client) { String stashedContext; - try (ThreadContext.StoredContext storedContext = pluginAwareClient.switchContext()) { - stashedContext = pluginAwareClient.threadPool().getThreadContext().getHeader(ThreadContext.PLUGIN_EXECUTION_CONTEXT); + try (ThreadContext.StoredContext storedContext = contextSwitcher.switchContext()) { + stashedContext = threadPool.getThreadContext().getHeader(ThreadContext.PLUGIN_EXECUTION_CONTEXT); } RestResponse response = new BytesRestResponse(RestStatus.OK, stashedContext); return channel -> channel.sendResponse(response); diff --git a/server/src/internalClusterTest/java/org/opensearch/action/ingest/AsyncIngestProcessorIT.java b/server/src/internalClusterTest/java/org/opensearch/action/ingest/AsyncIngestProcessorIT.java index d124f2d8ab459..773d660adeeb3 100644 --- a/server/src/internalClusterTest/java/org/opensearch/action/ingest/AsyncIngestProcessorIT.java +++ b/server/src/internalClusterTest/java/org/opensearch/action/ingest/AsyncIngestProcessorIT.java @@ -36,9 +36,10 @@ import org.opensearch.action.get.GetRequest; import org.opensearch.action.get.GetResponse; import org.opensearch.action.index.IndexRequest; -import org.opensearch.client.node.PluginAwareNodeClient; +import org.opensearch.client.Client; import org.opensearch.cluster.metadata.IndexNameExpressionResolver; import org.opensearch.cluster.service.ClusterService; +import org.opensearch.common.util.concurrent.ContextSwitcher; import org.opensearch.core.common.bytes.BytesArray; import org.opensearch.core.common.bytes.BytesReference; import org.opensearch.core.common.io.stream.NamedWriteableRegistry; @@ -110,7 +111,7 @@ public static class TestPlugin extends Plugin implements IngestPlugin { @Override public Collection createComponents( - PluginAwareNodeClient client, + Client client, ClusterService clusterService, ThreadPool threadPool, ResourceWatcherService resourceWatcherService, @@ -120,7 +121,8 @@ public Collection createComponents( NodeEnvironment nodeEnvironment, NamedWriteableRegistry namedWriteableRegistry, IndexNameExpressionResolver expressionResolver, - Supplier repositoriesServiceSupplier + Supplier repositoriesServiceSupplier, + ContextSwitcher contextSwitcher ) { this.threadPool = threadPool; return Collections.emptyList(); diff --git a/server/src/internalClusterTest/java/org/opensearch/cluster/SimpleClusterStateIT.java b/server/src/internalClusterTest/java/org/opensearch/cluster/SimpleClusterStateIT.java index a07a82c9b1f45..1a5898f58d871 100644 --- a/server/src/internalClusterTest/java/org/opensearch/cluster/SimpleClusterStateIT.java +++ b/server/src/internalClusterTest/java/org/opensearch/cluster/SimpleClusterStateIT.java @@ -38,7 +38,6 @@ import org.opensearch.action.support.IndicesOptions; import org.opensearch.client.Client; import org.opensearch.client.Requests; -import org.opensearch.client.node.PluginAwareNodeClient; import org.opensearch.cluster.metadata.IndexMetadata; import org.opensearch.cluster.metadata.IndexNameExpressionResolver; import org.opensearch.cluster.metadata.MappingMetadata; @@ -48,6 +47,7 @@ import org.opensearch.common.Priority; import org.opensearch.common.UUIDs; import org.opensearch.common.settings.Settings; +import org.opensearch.common.util.concurrent.ContextSwitcher; import org.opensearch.common.xcontent.XContentFactory; import org.opensearch.core.common.Strings; import org.opensearch.core.common.io.stream.NamedWriteableRegistry; @@ -460,7 +460,7 @@ public List getNamedWriteables() { @Override public Collection createComponents( - final PluginAwareNodeClient client, + final Client client, final ClusterService clusterService, final ThreadPool threadPool, final ResourceWatcherService resourceWatcherService, @@ -470,7 +470,8 @@ public Collection createComponents( final NodeEnvironment nodeEnvironment, final NamedWriteableRegistry namedWriteableRegistry, final IndexNameExpressionResolver expressionResolver, - final Supplier repositoriesServiceSupplier + final Supplier repositoriesServiceSupplier, + ContextSwitcher contextSwitcher ) { clusterService.addListener(event -> { final ClusterState state = event.state(); diff --git a/server/src/internalClusterTest/java/org/opensearch/cluster/metadata/TemplateUpgradeServiceIT.java b/server/src/internalClusterTest/java/org/opensearch/cluster/metadata/TemplateUpgradeServiceIT.java index 9dc80210d6b7b..0e051b82c5685 100644 --- a/server/src/internalClusterTest/java/org/opensearch/cluster/metadata/TemplateUpgradeServiceIT.java +++ b/server/src/internalClusterTest/java/org/opensearch/cluster/metadata/TemplateUpgradeServiceIT.java @@ -34,10 +34,11 @@ import org.apache.logging.log4j.LogManager; import org.apache.logging.log4j.Logger; -import org.opensearch.client.node.PluginAwareNodeClient; +import org.opensearch.client.Client; import org.opensearch.cluster.service.ClusterService; import org.opensearch.common.settings.Setting; import org.opensearch.common.settings.Settings; +import org.opensearch.common.util.concurrent.ContextSwitcher; import org.opensearch.core.common.io.stream.NamedWriteableRegistry; import org.opensearch.core.xcontent.NamedXContentRegistry; import org.opensearch.env.Environment; @@ -87,7 +88,7 @@ public TestPlugin(Settings settings) { @Override public Collection createComponents( - PluginAwareNodeClient client, + Client client, ClusterService clusterService, ThreadPool threadPool, ResourceWatcherService resourceWatcherService, @@ -97,7 +98,8 @@ public Collection createComponents( NodeEnvironment nodeEnvironment, NamedWriteableRegistry namedWriteableRegistry, IndexNameExpressionResolver expressionResolver, - Supplier repositoriesServiceSupplier + Supplier repositoriesServiceSupplier, + ContextSwitcher contextSwitcher ) { clusterService.getClusterSettings().addSettingsUpdateConsumer(UPDATE_TEMPLATE_DUMMY_SETTING, integer -> { logger.debug("the template dummy setting was updated to {}", integer); @@ -113,7 +115,8 @@ public Collection createComponents( nodeEnvironment, namedWriteableRegistry, expressionResolver, - repositoriesServiceSupplier + repositoriesServiceSupplier, + contextSwitcher ); } diff --git a/server/src/internalClusterTest/java/org/opensearch/index/FinalPipelineIT.java b/server/src/internalClusterTest/java/org/opensearch/index/FinalPipelineIT.java index d5eef4209376f..cff2992653f1c 100644 --- a/server/src/internalClusterTest/java/org/opensearch/index/FinalPipelineIT.java +++ b/server/src/internalClusterTest/java/org/opensearch/index/FinalPipelineIT.java @@ -42,10 +42,11 @@ import org.opensearch.action.ingest.PutPipelineRequest; import org.opensearch.action.search.SearchResponse; import org.opensearch.action.support.WriteRequest; -import org.opensearch.client.node.PluginAwareNodeClient; +import org.opensearch.client.Client; import org.opensearch.cluster.metadata.IndexNameExpressionResolver; import org.opensearch.cluster.service.ClusterService; import org.opensearch.common.settings.Settings; +import org.opensearch.common.util.concurrent.ContextSwitcher; import org.opensearch.core.common.bytes.BytesArray; import org.opensearch.core.common.bytes.BytesReference; import org.opensearch.core.common.io.stream.NamedWriteableRegistry; @@ -363,7 +364,7 @@ public static class TestPlugin extends Plugin implements IngestPlugin { @Override public Collection createComponents( - final PluginAwareNodeClient client, + final Client client, final ClusterService clusterService, final ThreadPool threadPool, final ResourceWatcherService resourceWatcherService, @@ -373,7 +374,8 @@ public Collection createComponents( final NodeEnvironment nodeEnvironment, final NamedWriteableRegistry namedWriteableRegistry, final IndexNameExpressionResolver expressionResolver, - final Supplier repositoriesServiceSupplier + final Supplier repositoriesServiceSupplier, + ContextSwitcher contextSwitcher ) { return Collections.emptyList(); } diff --git a/server/src/main/java/org/opensearch/action/SystemIndexFilter.java b/server/src/main/java/org/opensearch/action/SystemIndexFilter.java new file mode 100644 index 0000000000000..e5f800e162293 --- /dev/null +++ b/server/src/main/java/org/opensearch/action/SystemIndexFilter.java @@ -0,0 +1,66 @@ +/* + * SPDX-License-Identifier: Apache-2.0 + * + * The OpenSearch Contributors require contributions made to + * this file be licensed under the Apache-2.0 license or a + * compatible open source license. + */ + +package org.opensearch.action; + +import org.opensearch.action.support.ActionFilter; +import org.opensearch.action.support.ActionFilterChain; +import org.opensearch.cluster.metadata.IndexNameExpressionResolver; +import org.opensearch.common.util.concurrent.ThreadContext; +import org.opensearch.core.action.ActionListener; +import org.opensearch.core.action.ActionResponse; +import org.opensearch.tasks.Task; + +/** + * Action filter that limits system index interaction for plugins + * + * Plugins are passed a PluginAwareNodeClient that allows a plugin to switch context and securely + * interact with system indices it registers through SystemIndexPlugin.getSystemIndexDescriptors + */ +public class SystemIndexFilter implements ActionFilter { + + private final ThreadContext threadContext; + private final IndexNameExpressionResolver resolver; + + public SystemIndexFilter(ThreadContext threadContext, IndexNameExpressionResolver resolver) { + this.threadContext = threadContext; + this.resolver = resolver; + } + + @Override + public int order() { + return Integer.MIN_VALUE + 100; + } + + @Override + public void apply( + Task task, + String action, + Request request, + ActionListener listener, + ActionFilterChain chain + ) { + // String pluginExecutionContext = threadContext.getHeader(ThreadContext.PLUGIN_EXECUTION_CONTEXT); + // if (pluginExecutionContext != null) { + // IndexResolverReplacer.Resolved requestedResolved = indexResolverReplacer.resolveRequest(request); + // if (!requestedResolved.getAllIndices().isEmpty()) { + // Set matchingSystemIndices = SystemIndexRegistry.matchesPluginSystemIndexPattern( + // pluginExecutionContext, + // requestedResolved.getAllIndices() + // ); + // if (!matchingSystemIndices.equals(requestedResolved.getAllIndices())) { + // String err = "Plugin " + pluginExecutionContext + " can only interact with its own system indices"; + // listener.onFailure(new OpenSearchSecurityException(err, RestStatus.FORBIDDEN)); + // return; + // } + // } + // } + // TODO Figure out how to resolve Request -> Indices + chain.proceed(task, action, request, listener); + } +} diff --git a/server/src/main/java/org/opensearch/client/node/PluginAwareNodeClient.java b/server/src/main/java/org/opensearch/client/node/PluginAwareNodeClient.java deleted file mode 100644 index deb1021e5ea81..0000000000000 --- a/server/src/main/java/org/opensearch/client/node/PluginAwareNodeClient.java +++ /dev/null @@ -1,60 +0,0 @@ -/* - * SPDX-License-Identifier: Apache-2.0 - * - * The OpenSearch Contributors require contributions made to - * this file be licensed under the Apache-2.0 license or a - * compatible open source license. - */ - -/* - * Licensed to Elasticsearch under one or more contributor - * license agreements. See the NOTICE file distributed with - * this work for additional information regarding copyright - * ownership. Elasticsearch licenses this file to you under - * the Apache License, Version 2.0 (the "License"); you may - * not use this file except in compliance with the License. - * You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, - * software distributed under the License is distributed on an - * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY - * KIND, either express or implied. See the License for the - * specific language governing permissions and limitations - * under the License. - */ - -/* - * Modifications Copyright OpenSearch Contributors. See - * GitHub history for details. - */ - -package org.opensearch.client.node; - -import org.opensearch.common.annotation.PublicApi; -import org.opensearch.common.settings.Settings; -import org.opensearch.common.util.concurrent.PluginAwareThreadContextWrapper; -import org.opensearch.common.util.concurrent.ThreadContext; -import org.opensearch.plugins.Plugin; -import org.opensearch.threadpool.ThreadPool; - -/** - * Client that executes actions on the local node. This NodeClient is passed to a plugin in createComponents. - * - * @opensearch.api - */ -@PublicApi(since = "2.16.0") -public class PluginAwareNodeClient extends NodeClient { - - private PluginAwareThreadContextWrapper wrapper; - - public PluginAwareNodeClient(Settings settings, ThreadPool threadPool, Plugin plugin) { - super(settings, threadPool); - this.wrapper = new PluginAwareThreadContextWrapper(threadPool.getThreadContext(), plugin); - } - - public ThreadContext.StoredContext switchContext() { - return wrapper.stashContext(); - } -} diff --git a/server/src/main/java/org/opensearch/cluster/service/ClusterApplierService.java b/server/src/main/java/org/opensearch/cluster/service/ClusterApplierService.java index 6234427445754..4ef014bd08621 100644 --- a/server/src/main/java/org/opensearch/cluster/service/ClusterApplierService.java +++ b/server/src/main/java/org/opensearch/cluster/service/ClusterApplierService.java @@ -58,6 +58,7 @@ import org.opensearch.common.settings.Setting; import org.opensearch.common.settings.Settings; import org.opensearch.common.unit.TimeValue; +import org.opensearch.common.util.concurrent.InternalContextSwitcher; import org.opensearch.common.util.concurrent.OpenSearchExecutors; import org.opensearch.common.util.concurrent.PrioritizedOpenSearchThreadPoolExecutor; import org.opensearch.common.util.concurrent.ThreadContext; @@ -104,6 +105,7 @@ public class ClusterApplierService extends AbstractLifecycleComponent implements private final ClusterSettings clusterSettings; protected final ThreadPool threadPool; + protected final InternalContextSwitcher contextSwitcher; private volatile TimeValue slowTaskLoggingThreshold; @@ -139,6 +141,7 @@ public ClusterApplierService( ) { this.clusterSettings = clusterSettings; this.threadPool = threadPool; + this.contextSwitcher = new InternalContextSwitcher(threadPool); this.state = new AtomicReference<>(); this.nodeName = nodeName; @@ -395,7 +398,7 @@ private void submitStateUpdateTask( } final ThreadContext threadContext = threadPool.getThreadContext(); final Supplier supplier = threadContext.newRestorableContext(true); - try (ThreadContext.StoredContext ignore = threadContext.stashContext()) { + try (ThreadContext.StoredContext ignore = contextSwitcher.switchContext()) { threadContext.markAsSystemContext(); final UpdateTask updateTask = new UpdateTask( config.priority(), diff --git a/server/src/main/java/org/opensearch/cluster/service/MasterService.java b/server/src/main/java/org/opensearch/cluster/service/MasterService.java index 686e9793a8fd3..c515c3b13494a 100644 --- a/server/src/main/java/org/opensearch/cluster/service/MasterService.java +++ b/server/src/main/java/org/opensearch/cluster/service/MasterService.java @@ -63,6 +63,7 @@ import org.opensearch.common.unit.TimeValue; import org.opensearch.common.util.concurrent.CountDown; import org.opensearch.common.util.concurrent.FutureUtils; +import org.opensearch.common.util.concurrent.InternalContextSwitcher; import org.opensearch.common.util.concurrent.OpenSearchExecutors; import org.opensearch.common.util.concurrent.PrioritizedOpenSearchThreadPoolExecutor; import org.opensearch.common.util.concurrent.ThreadContext; @@ -133,6 +134,7 @@ public class MasterService extends AbstractLifecycleComponent { private volatile TimeValue slowTaskLoggingThreshold; protected final ThreadPool threadPool; + protected final InternalContextSwitcher contextSwitcher; private volatile PrioritizedOpenSearchThreadPoolExecutor threadPoolExecutor; private volatile Batcher taskBatcher; @@ -168,6 +170,7 @@ public MasterService( ); this.stateStats = new ClusterStateStats(); this.threadPool = threadPool; + this.contextSwitcher = new InternalContextSwitcher(threadPool); this.clusterManagerMetrics = clusterManagerMetrics; } @@ -1008,7 +1011,7 @@ public void submitStateUpdateTasks( } final ThreadContext threadContext = threadPool.getThreadContext(); final Supplier supplier = threadContext.newRestorableContext(true); - try (ThreadContext.StoredContext ignore = threadContext.stashContext()) { + try (ThreadContext.StoredContext ignore = contextSwitcher.switchContext()) { threadContext.markAsSystemContext(); List safeTasks = tasks.entrySet() diff --git a/server/src/main/java/org/opensearch/common/util/concurrent/ContextSwitcher.java b/server/src/main/java/org/opensearch/common/util/concurrent/ContextSwitcher.java new file mode 100644 index 0000000000000..efa92dceb2124 --- /dev/null +++ b/server/src/main/java/org/opensearch/common/util/concurrent/ContextSwitcher.java @@ -0,0 +1,35 @@ +/* + * SPDX-License-Identifier: Apache-2.0 + * + * The OpenSearch Contributors require contributions made to + * this file be licensed under the Apache-2.0 license or a + * compatible open source license. + */ + +package org.opensearch.common.util.concurrent; + +import org.opensearch.common.annotation.PublicApi; +import org.opensearch.plugins.Plugin; +import org.opensearch.threadpool.ThreadPool; + +/** + * ContextSwitcher that is passed to plugins in order to switch to a fresh context + * from any existing context + * + * @opensearch.api + */ +@PublicApi(since = "2.17.0") +public class ContextSwitcher { + + private final ThreadPool threadPool; + private final Plugin plugin; + + public ContextSwitcher(ThreadPool threadPool, Plugin plugin) { + this.threadPool = threadPool; + this.plugin = plugin; + } + + public ThreadContext.StoredContext switchContext() { + return threadPool.getThreadContext().stashContext(plugin.getClass()); + } +} diff --git a/server/src/main/java/org/opensearch/common/util/concurrent/InternalContextSwitcher.java b/server/src/main/java/org/opensearch/common/util/concurrent/InternalContextSwitcher.java new file mode 100644 index 0000000000000..47aeda6fc0f3c --- /dev/null +++ b/server/src/main/java/org/opensearch/common/util/concurrent/InternalContextSwitcher.java @@ -0,0 +1,31 @@ +/* + * SPDX-License-Identifier: Apache-2.0 + * + * The OpenSearch Contributors require contributions made to + * this file be licensed under the Apache-2.0 license or a + * compatible open source license. + */ + +package org.opensearch.common.util.concurrent; + +import org.opensearch.common.annotation.InternalApi; +import org.opensearch.threadpool.ThreadPool; + +/** + * InternalContextSwitcher is an internal class used to switch into a fresh + * internal system context + * + * @opensearch.internal + */ +@InternalApi +public class InternalContextSwitcher { + private final ThreadPool threadPool; + + public InternalContextSwitcher(ThreadPool threadPool) { + this.threadPool = threadPool; + } + + public ThreadContext.StoredContext switchContext() { + return threadPool.getThreadContext().stashContext(); + } +} diff --git a/server/src/main/java/org/opensearch/common/util/concurrent/PluginAwareThreadContextWrapper.java b/server/src/main/java/org/opensearch/common/util/concurrent/PluginAwareThreadContextWrapper.java deleted file mode 100644 index d66b05868c692..0000000000000 --- a/server/src/main/java/org/opensearch/common/util/concurrent/PluginAwareThreadContextWrapper.java +++ /dev/null @@ -1,30 +0,0 @@ -/* - * SPDX-License-Identifier: Apache-2.0 - * - * The OpenSearch Contributors require contributions made to - * this file be licensed under the Apache-2.0 license or a - * compatible open source license. - */ - -package org.opensearch.common.util.concurrent; - -import org.opensearch.plugins.Plugin; - -/** - * Wrapper class around the ThreadContext that is used within {@link org.opensearch.client.node.PluginAwareNodeClient} - * to enable retaining information about the plugin when switching out an authenticated user context - */ -public class PluginAwareThreadContextWrapper { - - private final ThreadContext threadContext; - private final Plugin plugin; - - public PluginAwareThreadContextWrapper(ThreadContext threadContext, Plugin plugin) { - this.threadContext = threadContext; - this.plugin = plugin; - } - - public ThreadContext.StoredContext stashContext() { - return threadContext.stashContext(plugin.getClass()); - } -} diff --git a/server/src/main/java/org/opensearch/common/util/concurrent/ThreadContext.java b/server/src/main/java/org/opensearch/common/util/concurrent/ThreadContext.java index 9c011b2570731..446459e7d62e8 100644 --- a/server/src/main/java/org/opensearch/common/util/concurrent/ThreadContext.java +++ b/server/src/main/java/org/opensearch/common/util/concurrent/ThreadContext.java @@ -145,7 +145,7 @@ public void unregisterThreadContextStatePropagator(final ThreadContextStatePropa * Removes the current context and resets a default context. The removed context can be * restored by closing the returned {@link StoredContext}. */ - public StoredContext stashContext() { + StoredContext stashContext() { final ThreadContextStruct context = threadLocal.get(); /* X-Opaque-ID should be preserved in a threadContext in order to propagate this across threads. @@ -182,7 +182,7 @@ public StoredContext stashContext() { * Removes the current context and resets a default context. Retains information about plugin stashing the context. * The removed context can be restored by closing the returned {@link StoredContext}. */ - StoredContext stashContext(Class pluginClass) { + public StoredContext stashContext(Class pluginClass) { final ThreadContextStruct context = threadLocal.get(); /* X-Opaque-ID should be preserved in a threadContext in order to propagate this across threads. diff --git a/server/src/main/java/org/opensearch/http/AbstractHttpServerTransport.java b/server/src/main/java/org/opensearch/http/AbstractHttpServerTransport.java index 991fbf12072be..c9386ad9c491b 100644 --- a/server/src/main/java/org/opensearch/http/AbstractHttpServerTransport.java +++ b/server/src/main/java/org/opensearch/http/AbstractHttpServerTransport.java @@ -45,6 +45,7 @@ import org.opensearch.common.transport.NetworkExceptionHelper; import org.opensearch.common.transport.PortsRange; import org.opensearch.common.util.BigArrays; +import org.opensearch.common.util.concurrent.InternalContextSwitcher; import org.opensearch.common.util.concurrent.ThreadContext; import org.opensearch.core.action.ActionListener; import org.opensearch.core.common.Strings; @@ -99,6 +100,7 @@ public abstract class AbstractHttpServerTransport extends AbstractLifecycleCompo protected final NetworkService networkService; protected final BigArrays bigArrays; protected final ThreadPool threadPool; + protected final InternalContextSwitcher contextSwitcher; protected final Dispatcher dispatcher; protected final CorsHandler corsHandler; private final NamedXContentRegistry xContentRegistry; @@ -130,6 +132,7 @@ protected AbstractHttpServerTransport( this.networkService = networkService; this.bigArrays = bigArrays; this.threadPool = threadPool; + this.contextSwitcher = new InternalContextSwitcher(threadPool); this.xContentRegistry = xContentRegistry; this.dispatcher = dispatcher; this.handlingSettings = HttpHandlingSettings.fromSettings(settings); @@ -385,7 +388,7 @@ public void incomingRequest(final HttpRequest httpRequest, final HttpChannel htt void dispatchRequest(final RestRequest restRequest, final RestChannel channel, final Throwable badRequestCause) { RestChannel traceableRestChannel = channel; final ThreadContext threadContext = threadPool.getThreadContext(); - try (ThreadContext.StoredContext ignore = threadContext.stashContext()) { + try (ThreadContext.StoredContext ignore = contextSwitcher.switchContext()) { final Span span = tracer.startSpan(SpanBuilder.from(restRequest)); try (final SpanScope spanScope = tracer.withSpanInScope(span)) { if (channel != null) { diff --git a/server/src/main/java/org/opensearch/index/seqno/GlobalCheckpointSyncAction.java b/server/src/main/java/org/opensearch/index/seqno/GlobalCheckpointSyncAction.java index c6a1f5f27a875..eaf6d7c85220d 100644 --- a/server/src/main/java/org/opensearch/index/seqno/GlobalCheckpointSyncAction.java +++ b/server/src/main/java/org/opensearch/index/seqno/GlobalCheckpointSyncAction.java @@ -43,6 +43,7 @@ import org.opensearch.cluster.service.ClusterService; import org.opensearch.common.inject.Inject; import org.opensearch.common.settings.Settings; +import org.opensearch.common.util.concurrent.InternalContextSwitcher; import org.opensearch.common.util.concurrent.ThreadContext; import org.opensearch.core.action.ActionListener; import org.opensearch.core.common.io.stream.StreamInput; @@ -69,6 +70,7 @@ public class GlobalCheckpointSyncAction extends TransportReplicationAction< ReplicationResponse> { public static String ACTION_NAME = "indices:admin/seq_no/global_checkpoint_sync"; + private final InternalContextSwitcher contextSwitcher; @Inject public GlobalCheckpointSyncAction( @@ -93,11 +95,12 @@ public GlobalCheckpointSyncAction( Request::new, ThreadPool.Names.MANAGEMENT ); + this.contextSwitcher = new InternalContextSwitcher(threadPool); } public void updateGlobalCheckpointForShard(final ShardId shardId) { final ThreadContext threadContext = threadPool.getThreadContext(); - try (ThreadContext.StoredContext ignore = threadContext.stashContext()) { + try (ThreadContext.StoredContext ignore = contextSwitcher.switchContext()) { threadContext.markAsSystemContext(); execute(new Request(shardId), ActionListener.wrap(r -> {}, e -> { if (ExceptionsHelper.unwrap(e, AlreadyClosedException.class, IndexShardClosedException.class) == null) { diff --git a/server/src/main/java/org/opensearch/index/seqno/RetentionLeaseBackgroundSyncAction.java b/server/src/main/java/org/opensearch/index/seqno/RetentionLeaseBackgroundSyncAction.java index 5fa0a1a6459e7..7506740fe84bf 100644 --- a/server/src/main/java/org/opensearch/index/seqno/RetentionLeaseBackgroundSyncAction.java +++ b/server/src/main/java/org/opensearch/index/seqno/RetentionLeaseBackgroundSyncAction.java @@ -47,6 +47,7 @@ import org.opensearch.cluster.service.ClusterService; import org.opensearch.common.inject.Inject; import org.opensearch.common.settings.Settings; +import org.opensearch.common.util.concurrent.InternalContextSwitcher; import org.opensearch.common.util.concurrent.ThreadContext; import org.opensearch.core.action.ActionListener; import org.opensearch.core.common.io.stream.StreamInput; @@ -84,6 +85,8 @@ public class RetentionLeaseBackgroundSyncAction extends TransportReplicationActi public static final String ACTION_NAME = "indices:admin/seq_no/retention_lease_background_sync"; private static final Logger LOGGER = LogManager.getLogger(RetentionLeaseSyncAction.class); + private final InternalContextSwitcher contextSwitcher; + protected Logger getLogger() { return LOGGER; } @@ -111,6 +114,7 @@ public RetentionLeaseBackgroundSyncAction( Request::new, ThreadPool.Names.MANAGEMENT ); + this.contextSwitcher = new InternalContextSwitcher(threadPool); } @Override @@ -120,7 +124,7 @@ protected void doExecute(Task task, Request request, ActionListener listener ) { final ThreadContext threadContext = threadPool.getThreadContext(); - try (ThreadContext.StoredContext ignore = threadContext.stashContext()) { + try (ThreadContext.StoredContext ignore = contextSwitcher.switchContext()) { // we have to execute under the system context so that if security is enabled the sync is authorized threadContext.markAsSystemContext(); final Request request = new Request(shardId, retentionLeases); diff --git a/server/src/main/java/org/opensearch/index/shard/IndexShard.java b/server/src/main/java/org/opensearch/index/shard/IndexShard.java index 82b68b32f3bf8..10a5e34bf23f2 100644 --- a/server/src/main/java/org/opensearch/index/shard/IndexShard.java +++ b/server/src/main/java/org/opensearch/index/shard/IndexShard.java @@ -4566,7 +4566,7 @@ private RefreshListeners buildRefreshListeners() { indexSettings::getMaxRefreshListeners, () -> refresh("too_many_listeners"), logger, - threadPool.getThreadContext(), + threadPool, externalRefreshMetric ); } diff --git a/server/src/main/java/org/opensearch/index/shard/RefreshListeners.java b/server/src/main/java/org/opensearch/index/shard/RefreshListeners.java index 803db773efe6c..9d99c749832aa 100644 --- a/server/src/main/java/org/opensearch/index/shard/RefreshListeners.java +++ b/server/src/main/java/org/opensearch/index/shard/RefreshListeners.java @@ -37,9 +37,11 @@ import org.opensearch.common.collect.Tuple; import org.opensearch.common.lease.Releasable; import org.opensearch.common.metrics.MeanMetric; +import org.opensearch.common.util.concurrent.InternalContextSwitcher; import org.opensearch.common.util.concurrent.RunOnce; import org.opensearch.common.util.concurrent.ThreadContext; import org.opensearch.index.translog.Translog; +import org.opensearch.threadpool.ThreadPool; import java.io.Closeable; import java.io.IOException; @@ -63,7 +65,8 @@ public final class RefreshListeners implements ReferenceManager.RefreshListener, private final IntSupplier getMaxRefreshListeners; private final Runnable forceRefresh; private final Logger logger; - private final ThreadContext threadContext; + private final ThreadPool threadPool; + private final InternalContextSwitcher contextSwitcher; private final MeanMetric refreshMetric; /** @@ -99,13 +102,14 @@ public RefreshListeners( final IntSupplier getMaxRefreshListeners, final Runnable forceRefresh, final Logger logger, - final ThreadContext threadContext, + final ThreadPool threadPool, final MeanMetric refreshMetric ) { this.getMaxRefreshListeners = getMaxRefreshListeners; this.forceRefresh = forceRefresh; this.logger = logger; - this.threadContext = threadContext; + this.threadPool = threadPool; + this.contextSwitcher = new InternalContextSwitcher(threadPool); this.refreshMetric = refreshMetric; } @@ -160,9 +164,9 @@ public boolean addOrNotify(Translog.Location location, Consumer listene List>> listeners = refreshListeners; final int maxRefreshes = getMaxRefreshListeners.getAsInt(); if (refreshForcers == 0 && maxRefreshes > 0 && (listeners == null || listeners.size() < maxRefreshes)) { - ThreadContext.StoredContext storedContext = threadContext.newStoredContext(true); + ThreadContext.StoredContext storedContext = threadPool.getThreadContext().newStoredContext(true); Consumer contextPreservingListener = forced -> { - try (ThreadContext.StoredContext ignore = threadContext.stashContext()) { + try (ThreadContext.StoredContext ignore = contextSwitcher.switchContext()) { storedContext.restore(); listener.accept(forced); } diff --git a/server/src/main/java/org/opensearch/indices/replication/checkpoint/PublishCheckpointAction.java b/server/src/main/java/org/opensearch/indices/replication/checkpoint/PublishCheckpointAction.java index 8f39aa194b06c..551fcf2b18b87 100644 --- a/server/src/main/java/org/opensearch/indices/replication/checkpoint/PublishCheckpointAction.java +++ b/server/src/main/java/org/opensearch/indices/replication/checkpoint/PublishCheckpointAction.java @@ -23,6 +23,7 @@ import org.opensearch.common.annotation.PublicApi; import org.opensearch.common.inject.Inject; import org.opensearch.common.settings.Settings; +import org.opensearch.common.util.concurrent.InternalContextSwitcher; import org.opensearch.common.util.concurrent.ThreadContext; import org.opensearch.core.action.ActionListener; import org.opensearch.core.common.io.stream.StreamInput; @@ -58,6 +59,7 @@ public class PublishCheckpointAction extends TransportReplicationAction< protected static Logger logger = LogManager.getLogger(PublishCheckpointAction.class); private final SegmentReplicationTargetService replicationService; + private final InternalContextSwitcher contextSwitcher; @Inject public PublishCheckpointAction( @@ -84,6 +86,7 @@ public PublishCheckpointAction( ThreadPool.Names.REFRESH ); this.replicationService = targetService; + this.contextSwitcher = new InternalContextSwitcher(threadPool); } @Override @@ -111,7 +114,7 @@ final void publish(IndexShard indexShard, ReplicationCheckpoint checkpoint) { String primaryAllocationId = indexShard.routingEntry().allocationId().getId(); long primaryTerm = indexShard.getPendingPrimaryTerm(); final ThreadContext threadContext = threadPool.getThreadContext(); - try (ThreadContext.StoredContext ignore = threadContext.stashContext()) { + try (ThreadContext.StoredContext ignore = contextSwitcher.switchContext()) { // we have to execute under the system context so that if security is enabled the sync is authorized threadContext.markAsSystemContext(); PublishCheckpointRequest request = new PublishCheckpointRequest(checkpoint); diff --git a/server/src/main/java/org/opensearch/node/Node.java b/server/src/main/java/org/opensearch/node/Node.java index 063d3741812c3..9b04d7d16bec7 100644 --- a/server/src/main/java/org/opensearch/node/Node.java +++ b/server/src/main/java/org/opensearch/node/Node.java @@ -59,7 +59,6 @@ import org.opensearch.bootstrap.BootstrapContext; import org.opensearch.client.Client; import org.opensearch.client.node.NodeClient; -import org.opensearch.client.node.PluginAwareNodeClient; import org.opensearch.cluster.ClusterInfoService; import org.opensearch.cluster.ClusterManagerMetrics; import org.opensearch.cluster.ClusterModule; @@ -115,6 +114,7 @@ import org.opensearch.common.util.BigArrays; import org.opensearch.common.util.FeatureFlags; import org.opensearch.common.util.PageCacheRecycler; +import org.opensearch.common.util.concurrent.ContextSwitcher; import org.opensearch.common.util.io.IOUtils; import org.opensearch.core.Assertions; import org.opensearch.core.common.breaker.CircuitBreaker; @@ -931,12 +931,10 @@ protected Node( final ViewService viewService = new ViewService(clusterService, client, null); - List pluginNodeClients = new ArrayList<>(); Collection pluginComponents = pluginsService.filterPlugins(Plugin.class).stream().flatMap(p -> { - PluginAwareNodeClient pluginClient = new PluginAwareNodeClient(settings, threadPool, p); - pluginNodeClients.add(pluginClient); + ContextSwitcher contextSwitcher = new ContextSwitcher(threadPool, p); return p.createComponents( - pluginClient, + client, clusterService, threadPool, resourceWatcherService, @@ -946,17 +944,17 @@ protected Node( nodeEnvironment, namedWriteableRegistry, clusterModule.getIndexNameExpressionResolver(), - repositoriesServiceReference::get + repositoriesServiceReference::get, + contextSwitcher ).stream(); }).collect(Collectors.toList()); Collection telemetryAwarePluginComponents = pluginsService.filterPlugins(TelemetryAwarePlugin.class) .stream() .flatMap(p -> { - PluginAwareNodeClient pluginClient = new PluginAwareNodeClient(settings, threadPool, (Plugin) p); - pluginNodeClients.add(pluginClient); + ContextSwitcher contextSwitcher = new ContextSwitcher(threadPool, (Plugin) p); return p.createComponents( - pluginClient, + client, clusterService, threadPool, resourceWatcherService, @@ -968,7 +966,8 @@ protected Node( clusterModule.getIndexNameExpressionResolver(), repositoriesServiceReference::get, tracer, - metricsRegistry + metricsRegistry, + contextSwitcher ).stream(); }) .collect(Collectors.toList()); @@ -1432,14 +1431,6 @@ protected Node( transportService.getRemoteClusterService(), namedWriteableRegistry ); - for (PluginAwareNodeClient pluginClient : pluginNodeClients) { - pluginClient.initialize( - dynamicActionRegistry, - () -> clusterService.localNode().getId(), - transportService.getRemoteClusterService(), - namedWriteableRegistry - ); - } this.namedWriteableRegistry = namedWriteableRegistry; logger.debug("initializing HTTP handlers ..."); diff --git a/server/src/main/java/org/opensearch/plugins/Plugin.java b/server/src/main/java/org/opensearch/plugins/Plugin.java index 15427fb1051c1..acf1e386732af 100644 --- a/server/src/main/java/org/opensearch/plugins/Plugin.java +++ b/server/src/main/java/org/opensearch/plugins/Plugin.java @@ -33,7 +33,7 @@ package org.opensearch.plugins; import org.opensearch.bootstrap.BootstrapCheck; -import org.opensearch.client.node.PluginAwareNodeClient; +import org.opensearch.client.Client; import org.opensearch.cluster.ClusterState; import org.opensearch.cluster.metadata.IndexNameExpressionResolver; import org.opensearch.cluster.metadata.IndexTemplateMetadata; @@ -46,6 +46,7 @@ import org.opensearch.common.settings.Setting; import org.opensearch.common.settings.SettingUpgrader; import org.opensearch.common.settings.Settings; +import org.opensearch.common.util.concurrent.ContextSwitcher; import org.opensearch.core.common.io.stream.NamedWriteable; import org.opensearch.core.common.io.stream.NamedWriteableRegistry; import org.opensearch.core.xcontent.NamedXContentRegistry; @@ -126,21 +127,22 @@ public Collection> getGuiceServiceClasses() * Note: To aid in the migration away from guice, all objects returned as components will be bound in guice * to themselves. * - * @param client A client to make requests to the system - * @param clusterService A service to allow watching and updating cluster state - * @param threadPool A service to allow retrieving an executor to run an async action - * @param resourceWatcherService A service to watch for changes to node local files - * @param scriptService A service to allow running scripts on the local node - * @param xContentRegistry the registry for extensible xContent parsing - * @param environment the environment for path and setting configurations - * @param nodeEnvironment the node environment used coordinate access to the data paths - * @param namedWriteableRegistry the registry for {@link NamedWriteable} object parsing + * @param client A client to make requests to the system + * @param clusterService A service to allow watching and updating cluster state + * @param threadPool A service to allow retrieving an executor to run an async action + * @param resourceWatcherService A service to watch for changes to node local files + * @param scriptService A service to allow running scripts on the local node + * @param xContentRegistry the registry for extensible xContent parsing + * @param environment the environment for path and setting configurations + * @param nodeEnvironment the node environment used coordinate access to the data paths + * @param namedWriteableRegistry the registry for {@link NamedWriteable} object parsing * @param indexNameExpressionResolver A service that resolves expression to index and alias names * @param repositoriesServiceSupplier A supplier for the service that manages snapshot repositories; will return null when this method - * is called, but will return the repositories service once the node is initialized. + * is called, but will return the repositories service once the node is initialized. + * @param contextSwitcher */ public Collection createComponents( - PluginAwareNodeClient client, + Client client, ClusterService clusterService, ThreadPool threadPool, ResourceWatcherService resourceWatcherService, @@ -150,7 +152,8 @@ public Collection createComponents( NodeEnvironment nodeEnvironment, NamedWriteableRegistry namedWriteableRegistry, IndexNameExpressionResolver indexNameExpressionResolver, - Supplier repositoriesServiceSupplier + Supplier repositoriesServiceSupplier, + ContextSwitcher contextSwitcher ) { return Collections.emptyList(); } diff --git a/server/src/main/java/org/opensearch/plugins/TelemetryAwarePlugin.java b/server/src/main/java/org/opensearch/plugins/TelemetryAwarePlugin.java index 471b334846160..13f17bc86cb44 100644 --- a/server/src/main/java/org/opensearch/plugins/TelemetryAwarePlugin.java +++ b/server/src/main/java/org/opensearch/plugins/TelemetryAwarePlugin.java @@ -8,11 +8,12 @@ package org.opensearch.plugins; -import org.opensearch.client.node.PluginAwareNodeClient; +import org.opensearch.client.node.NodeClient; import org.opensearch.cluster.metadata.IndexNameExpressionResolver; import org.opensearch.cluster.service.ClusterService; import org.opensearch.common.annotation.ExperimentalApi; import org.opensearch.common.lifecycle.LifecycleComponent; +import org.opensearch.common.util.concurrent.ContextSwitcher; import org.opensearch.core.common.io.stream.NamedWriteable; import org.opensearch.core.common.io.stream.NamedWriteableRegistry; import org.opensearch.core.xcontent.NamedXContentRegistry; @@ -61,7 +62,7 @@ public interface TelemetryAwarePlugin { * @param metricsRegistry the registry for metrics instrumentation. */ default Collection createComponents( - PluginAwareNodeClient client, + NodeClient client, ClusterService clusterService, ThreadPool threadPool, ResourceWatcherService resourceWatcherService, @@ -73,7 +74,8 @@ default Collection createComponents( IndexNameExpressionResolver indexNameExpressionResolver, Supplier repositoriesServiceSupplier, Tracer tracer, - MetricsRegistry metricsRegistry + MetricsRegistry metricsRegistry, + ContextSwitcher contextSwitcher ) { return Collections.emptyList(); } diff --git a/server/src/main/java/org/opensearch/transport/NativeMessageHandler.java b/server/src/main/java/org/opensearch/transport/NativeMessageHandler.java index 4c972fdc14fa5..fb90e6761df76 100644 --- a/server/src/main/java/org/opensearch/transport/NativeMessageHandler.java +++ b/server/src/main/java/org/opensearch/transport/NativeMessageHandler.java @@ -39,6 +39,7 @@ import org.opensearch.Version; import org.opensearch.common.util.BigArrays; import org.opensearch.common.util.concurrent.AbstractRunnable; +import org.opensearch.common.util.concurrent.InternalContextSwitcher; import org.opensearch.common.util.concurrent.ThreadContext; import org.opensearch.core.common.io.stream.ByteBufferStreamInput; import org.opensearch.core.common.io.stream.NamedWriteableAwareStreamInput; @@ -74,6 +75,7 @@ public class NativeMessageHandler implements ProtocolMessageHandler { private static final Logger logger = LogManager.getLogger(NativeMessageHandler.class); private final ThreadPool threadPool; + private final InternalContextSwitcher contextSwitcher; private final NativeOutboundHandler outboundHandler; private final NamedWriteableRegistry namedWriteableRegistry; private final TransportHandshaker handshaker; @@ -99,6 +101,7 @@ public class NativeMessageHandler implements ProtocolMessageHandler { TransportKeepAlive keepAlive ) { this.threadPool = threadPool; + this.contextSwitcher = new InternalContextSwitcher(threadPool); this.outboundHandler = new NativeOutboundHandler(nodeName, version, features, statsTracker, threadPool, bigArrays, outboundHandler); this.namedWriteableRegistry = namedWriteableRegistry; this.handshaker = handshaker; @@ -139,7 +142,7 @@ private void handleMessage( final Header header = message.getHeader(); assert header.needsToReadVariableHeader() == false; ThreadContext threadContext = threadPool.getThreadContext(); - try (ThreadContext.StoredContext existing = threadContext.stashContext()) { + try (ThreadContext.StoredContext existing = contextSwitcher.switchContext()) { // Place the context with the headers from the message threadContext.setHeaders(header.getHeaders()); threadContext.putTransient("_remote_address", remoteAddress); diff --git a/server/src/main/java/org/opensearch/transport/OutboundHandler.java b/server/src/main/java/org/opensearch/transport/OutboundHandler.java index 43f53e4011260..837f65b12e7b2 100644 --- a/server/src/main/java/org/opensearch/transport/OutboundHandler.java +++ b/server/src/main/java/org/opensearch/transport/OutboundHandler.java @@ -40,6 +40,7 @@ import org.opensearch.common.lease.Releasables; import org.opensearch.common.network.CloseableChannel; import org.opensearch.common.transport.NetworkExceptionHelper; +import org.opensearch.common.util.concurrent.InternalContextSwitcher; import org.opensearch.common.util.concurrent.ThreadContext; import org.opensearch.core.action.ActionListener; import org.opensearch.core.action.NotifyOnceListener; @@ -59,10 +60,12 @@ public final class OutboundHandler { private final StatsTracker statsTracker; private final ThreadPool threadPool; + private final InternalContextSwitcher contextSwitcher; public OutboundHandler(StatsTracker statsTracker, ThreadPool threadPool) { this.statsTracker = statsTracker; this.threadPool = threadPool; + this.contextSwitcher = new InternalContextSwitcher(threadPool); } void sendBytes(TcpChannel channel, BytesReference bytes, ActionListener listener) { @@ -79,7 +82,7 @@ public void sendBytes(TcpChannel channel, SendContext sendContext) throws IOExce channel.getChannelStats().markAccessed(threadPool.relativeTimeInMillis()); BytesReference reference = sendContext.get(); // stash thread context so that channel event loop is not polluted by thread context - try (ThreadContext.StoredContext existing = threadPool.getThreadContext().stashContext()) { + try (ThreadContext.StoredContext existing = contextSwitcher.switchContext()) { channel.sendMessage(reference, sendContext); } catch (RuntimeException ex) { sendContext.onFailure(ex); diff --git a/server/src/main/java/org/opensearch/transport/RemoteClusterConnection.java b/server/src/main/java/org/opensearch/transport/RemoteClusterConnection.java index 8a5f6dfffb036..559a8bd48c26a 100644 --- a/server/src/main/java/org/opensearch/transport/RemoteClusterConnection.java +++ b/server/src/main/java/org/opensearch/transport/RemoteClusterConnection.java @@ -39,6 +39,7 @@ import org.opensearch.cluster.node.DiscoveryNodes; import org.opensearch.common.settings.Settings; import org.opensearch.common.unit.TimeValue; +import org.opensearch.common.util.concurrent.InternalContextSwitcher; import org.opensearch.common.util.concurrent.ThreadContext; import org.opensearch.common.util.io.IOUtils; import org.opensearch.core.action.ActionListener; @@ -71,6 +72,7 @@ final class RemoteClusterConnection implements Closeable { private final RemoteConnectionStrategy connectionStrategy; private final String clusterAlias; private final ThreadPool threadPool; + private final InternalContextSwitcher contextSwitcher; private volatile boolean skipUnavailable; private final TimeValue initialConnectionTimeout; @@ -91,6 +93,7 @@ final class RemoteClusterConnection implements Closeable { this.skipUnavailable = RemoteClusterService.REMOTE_CLUSTER_SKIP_UNAVAILABLE.getConcreteSettingForNamespace(clusterAlias) .get(settings); this.threadPool = transportService.threadPool; + this.contextSwitcher = new InternalContextSwitcher(this.threadPool); initialConnectionTimeout = RemoteClusterService.REMOTE_INITIAL_CONNECTION_TIMEOUT_SETTING.get(settings); } @@ -134,7 +137,7 @@ void collectNodes(ActionListener> listener) { final ThreadContext threadContext = threadPool.getThreadContext(); final ContextPreservingActionListener> contextPreservingActionListener = new ContextPreservingActionListener<>(threadContext.newRestorableContext(false), listener); - try (ThreadContext.StoredContext ignore = threadContext.stashContext()) { + try (ThreadContext.StoredContext ignore = contextSwitcher.switchContext()) { // we stash any context here since this is an internal execution and should not leak any existing context information threadContext.markAsSystemContext(); diff --git a/server/src/main/java/org/opensearch/transport/SniffConnectionStrategy.java b/server/src/main/java/org/opensearch/transport/SniffConnectionStrategy.java index 07ba96b135189..915235d4825a7 100644 --- a/server/src/main/java/org/opensearch/transport/SniffConnectionStrategy.java +++ b/server/src/main/java/org/opensearch/transport/SniffConnectionStrategy.java @@ -46,6 +46,7 @@ import org.opensearch.common.UUIDs; import org.opensearch.common.settings.Setting; import org.opensearch.common.settings.Settings; +import org.opensearch.common.util.concurrent.InternalContextSwitcher; import org.opensearch.common.util.concurrent.ThreadContext; import org.opensearch.common.util.io.IOUtils; import org.opensearch.core.action.ActionListener; @@ -149,6 +150,7 @@ public class SniffConnectionStrategy extends RemoteConnectionStrategy { private final Predicate nodePredicate; private final SetOnce remoteClusterName = new SetOnce<>(); private final String proxyAddress; + private final InternalContextSwitcher contextSwitcher; SniffConnectionStrategy( String clusterAlias, @@ -210,6 +212,7 @@ public class SniffConnectionStrategy extends RemoteConnectionStrategy { this.nodePredicate = nodePredicate; this.configuredSeedNodes = configuredSeedNodes; this.seedNodes = seedNodes; + this.contextSwitcher = new InternalContextSwitcher(transportService.getThreadPool()); } static Stream> enablementSettings() { @@ -346,7 +349,7 @@ private void collectRemoteNodes(Iterator> seedNodes, Act threadContext.newRestorableContext(false), new SniffClusterStateResponseHandler(connection, listener, seedNodes) ); - try (ThreadContext.StoredContext ignore = threadContext.stashContext()) { + try (ThreadContext.StoredContext ignore = contextSwitcher.switchContext()) { // we stash any context here since this is an internal execution and should not leak any // existing context information. threadContext.markAsSystemContext(); diff --git a/server/src/test/java/org/opensearch/action/bulk/BulkProcessorTests.java b/server/src/test/java/org/opensearch/action/bulk/BulkProcessorTests.java index 6ff3ba473b5e9..648c97da5fb65 100644 --- a/server/src/test/java/org/opensearch/action/bulk/BulkProcessorTests.java +++ b/server/src/test/java/org/opensearch/action/bulk/BulkProcessorTests.java @@ -37,6 +37,7 @@ import org.opensearch.ExceptionsHelper; import org.opensearch.action.index.IndexRequest; import org.opensearch.common.unit.TimeValue; +import org.opensearch.common.util.concurrent.InternalContextSwitcher; import org.opensearch.common.util.concurrent.ThreadContext; import org.opensearch.core.action.ActionListener; import org.opensearch.core.common.bytes.BytesReference; @@ -68,11 +69,13 @@ public class BulkProcessorTests extends OpenSearchTestCase { private ThreadPool threadPool; + private InternalContextSwitcher contextSwitcher; private final Logger logger = LogManager.getLogger(BulkProcessorTests.class); @Before public void startThreadPool() { threadPool = new TestThreadPool("BulkProcessorTests"); + contextSwitcher = new InternalContextSwitcher(threadPool); } @After @@ -99,7 +102,7 @@ public void testBulkProcessorFlushPreservesContext() throws InterruptedException final BulkProcessor bulkProcessor; assertNull(threadPool.getThreadContext().getHeader(headerKey)); assertNull(threadPool.getThreadContext().getTransient(transientKey)); - try (ThreadContext.StoredContext ignore = threadPool.getThreadContext().stashContext()) { + try (ThreadContext.StoredContext ignore = contextSwitcher.switchContext()) { threadPool.getThreadContext().putHeader(headerKey, headerValue); threadPool.getThreadContext().putTransient(transientKey, transientValue); bulkProcessor = new BulkProcessor( diff --git a/server/src/test/java/org/opensearch/action/bulk/RetryTests.java b/server/src/test/java/org/opensearch/action/bulk/RetryTests.java index aa33372239fed..6d90e910c6ce4 100644 --- a/server/src/test/java/org/opensearch/action/bulk/RetryTests.java +++ b/server/src/test/java/org/opensearch/action/bulk/RetryTests.java @@ -72,7 +72,7 @@ public void setUp() throws Exception { super.setUp(); this.bulkClient = new MockBulkClient(getTestName(), CALLS_TO_FAIL); // Stash some random headers so we can assert that we preserve them - bulkClient.threadPool().getThreadContext().stashContext(); + // bulkClient.threadPool().getThreadContext().stashContext(); expectedHeaders.clear(); expectedHeaders.put(randomAlphaOfLength(5), randomAlphaOfLength(5)); bulkClient.threadPool().getThreadContext().putHeader(expectedHeaders); diff --git a/server/src/test/java/org/opensearch/action/support/ContextPreservingActionListenerTests.java b/server/src/test/java/org/opensearch/action/support/ContextPreservingActionListenerTests.java index 0b9f2c6707c02..7e283be59fdf6 100644 --- a/server/src/test/java/org/opensearch/action/support/ContextPreservingActionListenerTests.java +++ b/server/src/test/java/org/opensearch/action/support/ContextPreservingActionListenerTests.java @@ -31,10 +31,12 @@ package org.opensearch.action.support; -import org.opensearch.common.settings.Settings; +import org.opensearch.common.util.concurrent.InternalContextSwitcher; import org.opensearch.common.util.concurrent.ThreadContext; import org.opensearch.core.action.ActionListener; import org.opensearch.test.OpenSearchTestCase; +import org.opensearch.threadpool.TestThreadPool; +import org.opensearch.threadpool.ThreadPool; import java.io.IOException; @@ -44,13 +46,15 @@ public class ContextPreservingActionListenerTests extends OpenSearchTestCase { public void testOriginalContextIsPreservedAfterOnResponse() throws IOException { - ThreadContext threadContext = new ThreadContext(Settings.EMPTY); + ThreadPool threadPool = new TestThreadPool("ContextPreservingActionListenerTests.testOriginalContextIsPreservedAfterOnResponse"); + ThreadContext threadContext = threadPool.getThreadContext(); + InternalContextSwitcher contextSwitcher = new InternalContextSwitcher(threadPool); final boolean nonEmptyContext = randomBoolean(); if (nonEmptyContext) { threadContext.putHeader("not empty", "value"); } final ContextPreservingActionListener actionListener; - try (ThreadContext.StoredContext ignore = threadContext.stashContext()) { + try (ThreadContext.StoredContext ignore = contextSwitcher.switchContext()) { threadContext.putHeader("foo", "bar"); final ActionListener delegate = new ActionListener() { @Override @@ -81,13 +85,15 @@ public void onFailure(Exception e) { } public void testOriginalContextIsPreservedAfterOnFailure() throws Exception { - ThreadContext threadContext = new ThreadContext(Settings.EMPTY); + ThreadPool threadPool = new TestThreadPool("ContextPreservingActionListenerTests.testOriginalContextIsPreservedAfterOnFailure"); + ThreadContext threadContext = threadPool.getThreadContext(); + InternalContextSwitcher contextSwitcher = new InternalContextSwitcher(threadPool); final boolean nonEmptyContext = randomBoolean(); if (nonEmptyContext) { threadContext.putHeader("not empty", "value"); } final ContextPreservingActionListener actionListener; - try (ThreadContext.StoredContext ignore = threadContext.stashContext()) { + try (ThreadContext.StoredContext ignore = contextSwitcher.switchContext()) { threadContext.putHeader("foo", "bar"); final ActionListener delegate = new ActionListener() { @Override @@ -120,13 +126,15 @@ public void onFailure(Exception e) { } public void testOriginalContextIsWhenListenerThrows() throws Exception { - ThreadContext threadContext = new ThreadContext(Settings.EMPTY); + ThreadPool threadPool = new TestThreadPool("ContextPreservingActionListenerTests.testOriginalContextIsWhenListenerThrows"); + ThreadContext threadContext = threadPool.getThreadContext(); + InternalContextSwitcher contextSwitcher = new InternalContextSwitcher(threadPool); final boolean nonEmptyContext = randomBoolean(); if (nonEmptyContext) { threadContext.putHeader("not empty", "value"); } final ContextPreservingActionListener actionListener; - try (ThreadContext.StoredContext ignore = threadContext.stashContext()) { + try (ThreadContext.StoredContext ignore = contextSwitcher.switchContext()) { threadContext.putHeader("foo", "bar"); final ActionListener delegate = new ActionListener() { @Override @@ -168,9 +176,11 @@ public void onFailure(Exception e) { } public void testToStringIncludesDelegate() { - ThreadContext threadContext = new ThreadContext(Settings.EMPTY); + ThreadPool threadPool = new TestThreadPool("ContextPreservingActionListenerTests.testToStringIncludesDelegate"); + ThreadContext threadContext = threadPool.getThreadContext(); + InternalContextSwitcher contextSwitcher = new InternalContextSwitcher(threadPool); final ContextPreservingActionListener actionListener; - try (ThreadContext.StoredContext ignore = threadContext.stashContext()) { + try (ThreadContext.StoredContext ignore = contextSwitcher.switchContext()) { final ActionListener delegate = new ActionListener() { @Override public void onResponse(Void aVoid) {} diff --git a/server/src/test/java/org/opensearch/cluster/metadata/TemplateUpgradeServiceTests.java b/server/src/test/java/org/opensearch/cluster/metadata/TemplateUpgradeServiceTests.java index 36d984b7eb99b..5935dd0544615 100644 --- a/server/src/test/java/org/opensearch/cluster/metadata/TemplateUpgradeServiceTests.java +++ b/server/src/test/java/org/opensearch/cluster/metadata/TemplateUpgradeServiceTests.java @@ -46,6 +46,7 @@ import org.opensearch.cluster.node.DiscoveryNodes; import org.opensearch.cluster.service.ClusterService; import org.opensearch.common.collect.Tuple; +import org.opensearch.common.util.concurrent.InternalContextSwitcher; import org.opensearch.common.util.concurrent.ThreadContext; import org.opensearch.core.action.ActionListener; import org.opensearch.core.common.bytes.BytesArray; @@ -90,10 +91,12 @@ public class TemplateUpgradeServiceTests extends OpenSearchTestCase { private ThreadPool threadPool; private ClusterService clusterService; + private InternalContextSwitcher contextSwitcher; @Before public void setUpTest() throws Exception { threadPool = new TestThreadPool("TemplateUpgradeServiceTests"); + contextSwitcher = new InternalContextSwitcher(threadPool); clusterService = createClusterService(threadPool); } @@ -224,7 +227,7 @@ public void testUpdateTemplates() { service.upgradesInProgress.set(additionsCount + deletionsCount + 2); // +2 to skip tryFinishUpgrade final ThreadContext threadContext = threadPool.getThreadContext(); - try (ThreadContext.StoredContext ignore = threadContext.stashContext()) { + try (ThreadContext.StoredContext ignore = contextSwitcher.switchContext()) { threadContext.markAsSystemContext(); service.upgradeTemplates(additions, deletions); } diff --git a/server/src/test/java/org/opensearch/cluster/service/ClusterApplierServiceTests.java b/server/src/test/java/org/opensearch/cluster/service/ClusterApplierServiceTests.java index be6057a391b2e..475c2f12fcc7f 100644 --- a/server/src/test/java/org/opensearch/cluster/service/ClusterApplierServiceTests.java +++ b/server/src/test/java/org/opensearch/cluster/service/ClusterApplierServiceTests.java @@ -51,6 +51,7 @@ import org.opensearch.common.settings.ClusterSettings; import org.opensearch.common.settings.Settings; import org.opensearch.common.unit.TimeValue; +import org.opensearch.common.util.concurrent.InternalContextSwitcher; import org.opensearch.common.util.concurrent.ThreadContext; import org.opensearch.telemetry.metrics.Histogram; import org.opensearch.telemetry.metrics.MetricsRegistry; @@ -91,6 +92,7 @@ public class ClusterApplierServiceTests extends OpenSearchTestCase { private static ThreadPool threadPool; + private static InternalContextSwitcher contextSwitcher; private TimedClusterApplierService clusterApplierService; private static MetricsRegistry metricsRegistry; private static Histogram applierslatencyHistogram; @@ -99,6 +101,7 @@ public class ClusterApplierServiceTests extends OpenSearchTestCase { @BeforeClass public static void createThreadPool() { threadPool = new TestThreadPool(ClusterApplierServiceTests.class.getName()); + contextSwitcher = new InternalContextSwitcher(threadPool); metricsRegistry = mock(MetricsRegistry.class); applierslatencyHistogram = mock(Histogram.class); listenerslatencyHistogram = mock(Histogram.class); @@ -634,7 +637,7 @@ public void onFailure(String source, Exception e) { public void testThreadContext() throws InterruptedException { final CountDownLatch latch = new CountDownLatch(1); - try (ThreadContext.StoredContext ignored = threadPool.getThreadContext().stashContext()) { + try (ThreadContext.StoredContext ignored = contextSwitcher.switchContext()) { final Map expectedHeaders = Collections.singletonMap("test", "test"); final Map> expectedResponseHeaders = Collections.singletonMap( "testResponse", diff --git a/server/src/test/java/org/opensearch/cluster/service/MasterServiceTests.java b/server/src/test/java/org/opensearch/cluster/service/MasterServiceTests.java index 8c84ac365dfd1..846990d32c97b 100644 --- a/server/src/test/java/org/opensearch/cluster/service/MasterServiceTests.java +++ b/server/src/test/java/org/opensearch/cluster/service/MasterServiceTests.java @@ -60,6 +60,7 @@ import org.opensearch.common.settings.Settings; import org.opensearch.common.unit.TimeValue; import org.opensearch.common.util.concurrent.BaseFuture; +import org.opensearch.common.util.concurrent.InternalContextSwitcher; import org.opensearch.common.util.concurrent.ThreadContext; import org.opensearch.node.Node; import org.opensearch.telemetry.metrics.Histogram; @@ -111,6 +112,7 @@ public class MasterServiceTests extends OpenSearchTestCase { private static ThreadPool threadPool; + private static InternalContextSwitcher contextSwitcher; private static long timeDiffInMillis; @BeforeClass @@ -121,6 +123,7 @@ public long preciseRelativeTimeInNanos() { return timeDiffInMillis * TimeValue.NSEC_PER_MSEC; } }; + contextSwitcher = new InternalContextSwitcher(threadPool); } @AfterClass @@ -246,7 +249,7 @@ public void testThreadContext() throws InterruptedException { final ClusterManagerService clusterManagerService = createClusterManagerService(true); final CountDownLatch latch = new CountDownLatch(1); - try (ThreadContext.StoredContext ignored = threadPool.getThreadContext().stashContext()) { + try (ThreadContext.StoredContext ignored = contextSwitcher.switchContext()) { final Map expectedHeaders = Collections.singletonMap("test", "test"); final Map> expectedResponseHeaders = Collections.singletonMap( "testResponse", diff --git a/server/src/test/java/org/opensearch/index/shard/RefreshListenersTests.java b/server/src/test/java/org/opensearch/index/shard/RefreshListenersTests.java index 8a77fbca2915d..226bc88cddb9c 100644 --- a/server/src/test/java/org/opensearch/index/shard/RefreshListenersTests.java +++ b/server/src/test/java/org/opensearch/index/shard/RefreshListenersTests.java @@ -49,6 +49,7 @@ import org.opensearch.common.settings.Settings; import org.opensearch.common.unit.TimeValue; import org.opensearch.common.util.BigArrays; +import org.opensearch.common.util.concurrent.InternalContextSwitcher; import org.opensearch.common.util.concurrent.ThreadContext; import org.opensearch.common.util.io.IOUtils; import org.opensearch.core.common.bytes.BytesArray; @@ -105,6 +106,7 @@ public class RefreshListenersTests extends OpenSearchTestCase { private Engine engine; private volatile int maxListeners; private ThreadPool threadPool; + private InternalContextSwitcher contextSwitcher; private Store store; private MeanMetric refreshMetric; @@ -114,14 +116,9 @@ public void setupListeners() throws Exception { maxListeners = randomIntBetween(1, 1000); // Now setup the InternalEngine which is much more complicated because we aren't mocking anything threadPool = new TestThreadPool(getTestName()); + contextSwitcher = new InternalContextSwitcher(threadPool); refreshMetric = new MeanMetric(); - listeners = new RefreshListeners( - () -> maxListeners, - () -> engine.refresh("too-many-listeners"), - logger, - threadPool.getThreadContext(), - refreshMetric - ); + listeners = new RefreshListeners(() -> maxListeners, () -> engine.refresh("too-many-listeners"), logger, threadPool, refreshMetric); IndexSettings indexSettings = IndexSettingsModule.newIndexSettings("index", Settings.EMPTY); ShardId shardId = new ShardId(new Index("index", "_na_"), 1); @@ -218,7 +215,7 @@ public void testContextIsPreserved() throws IOException, InterruptedException { assertEquals(0, listeners.pendingCount()); Engine.IndexResult index = index("1"); CountDownLatch latch = new CountDownLatch(1); - try (ThreadContext.StoredContext ignore = threadPool.getThreadContext().stashContext()) { + try (ThreadContext.StoredContext ignore = contextSwitcher.switchContext()) { threadPool.getThreadContext().putHeader("test", "foobar"); assertFalse(listeners.addOrNotify(index.getTranslogLocation(), forced -> { assertEquals("foobar", threadPool.getThreadContext().getHeader("test")); diff --git a/server/src/test/java/org/opensearch/node/NodeTests.java b/server/src/test/java/org/opensearch/node/NodeTests.java index 45328769d8b29..37936c18b0226 100644 --- a/server/src/test/java/org/opensearch/node/NodeTests.java +++ b/server/src/test/java/org/opensearch/node/NodeTests.java @@ -34,7 +34,7 @@ import org.apache.lucene.tests.util.LuceneTestCase; import org.opensearch.bootstrap.BootstrapCheck; import org.opensearch.bootstrap.BootstrapContext; -import org.opensearch.client.node.PluginAwareNodeClient; +import org.opensearch.client.node.NodeClient; import org.opensearch.cluster.ClusterName; import org.opensearch.cluster.metadata.IndexNameExpressionResolver; import org.opensearch.cluster.node.DiscoveryNodeRole; @@ -466,7 +466,7 @@ public MetricsRegistry getMetricsRegistry() { public static class MockTelemetryAwarePlugin extends Plugin implements TelemetryAwarePlugin { @Override public Collection createComponents( - PluginAwareNodeClient client, + NodeClient client, ClusterService clusterService, ThreadPool threadPool, ResourceWatcherService resourceWatcherService, diff --git a/server/src/test/java/org/opensearch/rest/action/admin/indices/RestValidateQueryActionTests.java b/server/src/test/java/org/opensearch/rest/action/admin/indices/RestValidateQueryActionTests.java index 3fb6764846da6..1468f5d0f0b61 100644 --- a/server/src/test/java/org/opensearch/rest/action/admin/indices/RestValidateQueryActionTests.java +++ b/server/src/test/java/org/opensearch/rest/action/admin/indices/RestValidateQueryActionTests.java @@ -56,7 +56,6 @@ import org.opensearch.threadpool.ThreadPool; import org.opensearch.usage.UsageService; import org.junit.AfterClass; -import org.junit.Before; import org.junit.BeforeClass; import java.util.Collections; @@ -113,12 +112,6 @@ protected void doExecute(Task task, ActionRequest request, ActionListener listen controller.registerHandler(action); } - @Before - public void ensureCleanContext() { - // Make sure we have a clean context for each test - threadPool.getThreadContext().stashContext(); - } - @AfterClass public static void terminateThreadPool() throws InterruptedException { terminate(threadPool); diff --git a/server/src/test/java/org/opensearch/telemetry/tracing/ThreadContextBasedTracerContextStorageTests.java b/server/src/test/java/org/opensearch/telemetry/tracing/ThreadContextBasedTracerContextStorageTests.java index bf11bcaf39a96..bfd43c8804fd4 100644 --- a/server/src/test/java/org/opensearch/telemetry/tracing/ThreadContextBasedTracerContextStorageTests.java +++ b/server/src/test/java/org/opensearch/telemetry/tracing/ThreadContextBasedTracerContextStorageTests.java @@ -10,6 +10,7 @@ import org.opensearch.common.settings.ClusterSettings; import org.opensearch.common.settings.Settings; +import org.opensearch.common.util.concurrent.InternalContextSwitcher; import org.opensearch.common.util.concurrent.ThreadContext; import org.opensearch.common.util.concurrent.ThreadContext.StoredContext; import org.opensearch.telemetry.Telemetry; @@ -18,6 +19,8 @@ import org.opensearch.telemetry.tracing.noop.NoopTracer; import org.opensearch.test.OpenSearchTestCase; import org.opensearch.test.telemetry.tracing.MockTracingTelemetry; +import org.opensearch.threadpool.TestThreadPool; +import org.opensearch.threadpool.ThreadPool; import org.junit.After; import org.junit.Before; @@ -39,6 +42,8 @@ public class ThreadContextBasedTracerContextStorageTests extends OpenSearchTestCase { private Tracer tracer; + private ThreadPool threadPool; + private InternalContextSwitcher contextSwitcher; private ThreadContext threadContext; private TracerContextStorage threadContextStorage; private ExecutorService executorService; @@ -61,7 +66,9 @@ public void setUp() throws Exception { final TracingTelemetry tracingTelemetry = new MockTracingTelemetry(); - threadContext = new ThreadContext(Settings.EMPTY); + threadPool = new TestThreadPool(getTestName()); + threadContext = threadPool.getThreadContext(); + contextSwitcher = new InternalContextSwitcher(threadPool); threadContextStorage = new ThreadContextBasedTracerContextStorage(threadContext, tracingTelemetry); tracer = new TracerFactory(telemetrySettings, Optional.of(new Telemetry() { @@ -116,7 +123,7 @@ public void testStashingPropagatesThreadContext() { final Span span = tracer.startSpan(SpanCreationContext.internal().name("test")); try (SpanScope scope = tracer.withSpanInScope(span)) { - try (StoredContext ignored = threadContext.stashContext()) { + try (StoredContext ignored = contextSwitcher.switchContext()) { assertThat(threadContext.getTransient(ThreadContextBasedTracerContextStorage.CURRENT_SPAN), is(not(nullValue()))); assertThat(threadContextStorage.get(ThreadContextBasedTracerContextStorage.CURRENT_SPAN), is(span)); } @@ -154,7 +161,7 @@ public void run() { final Span local1 = tracer.startSpan(SpanCreationContext.internal().name("test-local-1")); try (SpanScope localScope = tracer.withSpanInScope(local1)) { - try (StoredContext ignored = threadContext.stashContext()) { + try (StoredContext ignored = contextSwitcher.switchContext()) { assertThat(local1.getParentSpan(), is(nullValue())); assertThat(threadContextStorage.get(ThreadContextBasedTracerContextStorage.CURRENT_SPAN), is(local1)); } @@ -162,7 +169,7 @@ public void run() { final Span local2 = tracer.startSpan(SpanCreationContext.internal().name("test-local-2")); try (SpanScope localScope = tracer.withSpanInScope(local2)) { - try (StoredContext ignored = threadContext.stashContext()) { + try (StoredContext ignored = contextSwitcher.switchContext()) { assertThat(local2.getParentSpan(), is(nullValue())); assertThat(threadContextStorage.get(ThreadContextBasedTracerContextStorage.CURRENT_SPAN), is(local2)); } @@ -170,7 +177,7 @@ public void run() { final Span local3 = tracer.startSpan(SpanCreationContext.internal().name("test-local-3")); try (SpanScope localScope = tracer.withSpanInScope(local3)) { - try (StoredContext ignored = threadContext.stashContext()) { + try (StoredContext ignored = contextSwitcher.switchContext()) { assertThat(local3.getParentSpan(), is(nullValue())); assertThat(threadContextStorage.get(ThreadContextBasedTracerContextStorage.CURRENT_SPAN), is(local3)); } @@ -195,7 +202,7 @@ public void run() { final Span local1 = tracer.startSpan(SpanCreationContext.internal().name("test-local-1")); try (SpanScope localScope = tracer.withSpanInScope(local1)) { - try (StoredContext ignored = threadContext.stashContext()) { + try (StoredContext ignored = contextSwitcher.switchContext()) { assertThat(local1.getParentSpan(), is(span)); assertThat(threadContextStorage.get(ThreadContextBasedTracerContextStorage.CURRENT_SPAN), is(local1)); } @@ -203,7 +210,7 @@ public void run() { final Span local2 = tracer.startSpan(SpanCreationContext.internal().name("test-local-2")); try (SpanScope localScope = tracer.withSpanInScope(local2)) { - try (StoredContext ignored = threadContext.stashContext()) { + try (StoredContext ignored = contextSwitcher.switchContext()) { assertThat(local2.getParentSpan(), is(span)); assertThat(threadContextStorage.get(ThreadContextBasedTracerContextStorage.CURRENT_SPAN), is(local2)); } @@ -211,7 +218,7 @@ public void run() { final Span local3 = tracer.startSpan(SpanCreationContext.internal().name("test-local-3")); try (SpanScope localScope = tracer.withSpanInScope(local3)) { - try (StoredContext ignored = threadContext.stashContext()) { + try (StoredContext ignored = contextSwitcher.switchContext()) { assertThat(local3.getParentSpan(), is(span)); assertThat(threadContextStorage.get(ThreadContextBasedTracerContextStorage.CURRENT_SPAN), is(local3)); } @@ -235,7 +242,7 @@ public void testPreservingContextAndStashingThreadContext() throws InterruptedEx public void run() { final Span local = tracer.startSpan(SpanCreationContext.internal().name("test-local")); try (SpanScope localScope = tracer.withSpanInScope(local)) { - try (StoredContext ignored = threadContext.stashContext()) { + try (StoredContext ignored = contextSwitcher.switchContext()) { assertThat( threadContext.getTransient(ThreadContextBasedTracerContextStorage.CURRENT_SPAN), is(not(nullValue())) @@ -257,7 +264,7 @@ public void testSpanNotPropagatedToChildSystemThreadContext() { final Span span = tracer.startSpan(SpanCreationContext.internal().name("test")); try (SpanScope scope = tracer.withSpanInScope(span)) { - try (StoredContext ignored = threadContext.stashContext()) { + try (StoredContext ignored = contextSwitcher.switchContext()) { assertThat(threadContext.getTransient(ThreadContextBasedTracerContextStorage.CURRENT_SPAN), is(not(nullValue()))); assertThat(threadContextStorage.get(ThreadContextBasedTracerContextStorage.CURRENT_SPAN), is(span)); threadContext.markAsSystemContext(); diff --git a/test/framework/src/main/java/org/opensearch/cluster/service/FakeThreadPoolClusterManagerService.java b/test/framework/src/main/java/org/opensearch/cluster/service/FakeThreadPoolClusterManagerService.java index 53ef595c7931e..cf20c34cca660 100644 --- a/test/framework/src/main/java/org/opensearch/cluster/service/FakeThreadPoolClusterManagerService.java +++ b/test/framework/src/main/java/org/opensearch/cluster/service/FakeThreadPoolClusterManagerService.java @@ -41,6 +41,7 @@ import org.opensearch.common.settings.ClusterSettings; import org.opensearch.common.settings.Settings; import org.opensearch.common.unit.TimeValue; +import org.opensearch.common.util.concurrent.InternalContextSwitcher; import org.opensearch.common.util.concurrent.OpenSearchExecutors; import org.opensearch.common.util.concurrent.PrioritizedOpenSearchThreadPoolExecutor; import org.opensearch.common.util.concurrent.ThreadContext; @@ -63,6 +64,7 @@ public class FakeThreadPoolClusterManagerService extends ClusterManagerService { private final String name; private final List pendingTasks = new ArrayList<>(); private final Consumer onTaskAvailableToRun; + private final InternalContextSwitcher contextSwitcher; private boolean scheduledNextTask = false; private boolean taskInProgress = false; private boolean waitForPublish = false; @@ -81,6 +83,7 @@ public FakeThreadPoolClusterManagerService( ); this.name = serviceName; this.onTaskAvailableToRun = onTaskAvailableToRun; + this.contextSwitcher = new InternalContextSwitcher(threadPool); } @Override @@ -133,7 +136,7 @@ public void run() { taskInProgress = true; scheduledNextTask = false; final ThreadContext threadContext = threadPool.getThreadContext(); - try (ThreadContext.StoredContext ignored = threadContext.stashContext()) { + try (ThreadContext.StoredContext ignored = contextSwitcher.switchContext()) { threadContext.markAsSystemContext(); task.run(); } diff --git a/test/framework/src/main/java/org/opensearch/test/OpenSearchTestCase.java b/test/framework/src/main/java/org/opensearch/test/OpenSearchTestCase.java index 6afc7c23d9e66..e0d4f91355f88 100644 --- a/test/framework/src/main/java/org/opensearch/test/OpenSearchTestCase.java +++ b/test/framework/src/main/java/org/opensearch/test/OpenSearchTestCase.java @@ -618,7 +618,7 @@ private void assertWarnings(boolean stripXContentPosition, List actualWa */ private void resetDeprecationLogger() { // "clear" context by stashing current values and dropping the returned StoredContext - threadContext.stashContext(); + // threadContext.stashContext(); } private static final List statusData = new ArrayList<>(); From e2ebb36cc9853dc7228496710af7fc9313be1e3a Mon Sep 17 00:00:00 2001 From: Craig Perkins Date: Tue, 23 Jul 2024 14:55:48 -0400 Subject: [PATCH 17/65] Make stashContext package-private Signed-off-by: Craig Perkins --- .../repositories/s3/S3RepositoryPlugin.java | 2 +- .../http/TestExecutionContextPlugin.java | 2 +- .../TestGetExecutionContextRestAction.java | 2 +- .../cluster/SimpleClusterStateIT.java | 2 +- .../org/opensearch/index/FinalPipelineIT.java | 2 +- .../client/OriginSettingClient.java | 13 +++++-- .../client/support/AbstractClient.java | 6 ++-- .../service/ClusterApplierService.java | 3 +- .../cluster/service/MasterService.java | 3 +- .../util/concurrent/ContextSwitcher.java | 20 ++--------- .../concurrent/InternalContextSwitcher.java | 9 ++++- .../concurrent/PluginContextSwitcher.java | 36 +++++++++++++++++++ .../common/util/concurrent/ThreadContext.java | 6 ++-- .../http/AbstractHttpServerTransport.java | 3 +- .../seqno/GlobalCheckpointSyncAction.java | 3 +- .../RetentionLeaseBackgroundSyncAction.java | 3 +- .../index/shard/RefreshListeners.java | 3 +- .../checkpoint/PublishCheckpointAction.java | 3 +- .../main/java/org/opensearch/node/Node.java | 5 +-- .../transport/NativeMessageHandler.java | 3 +- .../opensearch/transport/OutboundHandler.java | 3 +- .../transport/RemoteClusterConnection.java | 3 +- .../transport/SniffConnectionStrategy.java | 3 +- .../action/bulk/BulkProcessorTests.java | 3 +- .../ContextPreservingActionListenerTests.java | 9 ++--- .../metadata/TemplateUpgradeServiceTests.java | 3 +- .../service/ClusterApplierServiceTests.java | 3 +- .../cluster/service/MasterServiceTests.java | 3 +- .../index/shard/RefreshListenersTests.java | 3 +- ...ContextBasedTracerContextStorageTests.java | 3 +- .../FakeThreadPoolClusterManagerService.java | 3 +- .../util/concurrent/TestContextSwitcher.java | 29 +++++++++++++++ 32 files changed, 142 insertions(+), 55 deletions(-) create mode 100644 server/src/main/java/org/opensearch/common/util/concurrent/PluginContextSwitcher.java create mode 100644 test/framework/src/main/java/org/opensearch/common/util/concurrent/TestContextSwitcher.java diff --git a/plugins/repository-s3/src/main/java/org/opensearch/repositories/s3/S3RepositoryPlugin.java b/plugins/repository-s3/src/main/java/org/opensearch/repositories/s3/S3RepositoryPlugin.java index d5f29503cb325..0d72c554caee1 100644 --- a/plugins/repository-s3/src/main/java/org/opensearch/repositories/s3/S3RepositoryPlugin.java +++ b/plugins/repository-s3/src/main/java/org/opensearch/repositories/s3/S3RepositoryPlugin.java @@ -213,7 +213,7 @@ public Collection createComponents( final NamedWriteableRegistry namedWriteableRegistry, final IndexNameExpressionResolver expressionResolver, final Supplier repositoriesServiceSupplier, - ContextSwitcher contextSwitcher + final ContextSwitcher contextSwitcher ) { int urgentEventLoopThreads = urgentPoolCount(clusterService.getSettings()); int priorityEventLoopThreads = priorityPoolCount(clusterService.getSettings()); diff --git a/qa/smoke-test-http/src/test/java/org/opensearch/http/TestExecutionContextPlugin.java b/qa/smoke-test-http/src/test/java/org/opensearch/http/TestExecutionContextPlugin.java index 316e2104ed7f0..27879c6d2a6c7 100644 --- a/qa/smoke-test-http/src/test/java/org/opensearch/http/TestExecutionContextPlugin.java +++ b/qa/smoke-test-http/src/test/java/org/opensearch/http/TestExecutionContextPlugin.java @@ -16,6 +16,7 @@ import org.opensearch.common.settings.IndexScopedSettings; import org.opensearch.common.settings.Settings; import org.opensearch.common.settings.SettingsFilter; +import org.opensearch.common.util.concurrent.ContextSwitcher; import org.opensearch.core.common.io.stream.NamedWriteableRegistry; import org.opensearch.core.xcontent.NamedXContentRegistry; import org.opensearch.env.Environment; @@ -26,7 +27,6 @@ import org.opensearch.rest.RestController; import org.opensearch.rest.RestHandler; import org.opensearch.script.ScriptService; -import org.opensearch.common.util.concurrent.ContextSwitcher; import org.opensearch.threadpool.ThreadPool; import org.opensearch.watcher.ResourceWatcherService; diff --git a/qa/smoke-test-http/src/test/java/org/opensearch/http/TestGetExecutionContextRestAction.java b/qa/smoke-test-http/src/test/java/org/opensearch/http/TestGetExecutionContextRestAction.java index 0fa3861226cdf..ca9a8fc295c67 100644 --- a/qa/smoke-test-http/src/test/java/org/opensearch/http/TestGetExecutionContextRestAction.java +++ b/qa/smoke-test-http/src/test/java/org/opensearch/http/TestGetExecutionContextRestAction.java @@ -9,13 +9,13 @@ package org.opensearch.http; import org.opensearch.client.node.NodeClient; +import org.opensearch.common.util.concurrent.ContextSwitcher; import org.opensearch.common.util.concurrent.ThreadContext; import org.opensearch.core.rest.RestStatus; import org.opensearch.rest.BaseRestHandler; import org.opensearch.rest.BytesRestResponse; import org.opensearch.rest.RestRequest; import org.opensearch.rest.RestResponse; -import org.opensearch.common.util.concurrent.ContextSwitcher; import org.opensearch.threadpool.ThreadPool; import java.util.List; diff --git a/server/src/internalClusterTest/java/org/opensearch/cluster/SimpleClusterStateIT.java b/server/src/internalClusterTest/java/org/opensearch/cluster/SimpleClusterStateIT.java index 1a5898f58d871..3f57ec9e421c8 100644 --- a/server/src/internalClusterTest/java/org/opensearch/cluster/SimpleClusterStateIT.java +++ b/server/src/internalClusterTest/java/org/opensearch/cluster/SimpleClusterStateIT.java @@ -471,7 +471,7 @@ public Collection createComponents( final NamedWriteableRegistry namedWriteableRegistry, final IndexNameExpressionResolver expressionResolver, final Supplier repositoriesServiceSupplier, - ContextSwitcher contextSwitcher + final ContextSwitcher contextSwitcher ) { clusterService.addListener(event -> { final ClusterState state = event.state(); diff --git a/server/src/internalClusterTest/java/org/opensearch/index/FinalPipelineIT.java b/server/src/internalClusterTest/java/org/opensearch/index/FinalPipelineIT.java index cff2992653f1c..2b6931c3ade4a 100644 --- a/server/src/internalClusterTest/java/org/opensearch/index/FinalPipelineIT.java +++ b/server/src/internalClusterTest/java/org/opensearch/index/FinalPipelineIT.java @@ -375,7 +375,7 @@ public Collection createComponents( final NamedWriteableRegistry namedWriteableRegistry, final IndexNameExpressionResolver expressionResolver, final Supplier repositoriesServiceSupplier, - ContextSwitcher contextSwitcher + final ContextSwitcher contextSwitcher ) { return Collections.emptyList(); } diff --git a/server/src/main/java/org/opensearch/client/OriginSettingClient.java b/server/src/main/java/org/opensearch/client/OriginSettingClient.java index 1b0e08cc489c4..58efbaaab1e9a 100644 --- a/server/src/main/java/org/opensearch/client/OriginSettingClient.java +++ b/server/src/main/java/org/opensearch/client/OriginSettingClient.java @@ -35,16 +35,20 @@ import org.opensearch.action.ActionRequest; import org.opensearch.action.ActionType; import org.opensearch.action.support.ContextPreservingActionListener; +import org.opensearch.common.util.concurrent.ContextSwitcher; +import org.opensearch.common.util.concurrent.InternalContextSwitcher; import org.opensearch.common.util.concurrent.ThreadContext; import org.opensearch.core.action.ActionListener; import org.opensearch.core.action.ActionResponse; import java.util.function.Supplier; +import static org.opensearch.common.util.concurrent.ThreadContext.ACTION_ORIGIN_TRANSIENT_NAME; + /** * A {@linkplain Client} that sends requests with the - * {@link ThreadContext#stashWithOrigin origin} set to a particular - * value and calls its {@linkplain ActionListener} in its original + * origin set to a particular value and calls its {@linkplain ActionListener} + * in its original * {@link ThreadContext}. * * @opensearch.internal @@ -52,10 +56,12 @@ public final class OriginSettingClient extends FilterClient { private final String origin; + private final ContextSwitcher contextSwitcher; public OriginSettingClient(Client in, String origin) { super(in); this.origin = origin; + this.contextSwitcher = new InternalContextSwitcher(in().threadPool()); } @Override @@ -65,7 +71,8 @@ protected void ActionListener listener ) { final Supplier supplier = in().threadPool().getThreadContext().newRestorableContext(false); - try (ThreadContext.StoredContext ignore = in().threadPool().getThreadContext().stashWithOrigin(origin)) { + try (ThreadContext.StoredContext ignore = contextSwitcher.switchContext()) { + in().threadPool().getThreadContext().putTransient(ACTION_ORIGIN_TRANSIENT_NAME, origin); super.doExecute(action, request, new ContextPreservingActionListener<>(supplier, listener)); } } diff --git a/server/src/main/java/org/opensearch/client/support/AbstractClient.java b/server/src/main/java/org/opensearch/client/support/AbstractClient.java index 6c6049f04231b..caee1658b16e6 100644 --- a/server/src/main/java/org/opensearch/client/support/AbstractClient.java +++ b/server/src/main/java/org/opensearch/client/support/AbstractClient.java @@ -415,6 +415,7 @@ import org.opensearch.common.Nullable; import org.opensearch.common.action.ActionFuture; import org.opensearch.common.settings.Settings; +import org.opensearch.common.util.concurrent.InternalContextSwitcher; import org.opensearch.common.util.concurrent.ThreadContext; import org.opensearch.core.action.ActionListener; import org.opensearch.core.action.ActionResponse; @@ -437,11 +438,13 @@ public abstract class AbstractClient implements Client { protected final Settings settings; private final ThreadPool threadPool; private final Admin admin; + private final InternalContextSwitcher contextSwitcher; public AbstractClient(Settings settings, ThreadPool threadPool) { this.settings = settings; this.threadPool = threadPool; this.admin = new Admin(this); + this.contextSwitcher = new InternalContextSwitcher(threadPool); this.logger = LogManager.getLogger(this.getClass()); } @@ -2147,8 +2150,7 @@ protected void Request request, ActionListener listener ) { - ThreadContext threadContext = threadPool().getThreadContext(); - try (ThreadContext.StoredContext ctx = threadContext.stashAndMergeHeaders(headers)) { + try (ThreadContext.StoredContext ctx = contextSwitcher.stashAndMergeHeaders(headers)) { super.doExecute(action, request, listener); } } diff --git a/server/src/main/java/org/opensearch/cluster/service/ClusterApplierService.java b/server/src/main/java/org/opensearch/cluster/service/ClusterApplierService.java index 4ef014bd08621..0bd84e8381afe 100644 --- a/server/src/main/java/org/opensearch/cluster/service/ClusterApplierService.java +++ b/server/src/main/java/org/opensearch/cluster/service/ClusterApplierService.java @@ -58,6 +58,7 @@ import org.opensearch.common.settings.Setting; import org.opensearch.common.settings.Settings; import org.opensearch.common.unit.TimeValue; +import org.opensearch.common.util.concurrent.ContextSwitcher; import org.opensearch.common.util.concurrent.InternalContextSwitcher; import org.opensearch.common.util.concurrent.OpenSearchExecutors; import org.opensearch.common.util.concurrent.PrioritizedOpenSearchThreadPoolExecutor; @@ -105,7 +106,7 @@ public class ClusterApplierService extends AbstractLifecycleComponent implements private final ClusterSettings clusterSettings; protected final ThreadPool threadPool; - protected final InternalContextSwitcher contextSwitcher; + protected final ContextSwitcher contextSwitcher; private volatile TimeValue slowTaskLoggingThreshold; diff --git a/server/src/main/java/org/opensearch/cluster/service/MasterService.java b/server/src/main/java/org/opensearch/cluster/service/MasterService.java index c515c3b13494a..036766f981b36 100644 --- a/server/src/main/java/org/opensearch/cluster/service/MasterService.java +++ b/server/src/main/java/org/opensearch/cluster/service/MasterService.java @@ -61,6 +61,7 @@ import org.opensearch.common.settings.Setting; import org.opensearch.common.settings.Settings; import org.opensearch.common.unit.TimeValue; +import org.opensearch.common.util.concurrent.ContextSwitcher; import org.opensearch.common.util.concurrent.CountDown; import org.opensearch.common.util.concurrent.FutureUtils; import org.opensearch.common.util.concurrent.InternalContextSwitcher; @@ -134,7 +135,7 @@ public class MasterService extends AbstractLifecycleComponent { private volatile TimeValue slowTaskLoggingThreshold; protected final ThreadPool threadPool; - protected final InternalContextSwitcher contextSwitcher; + protected final ContextSwitcher contextSwitcher; private volatile PrioritizedOpenSearchThreadPoolExecutor threadPoolExecutor; private volatile Batcher taskBatcher; diff --git a/server/src/main/java/org/opensearch/common/util/concurrent/ContextSwitcher.java b/server/src/main/java/org/opensearch/common/util/concurrent/ContextSwitcher.java index efa92dceb2124..c1976add3f05c 100644 --- a/server/src/main/java/org/opensearch/common/util/concurrent/ContextSwitcher.java +++ b/server/src/main/java/org/opensearch/common/util/concurrent/ContextSwitcher.java @@ -9,27 +9,13 @@ package org.opensearch.common.util.concurrent; import org.opensearch.common.annotation.PublicApi; -import org.opensearch.plugins.Plugin; -import org.opensearch.threadpool.ThreadPool; /** - * ContextSwitcher that is passed to plugins in order to switch to a fresh context - * from any existing context + * ContextSwitcher interface * * @opensearch.api */ @PublicApi(since = "2.17.0") -public class ContextSwitcher { - - private final ThreadPool threadPool; - private final Plugin plugin; - - public ContextSwitcher(ThreadPool threadPool, Plugin plugin) { - this.threadPool = threadPool; - this.plugin = plugin; - } - - public ThreadContext.StoredContext switchContext() { - return threadPool.getThreadContext().stashContext(plugin.getClass()); - } +public interface ContextSwitcher { + ThreadContext.StoredContext switchContext(); } diff --git a/server/src/main/java/org/opensearch/common/util/concurrent/InternalContextSwitcher.java b/server/src/main/java/org/opensearch/common/util/concurrent/InternalContextSwitcher.java index 47aeda6fc0f3c..162b13de52d56 100644 --- a/server/src/main/java/org/opensearch/common/util/concurrent/InternalContextSwitcher.java +++ b/server/src/main/java/org/opensearch/common/util/concurrent/InternalContextSwitcher.java @@ -11,6 +11,8 @@ import org.opensearch.common.annotation.InternalApi; import org.opensearch.threadpool.ThreadPool; +import java.util.Map; + /** * InternalContextSwitcher is an internal class used to switch into a fresh * internal system context @@ -18,14 +20,19 @@ * @opensearch.internal */ @InternalApi -public class InternalContextSwitcher { +public class InternalContextSwitcher implements ContextSwitcher { private final ThreadPool threadPool; public InternalContextSwitcher(ThreadPool threadPool) { this.threadPool = threadPool; } + @Override public ThreadContext.StoredContext switchContext() { return threadPool.getThreadContext().stashContext(); } + + public ThreadContext.StoredContext stashAndMergeHeaders(Map headers) { + return threadPool.getThreadContext().stashAndMergeHeaders(headers); + } } diff --git a/server/src/main/java/org/opensearch/common/util/concurrent/PluginContextSwitcher.java b/server/src/main/java/org/opensearch/common/util/concurrent/PluginContextSwitcher.java new file mode 100644 index 0000000000000..7a2c245a27cf2 --- /dev/null +++ b/server/src/main/java/org/opensearch/common/util/concurrent/PluginContextSwitcher.java @@ -0,0 +1,36 @@ +/* + * SPDX-License-Identifier: Apache-2.0 + * + * The OpenSearch Contributors require contributions made to + * this file be licensed under the Apache-2.0 license or a + * compatible open source license. + */ + +package org.opensearch.common.util.concurrent; + +import org.opensearch.common.annotation.PublicApi; +import org.opensearch.plugins.Plugin; +import org.opensearch.threadpool.ThreadPool; + +/** + * ContextSwitcher that is passed to plugins in order to switch to a fresh context + * from any existing context + * + * @opensearch.api + */ +@PublicApi(since = "2.17.0") +public class PluginContextSwitcher implements ContextSwitcher { + + private final ThreadPool threadPool; + private final Plugin plugin; + + public PluginContextSwitcher(ThreadPool threadPool, Plugin plugin) { + this.threadPool = threadPool; + this.plugin = plugin; + } + + @Override + public ThreadContext.StoredContext switchContext() { + return threadPool.getThreadContext().stashContext(plugin.getClass()); + } +} diff --git a/server/src/main/java/org/opensearch/common/util/concurrent/ThreadContext.java b/server/src/main/java/org/opensearch/common/util/concurrent/ThreadContext.java index 446459e7d62e8..3f03c8b57aeed 100644 --- a/server/src/main/java/org/opensearch/common/util/concurrent/ThreadContext.java +++ b/server/src/main/java/org/opensearch/common/util/concurrent/ThreadContext.java @@ -182,7 +182,7 @@ StoredContext stashContext() { * Removes the current context and resets a default context. Retains information about plugin stashing the context. * The removed context can be restored by closing the returned {@link StoredContext}. */ - public StoredContext stashContext(Class pluginClass) { + StoredContext stashContext(Class pluginClass) { final ThreadContextStruct context = threadLocal.get(); /* X-Opaque-ID should be preserved in a threadContext in order to propagate this across threads. @@ -246,7 +246,7 @@ public Writeable captureAsWriteable() { * but the tasks API will perform a get on their behalf using this method * if it can't find the task in memory. */ - public StoredContext stashWithOrigin(String origin) { + StoredContext stashWithOrigin(String origin) { final ThreadContext.StoredContext storedContext = stashContext(); putTransient(ACTION_ORIGIN_TRANSIENT_NAME, origin); return storedContext; @@ -257,7 +257,7 @@ public StoredContext stashWithOrigin(String origin) { * The removed context can be restored when closing the returned {@link StoredContext}. The merge strategy is that headers * that are already existing are preserved unless they are defaults. */ - public StoredContext stashAndMergeHeaders(Map headers) { + StoredContext stashAndMergeHeaders(Map headers) { final ThreadContextStruct context = threadLocal.get(); Map newHeader = new HashMap<>(headers); newHeader.putAll(context.requestHeaders); diff --git a/server/src/main/java/org/opensearch/http/AbstractHttpServerTransport.java b/server/src/main/java/org/opensearch/http/AbstractHttpServerTransport.java index c9386ad9c491b..712713f83023b 100644 --- a/server/src/main/java/org/opensearch/http/AbstractHttpServerTransport.java +++ b/server/src/main/java/org/opensearch/http/AbstractHttpServerTransport.java @@ -45,6 +45,7 @@ import org.opensearch.common.transport.NetworkExceptionHelper; import org.opensearch.common.transport.PortsRange; import org.opensearch.common.util.BigArrays; +import org.opensearch.common.util.concurrent.ContextSwitcher; import org.opensearch.common.util.concurrent.InternalContextSwitcher; import org.opensearch.common.util.concurrent.ThreadContext; import org.opensearch.core.action.ActionListener; @@ -100,7 +101,7 @@ public abstract class AbstractHttpServerTransport extends AbstractLifecycleCompo protected final NetworkService networkService; protected final BigArrays bigArrays; protected final ThreadPool threadPool; - protected final InternalContextSwitcher contextSwitcher; + protected final ContextSwitcher contextSwitcher; protected final Dispatcher dispatcher; protected final CorsHandler corsHandler; private final NamedXContentRegistry xContentRegistry; diff --git a/server/src/main/java/org/opensearch/index/seqno/GlobalCheckpointSyncAction.java b/server/src/main/java/org/opensearch/index/seqno/GlobalCheckpointSyncAction.java index eaf6d7c85220d..dcac7fac54def 100644 --- a/server/src/main/java/org/opensearch/index/seqno/GlobalCheckpointSyncAction.java +++ b/server/src/main/java/org/opensearch/index/seqno/GlobalCheckpointSyncAction.java @@ -43,6 +43,7 @@ import org.opensearch.cluster.service.ClusterService; import org.opensearch.common.inject.Inject; import org.opensearch.common.settings.Settings; +import org.opensearch.common.util.concurrent.ContextSwitcher; import org.opensearch.common.util.concurrent.InternalContextSwitcher; import org.opensearch.common.util.concurrent.ThreadContext; import org.opensearch.core.action.ActionListener; @@ -70,7 +71,7 @@ public class GlobalCheckpointSyncAction extends TransportReplicationAction< ReplicationResponse> { public static String ACTION_NAME = "indices:admin/seq_no/global_checkpoint_sync"; - private final InternalContextSwitcher contextSwitcher; + private final ContextSwitcher contextSwitcher; @Inject public GlobalCheckpointSyncAction( diff --git a/server/src/main/java/org/opensearch/index/seqno/RetentionLeaseBackgroundSyncAction.java b/server/src/main/java/org/opensearch/index/seqno/RetentionLeaseBackgroundSyncAction.java index 7506740fe84bf..9b3d984285621 100644 --- a/server/src/main/java/org/opensearch/index/seqno/RetentionLeaseBackgroundSyncAction.java +++ b/server/src/main/java/org/opensearch/index/seqno/RetentionLeaseBackgroundSyncAction.java @@ -47,6 +47,7 @@ import org.opensearch.cluster.service.ClusterService; import org.opensearch.common.inject.Inject; import org.opensearch.common.settings.Settings; +import org.opensearch.common.util.concurrent.ContextSwitcher; import org.opensearch.common.util.concurrent.InternalContextSwitcher; import org.opensearch.common.util.concurrent.ThreadContext; import org.opensearch.core.action.ActionListener; @@ -85,7 +86,7 @@ public class RetentionLeaseBackgroundSyncAction extends TransportReplicationActi public static final String ACTION_NAME = "indices:admin/seq_no/retention_lease_background_sync"; private static final Logger LOGGER = LogManager.getLogger(RetentionLeaseSyncAction.class); - private final InternalContextSwitcher contextSwitcher; + private final ContextSwitcher contextSwitcher; protected Logger getLogger() { return LOGGER; diff --git a/server/src/main/java/org/opensearch/index/shard/RefreshListeners.java b/server/src/main/java/org/opensearch/index/shard/RefreshListeners.java index 9d99c749832aa..ef4b9f33b786c 100644 --- a/server/src/main/java/org/opensearch/index/shard/RefreshListeners.java +++ b/server/src/main/java/org/opensearch/index/shard/RefreshListeners.java @@ -37,6 +37,7 @@ import org.opensearch.common.collect.Tuple; import org.opensearch.common.lease.Releasable; import org.opensearch.common.metrics.MeanMetric; +import org.opensearch.common.util.concurrent.ContextSwitcher; import org.opensearch.common.util.concurrent.InternalContextSwitcher; import org.opensearch.common.util.concurrent.RunOnce; import org.opensearch.common.util.concurrent.ThreadContext; @@ -66,7 +67,7 @@ public final class RefreshListeners implements ReferenceManager.RefreshListener, private final Runnable forceRefresh; private final Logger logger; private final ThreadPool threadPool; - private final InternalContextSwitcher contextSwitcher; + private final ContextSwitcher contextSwitcher; private final MeanMetric refreshMetric; /** diff --git a/server/src/main/java/org/opensearch/indices/replication/checkpoint/PublishCheckpointAction.java b/server/src/main/java/org/opensearch/indices/replication/checkpoint/PublishCheckpointAction.java index 551fcf2b18b87..03b7c048c66da 100644 --- a/server/src/main/java/org/opensearch/indices/replication/checkpoint/PublishCheckpointAction.java +++ b/server/src/main/java/org/opensearch/indices/replication/checkpoint/PublishCheckpointAction.java @@ -23,6 +23,7 @@ import org.opensearch.common.annotation.PublicApi; import org.opensearch.common.inject.Inject; import org.opensearch.common.settings.Settings; +import org.opensearch.common.util.concurrent.ContextSwitcher; import org.opensearch.common.util.concurrent.InternalContextSwitcher; import org.opensearch.common.util.concurrent.ThreadContext; import org.opensearch.core.action.ActionListener; @@ -59,7 +60,7 @@ public class PublishCheckpointAction extends TransportReplicationAction< protected static Logger logger = LogManager.getLogger(PublishCheckpointAction.class); private final SegmentReplicationTargetService replicationService; - private final InternalContextSwitcher contextSwitcher; + private final ContextSwitcher contextSwitcher; @Inject public PublishCheckpointAction( diff --git a/server/src/main/java/org/opensearch/node/Node.java b/server/src/main/java/org/opensearch/node/Node.java index 9b04d7d16bec7..a8873aceff3b0 100644 --- a/server/src/main/java/org/opensearch/node/Node.java +++ b/server/src/main/java/org/opensearch/node/Node.java @@ -115,6 +115,7 @@ import org.opensearch.common.util.FeatureFlags; import org.opensearch.common.util.PageCacheRecycler; import org.opensearch.common.util.concurrent.ContextSwitcher; +import org.opensearch.common.util.concurrent.PluginContextSwitcher; import org.opensearch.common.util.io.IOUtils; import org.opensearch.core.Assertions; import org.opensearch.core.common.breaker.CircuitBreaker; @@ -932,7 +933,7 @@ protected Node( final ViewService viewService = new ViewService(clusterService, client, null); Collection pluginComponents = pluginsService.filterPlugins(Plugin.class).stream().flatMap(p -> { - ContextSwitcher contextSwitcher = new ContextSwitcher(threadPool, p); + ContextSwitcher contextSwitcher = new PluginContextSwitcher(threadPool, p); return p.createComponents( client, clusterService, @@ -952,7 +953,7 @@ protected Node( Collection telemetryAwarePluginComponents = pluginsService.filterPlugins(TelemetryAwarePlugin.class) .stream() .flatMap(p -> { - ContextSwitcher contextSwitcher = new ContextSwitcher(threadPool, (Plugin) p); + ContextSwitcher contextSwitcher = new PluginContextSwitcher(threadPool, (Plugin) p); return p.createComponents( client, clusterService, diff --git a/server/src/main/java/org/opensearch/transport/NativeMessageHandler.java b/server/src/main/java/org/opensearch/transport/NativeMessageHandler.java index fb90e6761df76..835734974ca63 100644 --- a/server/src/main/java/org/opensearch/transport/NativeMessageHandler.java +++ b/server/src/main/java/org/opensearch/transport/NativeMessageHandler.java @@ -39,6 +39,7 @@ import org.opensearch.Version; import org.opensearch.common.util.BigArrays; import org.opensearch.common.util.concurrent.AbstractRunnable; +import org.opensearch.common.util.concurrent.ContextSwitcher; import org.opensearch.common.util.concurrent.InternalContextSwitcher; import org.opensearch.common.util.concurrent.ThreadContext; import org.opensearch.core.common.io.stream.ByteBufferStreamInput; @@ -75,7 +76,7 @@ public class NativeMessageHandler implements ProtocolMessageHandler { private static final Logger logger = LogManager.getLogger(NativeMessageHandler.class); private final ThreadPool threadPool; - private final InternalContextSwitcher contextSwitcher; + private final ContextSwitcher contextSwitcher; private final NativeOutboundHandler outboundHandler; private final NamedWriteableRegistry namedWriteableRegistry; private final TransportHandshaker handshaker; diff --git a/server/src/main/java/org/opensearch/transport/OutboundHandler.java b/server/src/main/java/org/opensearch/transport/OutboundHandler.java index 837f65b12e7b2..8ab283fbbef8f 100644 --- a/server/src/main/java/org/opensearch/transport/OutboundHandler.java +++ b/server/src/main/java/org/opensearch/transport/OutboundHandler.java @@ -40,6 +40,7 @@ import org.opensearch.common.lease.Releasables; import org.opensearch.common.network.CloseableChannel; import org.opensearch.common.transport.NetworkExceptionHelper; +import org.opensearch.common.util.concurrent.ContextSwitcher; import org.opensearch.common.util.concurrent.InternalContextSwitcher; import org.opensearch.common.util.concurrent.ThreadContext; import org.opensearch.core.action.ActionListener; @@ -60,7 +61,7 @@ public final class OutboundHandler { private final StatsTracker statsTracker; private final ThreadPool threadPool; - private final InternalContextSwitcher contextSwitcher; + private final ContextSwitcher contextSwitcher; public OutboundHandler(StatsTracker statsTracker, ThreadPool threadPool) { this.statsTracker = statsTracker; diff --git a/server/src/main/java/org/opensearch/transport/RemoteClusterConnection.java b/server/src/main/java/org/opensearch/transport/RemoteClusterConnection.java index 559a8bd48c26a..f27ab8132f26c 100644 --- a/server/src/main/java/org/opensearch/transport/RemoteClusterConnection.java +++ b/server/src/main/java/org/opensearch/transport/RemoteClusterConnection.java @@ -39,6 +39,7 @@ import org.opensearch.cluster.node.DiscoveryNodes; import org.opensearch.common.settings.Settings; import org.opensearch.common.unit.TimeValue; +import org.opensearch.common.util.concurrent.ContextSwitcher; import org.opensearch.common.util.concurrent.InternalContextSwitcher; import org.opensearch.common.util.concurrent.ThreadContext; import org.opensearch.common.util.io.IOUtils; @@ -72,7 +73,7 @@ final class RemoteClusterConnection implements Closeable { private final RemoteConnectionStrategy connectionStrategy; private final String clusterAlias; private final ThreadPool threadPool; - private final InternalContextSwitcher contextSwitcher; + private final ContextSwitcher contextSwitcher; private volatile boolean skipUnavailable; private final TimeValue initialConnectionTimeout; diff --git a/server/src/main/java/org/opensearch/transport/SniffConnectionStrategy.java b/server/src/main/java/org/opensearch/transport/SniffConnectionStrategy.java index 915235d4825a7..57b44d9dd4ccd 100644 --- a/server/src/main/java/org/opensearch/transport/SniffConnectionStrategy.java +++ b/server/src/main/java/org/opensearch/transport/SniffConnectionStrategy.java @@ -46,6 +46,7 @@ import org.opensearch.common.UUIDs; import org.opensearch.common.settings.Setting; import org.opensearch.common.settings.Settings; +import org.opensearch.common.util.concurrent.ContextSwitcher; import org.opensearch.common.util.concurrent.InternalContextSwitcher; import org.opensearch.common.util.concurrent.ThreadContext; import org.opensearch.common.util.io.IOUtils; @@ -150,7 +151,7 @@ public class SniffConnectionStrategy extends RemoteConnectionStrategy { private final Predicate nodePredicate; private final SetOnce remoteClusterName = new SetOnce<>(); private final String proxyAddress; - private final InternalContextSwitcher contextSwitcher; + private final ContextSwitcher contextSwitcher; SniffConnectionStrategy( String clusterAlias, diff --git a/server/src/test/java/org/opensearch/action/bulk/BulkProcessorTests.java b/server/src/test/java/org/opensearch/action/bulk/BulkProcessorTests.java index 648c97da5fb65..31585d2b7a134 100644 --- a/server/src/test/java/org/opensearch/action/bulk/BulkProcessorTests.java +++ b/server/src/test/java/org/opensearch/action/bulk/BulkProcessorTests.java @@ -37,6 +37,7 @@ import org.opensearch.ExceptionsHelper; import org.opensearch.action.index.IndexRequest; import org.opensearch.common.unit.TimeValue; +import org.opensearch.common.util.concurrent.ContextSwitcher; import org.opensearch.common.util.concurrent.InternalContextSwitcher; import org.opensearch.common.util.concurrent.ThreadContext; import org.opensearch.core.action.ActionListener; @@ -69,7 +70,7 @@ public class BulkProcessorTests extends OpenSearchTestCase { private ThreadPool threadPool; - private InternalContextSwitcher contextSwitcher; + private ContextSwitcher contextSwitcher; private final Logger logger = LogManager.getLogger(BulkProcessorTests.class); @Before diff --git a/server/src/test/java/org/opensearch/action/support/ContextPreservingActionListenerTests.java b/server/src/test/java/org/opensearch/action/support/ContextPreservingActionListenerTests.java index 7e283be59fdf6..f93f66c3aec40 100644 --- a/server/src/test/java/org/opensearch/action/support/ContextPreservingActionListenerTests.java +++ b/server/src/test/java/org/opensearch/action/support/ContextPreservingActionListenerTests.java @@ -31,6 +31,7 @@ package org.opensearch.action.support; +import org.opensearch.common.util.concurrent.ContextSwitcher; import org.opensearch.common.util.concurrent.InternalContextSwitcher; import org.opensearch.common.util.concurrent.ThreadContext; import org.opensearch.core.action.ActionListener; @@ -48,7 +49,7 @@ public class ContextPreservingActionListenerTests extends OpenSearchTestCase { public void testOriginalContextIsPreservedAfterOnResponse() throws IOException { ThreadPool threadPool = new TestThreadPool("ContextPreservingActionListenerTests.testOriginalContextIsPreservedAfterOnResponse"); ThreadContext threadContext = threadPool.getThreadContext(); - InternalContextSwitcher contextSwitcher = new InternalContextSwitcher(threadPool); + ContextSwitcher contextSwitcher = new InternalContextSwitcher(threadPool); final boolean nonEmptyContext = randomBoolean(); if (nonEmptyContext) { threadContext.putHeader("not empty", "value"); @@ -87,7 +88,7 @@ public void onFailure(Exception e) { public void testOriginalContextIsPreservedAfterOnFailure() throws Exception { ThreadPool threadPool = new TestThreadPool("ContextPreservingActionListenerTests.testOriginalContextIsPreservedAfterOnFailure"); ThreadContext threadContext = threadPool.getThreadContext(); - InternalContextSwitcher contextSwitcher = new InternalContextSwitcher(threadPool); + ContextSwitcher contextSwitcher = new InternalContextSwitcher(threadPool); final boolean nonEmptyContext = randomBoolean(); if (nonEmptyContext) { threadContext.putHeader("not empty", "value"); @@ -128,7 +129,7 @@ public void onFailure(Exception e) { public void testOriginalContextIsWhenListenerThrows() throws Exception { ThreadPool threadPool = new TestThreadPool("ContextPreservingActionListenerTests.testOriginalContextIsWhenListenerThrows"); ThreadContext threadContext = threadPool.getThreadContext(); - InternalContextSwitcher contextSwitcher = new InternalContextSwitcher(threadPool); + ContextSwitcher contextSwitcher = new InternalContextSwitcher(threadPool); final boolean nonEmptyContext = randomBoolean(); if (nonEmptyContext) { threadContext.putHeader("not empty", "value"); @@ -178,7 +179,7 @@ public void onFailure(Exception e) { public void testToStringIncludesDelegate() { ThreadPool threadPool = new TestThreadPool("ContextPreservingActionListenerTests.testToStringIncludesDelegate"); ThreadContext threadContext = threadPool.getThreadContext(); - InternalContextSwitcher contextSwitcher = new InternalContextSwitcher(threadPool); + ContextSwitcher contextSwitcher = new InternalContextSwitcher(threadPool); final ContextPreservingActionListener actionListener; try (ThreadContext.StoredContext ignore = contextSwitcher.switchContext()) { final ActionListener delegate = new ActionListener() { diff --git a/server/src/test/java/org/opensearch/cluster/metadata/TemplateUpgradeServiceTests.java b/server/src/test/java/org/opensearch/cluster/metadata/TemplateUpgradeServiceTests.java index 5935dd0544615..bd61596084374 100644 --- a/server/src/test/java/org/opensearch/cluster/metadata/TemplateUpgradeServiceTests.java +++ b/server/src/test/java/org/opensearch/cluster/metadata/TemplateUpgradeServiceTests.java @@ -46,6 +46,7 @@ import org.opensearch.cluster.node.DiscoveryNodes; import org.opensearch.cluster.service.ClusterService; import org.opensearch.common.collect.Tuple; +import org.opensearch.common.util.concurrent.ContextSwitcher; import org.opensearch.common.util.concurrent.InternalContextSwitcher; import org.opensearch.common.util.concurrent.ThreadContext; import org.opensearch.core.action.ActionListener; @@ -91,7 +92,7 @@ public class TemplateUpgradeServiceTests extends OpenSearchTestCase { private ThreadPool threadPool; private ClusterService clusterService; - private InternalContextSwitcher contextSwitcher; + private ContextSwitcher contextSwitcher; @Before public void setUpTest() throws Exception { diff --git a/server/src/test/java/org/opensearch/cluster/service/ClusterApplierServiceTests.java b/server/src/test/java/org/opensearch/cluster/service/ClusterApplierServiceTests.java index 475c2f12fcc7f..8de8099b9ffd1 100644 --- a/server/src/test/java/org/opensearch/cluster/service/ClusterApplierServiceTests.java +++ b/server/src/test/java/org/opensearch/cluster/service/ClusterApplierServiceTests.java @@ -51,6 +51,7 @@ import org.opensearch.common.settings.ClusterSettings; import org.opensearch.common.settings.Settings; import org.opensearch.common.unit.TimeValue; +import org.opensearch.common.util.concurrent.ContextSwitcher; import org.opensearch.common.util.concurrent.InternalContextSwitcher; import org.opensearch.common.util.concurrent.ThreadContext; import org.opensearch.telemetry.metrics.Histogram; @@ -92,7 +93,7 @@ public class ClusterApplierServiceTests extends OpenSearchTestCase { private static ThreadPool threadPool; - private static InternalContextSwitcher contextSwitcher; + private static ContextSwitcher contextSwitcher; private TimedClusterApplierService clusterApplierService; private static MetricsRegistry metricsRegistry; private static Histogram applierslatencyHistogram; diff --git a/server/src/test/java/org/opensearch/cluster/service/MasterServiceTests.java b/server/src/test/java/org/opensearch/cluster/service/MasterServiceTests.java index 846990d32c97b..41b0ef955fef4 100644 --- a/server/src/test/java/org/opensearch/cluster/service/MasterServiceTests.java +++ b/server/src/test/java/org/opensearch/cluster/service/MasterServiceTests.java @@ -60,6 +60,7 @@ import org.opensearch.common.settings.Settings; import org.opensearch.common.unit.TimeValue; import org.opensearch.common.util.concurrent.BaseFuture; +import org.opensearch.common.util.concurrent.ContextSwitcher; import org.opensearch.common.util.concurrent.InternalContextSwitcher; import org.opensearch.common.util.concurrent.ThreadContext; import org.opensearch.node.Node; @@ -112,7 +113,7 @@ public class MasterServiceTests extends OpenSearchTestCase { private static ThreadPool threadPool; - private static InternalContextSwitcher contextSwitcher; + private static ContextSwitcher contextSwitcher; private static long timeDiffInMillis; @BeforeClass diff --git a/server/src/test/java/org/opensearch/index/shard/RefreshListenersTests.java b/server/src/test/java/org/opensearch/index/shard/RefreshListenersTests.java index 226bc88cddb9c..d5add99741080 100644 --- a/server/src/test/java/org/opensearch/index/shard/RefreshListenersTests.java +++ b/server/src/test/java/org/opensearch/index/shard/RefreshListenersTests.java @@ -49,6 +49,7 @@ import org.opensearch.common.settings.Settings; import org.opensearch.common.unit.TimeValue; import org.opensearch.common.util.BigArrays; +import org.opensearch.common.util.concurrent.ContextSwitcher; import org.opensearch.common.util.concurrent.InternalContextSwitcher; import org.opensearch.common.util.concurrent.ThreadContext; import org.opensearch.common.util.io.IOUtils; @@ -106,7 +107,7 @@ public class RefreshListenersTests extends OpenSearchTestCase { private Engine engine; private volatile int maxListeners; private ThreadPool threadPool; - private InternalContextSwitcher contextSwitcher; + private ContextSwitcher contextSwitcher; private Store store; private MeanMetric refreshMetric; diff --git a/server/src/test/java/org/opensearch/telemetry/tracing/ThreadContextBasedTracerContextStorageTests.java b/server/src/test/java/org/opensearch/telemetry/tracing/ThreadContextBasedTracerContextStorageTests.java index bfd43c8804fd4..339c85084fb41 100644 --- a/server/src/test/java/org/opensearch/telemetry/tracing/ThreadContextBasedTracerContextStorageTests.java +++ b/server/src/test/java/org/opensearch/telemetry/tracing/ThreadContextBasedTracerContextStorageTests.java @@ -10,6 +10,7 @@ import org.opensearch.common.settings.ClusterSettings; import org.opensearch.common.settings.Settings; +import org.opensearch.common.util.concurrent.ContextSwitcher; import org.opensearch.common.util.concurrent.InternalContextSwitcher; import org.opensearch.common.util.concurrent.ThreadContext; import org.opensearch.common.util.concurrent.ThreadContext.StoredContext; @@ -43,7 +44,7 @@ public class ThreadContextBasedTracerContextStorageTests extends OpenSearchTestCase { private Tracer tracer; private ThreadPool threadPool; - private InternalContextSwitcher contextSwitcher; + private ContextSwitcher contextSwitcher; private ThreadContext threadContext; private TracerContextStorage threadContextStorage; private ExecutorService executorService; diff --git a/test/framework/src/main/java/org/opensearch/cluster/service/FakeThreadPoolClusterManagerService.java b/test/framework/src/main/java/org/opensearch/cluster/service/FakeThreadPoolClusterManagerService.java index cf20c34cca660..0575790a508f4 100644 --- a/test/framework/src/main/java/org/opensearch/cluster/service/FakeThreadPoolClusterManagerService.java +++ b/test/framework/src/main/java/org/opensearch/cluster/service/FakeThreadPoolClusterManagerService.java @@ -41,6 +41,7 @@ import org.opensearch.common.settings.ClusterSettings; import org.opensearch.common.settings.Settings; import org.opensearch.common.unit.TimeValue; +import org.opensearch.common.util.concurrent.ContextSwitcher; import org.opensearch.common.util.concurrent.InternalContextSwitcher; import org.opensearch.common.util.concurrent.OpenSearchExecutors; import org.opensearch.common.util.concurrent.PrioritizedOpenSearchThreadPoolExecutor; @@ -64,7 +65,7 @@ public class FakeThreadPoolClusterManagerService extends ClusterManagerService { private final String name; private final List pendingTasks = new ArrayList<>(); private final Consumer onTaskAvailableToRun; - private final InternalContextSwitcher contextSwitcher; + private final ContextSwitcher contextSwitcher; private boolean scheduledNextTask = false; private boolean taskInProgress = false; private boolean waitForPublish = false; diff --git a/test/framework/src/main/java/org/opensearch/common/util/concurrent/TestContextSwitcher.java b/test/framework/src/main/java/org/opensearch/common/util/concurrent/TestContextSwitcher.java new file mode 100644 index 0000000000000..6e0ffb610d202 --- /dev/null +++ b/test/framework/src/main/java/org/opensearch/common/util/concurrent/TestContextSwitcher.java @@ -0,0 +1,29 @@ +/* + * SPDX-License-Identifier: Apache-2.0 + * + * The OpenSearch Contributors require contributions made to + * this file be licensed under the Apache-2.0 license or a + * compatible open source license. + */ + +package org.opensearch.common.util.concurrent; + +import org.opensearch.threadpool.ThreadPool; + +/** + * Test Context Switcher + */ +public class TestContextSwitcher implements ContextSwitcher { + private final ThreadPool threadPool; + private final Class pluginClass; + + public TestContextSwitcher(ThreadPool threadPool, Class pluginClass) { + this.threadPool = threadPool; + this.pluginClass = pluginClass; + } + + @Override + public ThreadContext.StoredContext switchContext() { + return threadPool.getThreadContext().stashContext(pluginClass); + } +} From ed7124739f1517c68bb57292c639a8fd2003f4ce Mon Sep 17 00:00:00 2001 From: Craig Perkins Date: Tue, 23 Jul 2024 16:21:27 -0400 Subject: [PATCH 18/65] Make markAsSystemContext package-private Signed-off-by: Craig Perkins --- .../org/opensearch/client/OriginSettingClient.java | 4 ++-- .../opensearch/client/support/AbstractClient.java | 6 +++--- .../cluster/service/ClusterApplierService.java | 5 ++--- .../opensearch/cluster/service/MasterService.java | 5 ++--- ...extSwitcher.java => SystemContextSwitcher.java} | 4 ++-- .../common/util/concurrent/ThreadContext.java | 3 ++- .../http/AbstractHttpServerTransport.java | 4 ++-- .../index/seqno/GlobalCheckpointSyncAction.java | 6 ++---- .../seqno/RetentionLeaseBackgroundSyncAction.java | 7 ++----- .../index/seqno/RetentionLeaseSyncAction.java | 9 +++------ .../opensearch/index/shard/RefreshListeners.java | 4 ++-- .../checkpoint/PublishCheckpointAction.java | 7 ++----- .../opensearch/transport/NativeMessageHandler.java | 4 ++-- .../org/opensearch/transport/OutboundHandler.java | 4 ++-- .../transport/RemoteClusterConnection.java | 6 ++---- .../transport/SniffConnectionStrategy.java | 7 ++----- .../opensearch/action/bulk/BulkProcessorTests.java | 4 ++-- .../ContextPreservingActionListenerTests.java | 10 +++++----- .../metadata/TemplateUpgradeServiceTests.java | 6 ++---- .../service/ClusterApplierServiceTests.java | 4 ++-- .../cluster/service/MasterServiceTests.java | 4 ++-- .../common/util/concurrent/ThreadContextTests.java | 14 +++----------- .../index/shard/RefreshListenersTests.java | 4 ++-- .../test/java/org/opensearch/node/NodeTests.java | 4 +++- ...hreadContextBasedTracerContextStorageTests.java | 9 +++++---- .../FakeThreadPoolClusterManagerService.java | 6 ++---- 26 files changed, 62 insertions(+), 88 deletions(-) rename server/src/main/java/org/opensearch/common/util/concurrent/{InternalContextSwitcher.java => SystemContextSwitcher.java} (88%) diff --git a/server/src/main/java/org/opensearch/client/OriginSettingClient.java b/server/src/main/java/org/opensearch/client/OriginSettingClient.java index 58efbaaab1e9a..073e92122ef8e 100644 --- a/server/src/main/java/org/opensearch/client/OriginSettingClient.java +++ b/server/src/main/java/org/opensearch/client/OriginSettingClient.java @@ -36,7 +36,7 @@ import org.opensearch.action.ActionType; import org.opensearch.action.support.ContextPreservingActionListener; import org.opensearch.common.util.concurrent.ContextSwitcher; -import org.opensearch.common.util.concurrent.InternalContextSwitcher; +import org.opensearch.common.util.concurrent.SystemContextSwitcher; import org.opensearch.common.util.concurrent.ThreadContext; import org.opensearch.core.action.ActionListener; import org.opensearch.core.action.ActionResponse; @@ -61,7 +61,7 @@ public final class OriginSettingClient extends FilterClient { public OriginSettingClient(Client in, String origin) { super(in); this.origin = origin; - this.contextSwitcher = new InternalContextSwitcher(in().threadPool()); + this.contextSwitcher = new SystemContextSwitcher(in().threadPool()); } @Override diff --git a/server/src/main/java/org/opensearch/client/support/AbstractClient.java b/server/src/main/java/org/opensearch/client/support/AbstractClient.java index caee1658b16e6..6fcad9c5e95ad 100644 --- a/server/src/main/java/org/opensearch/client/support/AbstractClient.java +++ b/server/src/main/java/org/opensearch/client/support/AbstractClient.java @@ -415,7 +415,7 @@ import org.opensearch.common.Nullable; import org.opensearch.common.action.ActionFuture; import org.opensearch.common.settings.Settings; -import org.opensearch.common.util.concurrent.InternalContextSwitcher; +import org.opensearch.common.util.concurrent.SystemContextSwitcher; import org.opensearch.common.util.concurrent.ThreadContext; import org.opensearch.core.action.ActionListener; import org.opensearch.core.action.ActionResponse; @@ -438,13 +438,13 @@ public abstract class AbstractClient implements Client { protected final Settings settings; private final ThreadPool threadPool; private final Admin admin; - private final InternalContextSwitcher contextSwitcher; + private final SystemContextSwitcher contextSwitcher; public AbstractClient(Settings settings, ThreadPool threadPool) { this.settings = settings; this.threadPool = threadPool; this.admin = new Admin(this); - this.contextSwitcher = new InternalContextSwitcher(threadPool); + this.contextSwitcher = new SystemContextSwitcher(threadPool); this.logger = LogManager.getLogger(this.getClass()); } diff --git a/server/src/main/java/org/opensearch/cluster/service/ClusterApplierService.java b/server/src/main/java/org/opensearch/cluster/service/ClusterApplierService.java index 0bd84e8381afe..d5c65a23507a8 100644 --- a/server/src/main/java/org/opensearch/cluster/service/ClusterApplierService.java +++ b/server/src/main/java/org/opensearch/cluster/service/ClusterApplierService.java @@ -59,9 +59,9 @@ import org.opensearch.common.settings.Settings; import org.opensearch.common.unit.TimeValue; import org.opensearch.common.util.concurrent.ContextSwitcher; -import org.opensearch.common.util.concurrent.InternalContextSwitcher; import org.opensearch.common.util.concurrent.OpenSearchExecutors; import org.opensearch.common.util.concurrent.PrioritizedOpenSearchThreadPoolExecutor; +import org.opensearch.common.util.concurrent.SystemContextSwitcher; import org.opensearch.common.util.concurrent.ThreadContext; import org.opensearch.core.concurrency.OpenSearchRejectedExecutionException; import org.opensearch.telemetry.metrics.noop.NoopMetricsRegistry; @@ -142,7 +142,7 @@ public ClusterApplierService( ) { this.clusterSettings = clusterSettings; this.threadPool = threadPool; - this.contextSwitcher = new InternalContextSwitcher(threadPool); + this.contextSwitcher = new SystemContextSwitcher(threadPool); this.state = new AtomicReference<>(); this.nodeName = nodeName; @@ -400,7 +400,6 @@ private void submitStateUpdateTask( final ThreadContext threadContext = threadPool.getThreadContext(); final Supplier supplier = threadContext.newRestorableContext(true); try (ThreadContext.StoredContext ignore = contextSwitcher.switchContext()) { - threadContext.markAsSystemContext(); final UpdateTask updateTask = new UpdateTask( config.priority(), source, diff --git a/server/src/main/java/org/opensearch/cluster/service/MasterService.java b/server/src/main/java/org/opensearch/cluster/service/MasterService.java index 036766f981b36..bbeb0cc4b8f88 100644 --- a/server/src/main/java/org/opensearch/cluster/service/MasterService.java +++ b/server/src/main/java/org/opensearch/cluster/service/MasterService.java @@ -64,9 +64,9 @@ import org.opensearch.common.util.concurrent.ContextSwitcher; import org.opensearch.common.util.concurrent.CountDown; import org.opensearch.common.util.concurrent.FutureUtils; -import org.opensearch.common.util.concurrent.InternalContextSwitcher; import org.opensearch.common.util.concurrent.OpenSearchExecutors; import org.opensearch.common.util.concurrent.PrioritizedOpenSearchThreadPoolExecutor; +import org.opensearch.common.util.concurrent.SystemContextSwitcher; import org.opensearch.common.util.concurrent.ThreadContext; import org.opensearch.core.Assertions; import org.opensearch.core.common.text.Text; @@ -171,7 +171,7 @@ public MasterService( ); this.stateStats = new ClusterStateStats(); this.threadPool = threadPool; - this.contextSwitcher = new InternalContextSwitcher(threadPool); + this.contextSwitcher = new SystemContextSwitcher(threadPool); this.clusterManagerMetrics = clusterManagerMetrics; } @@ -1013,7 +1013,6 @@ public void submitStateUpdateTasks( final ThreadContext threadContext = threadPool.getThreadContext(); final Supplier supplier = threadContext.newRestorableContext(true); try (ThreadContext.StoredContext ignore = contextSwitcher.switchContext()) { - threadContext.markAsSystemContext(); List safeTasks = tasks.entrySet() .stream() diff --git a/server/src/main/java/org/opensearch/common/util/concurrent/InternalContextSwitcher.java b/server/src/main/java/org/opensearch/common/util/concurrent/SystemContextSwitcher.java similarity index 88% rename from server/src/main/java/org/opensearch/common/util/concurrent/InternalContextSwitcher.java rename to server/src/main/java/org/opensearch/common/util/concurrent/SystemContextSwitcher.java index 162b13de52d56..363f0900ea294 100644 --- a/server/src/main/java/org/opensearch/common/util/concurrent/InternalContextSwitcher.java +++ b/server/src/main/java/org/opensearch/common/util/concurrent/SystemContextSwitcher.java @@ -20,10 +20,10 @@ * @opensearch.internal */ @InternalApi -public class InternalContextSwitcher implements ContextSwitcher { +public class SystemContextSwitcher implements ContextSwitcher { private final ThreadPool threadPool; - public InternalContextSwitcher(ThreadPool threadPool) { + public SystemContextSwitcher(ThreadPool threadPool) { this.threadPool = threadPool; } diff --git a/server/src/main/java/org/opensearch/common/util/concurrent/ThreadContext.java b/server/src/main/java/org/opensearch/common/util/concurrent/ThreadContext.java index 3f03c8b57aeed..af7bfbe3c8c8e 100644 --- a/server/src/main/java/org/opensearch/common/util/concurrent/ThreadContext.java +++ b/server/src/main/java/org/opensearch/common/util/concurrent/ThreadContext.java @@ -154,6 +154,7 @@ StoredContext stashContext() { */ ThreadContextStruct threadContextStruct = DEFAULT_CONTEXT.putPersistent(context.persistentHeaders); + threadContextStruct.setSystemContext(propagators); if (context.requestHeaders.containsKey(Task.X_OPAQUE_ID)) { threadContextStruct = threadContextStruct.putHeaders( @@ -595,7 +596,7 @@ boolean isDefaultContext() { * Marks this thread context as an internal system context. This signals that actions in this context are issued * by the system itself rather than by a user action. */ - public void markAsSystemContext() { + void markAsSystemContext() { threadLocal.set(threadLocal.get().setSystemContext(propagators)); } diff --git a/server/src/main/java/org/opensearch/http/AbstractHttpServerTransport.java b/server/src/main/java/org/opensearch/http/AbstractHttpServerTransport.java index 712713f83023b..c4b53fb048211 100644 --- a/server/src/main/java/org/opensearch/http/AbstractHttpServerTransport.java +++ b/server/src/main/java/org/opensearch/http/AbstractHttpServerTransport.java @@ -46,7 +46,7 @@ import org.opensearch.common.transport.PortsRange; import org.opensearch.common.util.BigArrays; import org.opensearch.common.util.concurrent.ContextSwitcher; -import org.opensearch.common.util.concurrent.InternalContextSwitcher; +import org.opensearch.common.util.concurrent.SystemContextSwitcher; import org.opensearch.common.util.concurrent.ThreadContext; import org.opensearch.core.action.ActionListener; import org.opensearch.core.common.Strings; @@ -133,7 +133,7 @@ protected AbstractHttpServerTransport( this.networkService = networkService; this.bigArrays = bigArrays; this.threadPool = threadPool; - this.contextSwitcher = new InternalContextSwitcher(threadPool); + this.contextSwitcher = new SystemContextSwitcher(threadPool); this.xContentRegistry = xContentRegistry; this.dispatcher = dispatcher; this.handlingSettings = HttpHandlingSettings.fromSettings(settings); diff --git a/server/src/main/java/org/opensearch/index/seqno/GlobalCheckpointSyncAction.java b/server/src/main/java/org/opensearch/index/seqno/GlobalCheckpointSyncAction.java index dcac7fac54def..8f077050bbcb8 100644 --- a/server/src/main/java/org/opensearch/index/seqno/GlobalCheckpointSyncAction.java +++ b/server/src/main/java/org/opensearch/index/seqno/GlobalCheckpointSyncAction.java @@ -44,7 +44,7 @@ import org.opensearch.common.inject.Inject; import org.opensearch.common.settings.Settings; import org.opensearch.common.util.concurrent.ContextSwitcher; -import org.opensearch.common.util.concurrent.InternalContextSwitcher; +import org.opensearch.common.util.concurrent.SystemContextSwitcher; import org.opensearch.common.util.concurrent.ThreadContext; import org.opensearch.core.action.ActionListener; import org.opensearch.core.common.io.stream.StreamInput; @@ -96,13 +96,11 @@ public GlobalCheckpointSyncAction( Request::new, ThreadPool.Names.MANAGEMENT ); - this.contextSwitcher = new InternalContextSwitcher(threadPool); + this.contextSwitcher = new SystemContextSwitcher(threadPool); } public void updateGlobalCheckpointForShard(final ShardId shardId) { - final ThreadContext threadContext = threadPool.getThreadContext(); try (ThreadContext.StoredContext ignore = contextSwitcher.switchContext()) { - threadContext.markAsSystemContext(); execute(new Request(shardId), ActionListener.wrap(r -> {}, e -> { if (ExceptionsHelper.unwrap(e, AlreadyClosedException.class, IndexShardClosedException.class) == null) { logger.info(new ParameterizedMessage("{} global checkpoint sync failed", shardId), e); diff --git a/server/src/main/java/org/opensearch/index/seqno/RetentionLeaseBackgroundSyncAction.java b/server/src/main/java/org/opensearch/index/seqno/RetentionLeaseBackgroundSyncAction.java index 9b3d984285621..7bdd2bbbb0af0 100644 --- a/server/src/main/java/org/opensearch/index/seqno/RetentionLeaseBackgroundSyncAction.java +++ b/server/src/main/java/org/opensearch/index/seqno/RetentionLeaseBackgroundSyncAction.java @@ -48,7 +48,7 @@ import org.opensearch.common.inject.Inject; import org.opensearch.common.settings.Settings; import org.opensearch.common.util.concurrent.ContextSwitcher; -import org.opensearch.common.util.concurrent.InternalContextSwitcher; +import org.opensearch.common.util.concurrent.SystemContextSwitcher; import org.opensearch.common.util.concurrent.ThreadContext; import org.opensearch.core.action.ActionListener; import org.opensearch.core.common.io.stream.StreamInput; @@ -115,7 +115,7 @@ public RetentionLeaseBackgroundSyncAction( Request::new, ThreadPool.Names.MANAGEMENT ); - this.contextSwitcher = new InternalContextSwitcher(threadPool); + this.contextSwitcher = new SystemContextSwitcher(threadPool); } @Override @@ -124,10 +124,7 @@ protected void doExecute(Task task, Request request, ActionListener listener ) { - final ThreadContext threadContext = threadPool.getThreadContext(); try (ThreadContext.StoredContext ignore = contextSwitcher.switchContext()) { - // we have to execute under the system context so that if security is enabled the sync is authorized - threadContext.markAsSystemContext(); final Request request = new Request(shardId, retentionLeases); final ReplicationTask task = (ReplicationTask) taskManager.register("transport", "retention_lease_sync", request); transportService.sendChildRequest( diff --git a/server/src/main/java/org/opensearch/index/shard/RefreshListeners.java b/server/src/main/java/org/opensearch/index/shard/RefreshListeners.java index ef4b9f33b786c..38fe617e75157 100644 --- a/server/src/main/java/org/opensearch/index/shard/RefreshListeners.java +++ b/server/src/main/java/org/opensearch/index/shard/RefreshListeners.java @@ -38,8 +38,8 @@ import org.opensearch.common.lease.Releasable; import org.opensearch.common.metrics.MeanMetric; import org.opensearch.common.util.concurrent.ContextSwitcher; -import org.opensearch.common.util.concurrent.InternalContextSwitcher; import org.opensearch.common.util.concurrent.RunOnce; +import org.opensearch.common.util.concurrent.SystemContextSwitcher; import org.opensearch.common.util.concurrent.ThreadContext; import org.opensearch.index.translog.Translog; import org.opensearch.threadpool.ThreadPool; @@ -110,7 +110,7 @@ public RefreshListeners( this.forceRefresh = forceRefresh; this.logger = logger; this.threadPool = threadPool; - this.contextSwitcher = new InternalContextSwitcher(threadPool); + this.contextSwitcher = new SystemContextSwitcher(threadPool); this.refreshMetric = refreshMetric; } diff --git a/server/src/main/java/org/opensearch/indices/replication/checkpoint/PublishCheckpointAction.java b/server/src/main/java/org/opensearch/indices/replication/checkpoint/PublishCheckpointAction.java index 03b7c048c66da..364a7ffce5c42 100644 --- a/server/src/main/java/org/opensearch/indices/replication/checkpoint/PublishCheckpointAction.java +++ b/server/src/main/java/org/opensearch/indices/replication/checkpoint/PublishCheckpointAction.java @@ -24,7 +24,7 @@ import org.opensearch.common.inject.Inject; import org.opensearch.common.settings.Settings; import org.opensearch.common.util.concurrent.ContextSwitcher; -import org.opensearch.common.util.concurrent.InternalContextSwitcher; +import org.opensearch.common.util.concurrent.SystemContextSwitcher; import org.opensearch.common.util.concurrent.ThreadContext; import org.opensearch.core.action.ActionListener; import org.opensearch.core.common.io.stream.StreamInput; @@ -87,7 +87,7 @@ public PublishCheckpointAction( ThreadPool.Names.REFRESH ); this.replicationService = targetService; - this.contextSwitcher = new InternalContextSwitcher(threadPool); + this.contextSwitcher = new SystemContextSwitcher(threadPool); } @Override @@ -114,10 +114,7 @@ public ReplicationMode getReplicationMode(IndexShard indexShard) { final void publish(IndexShard indexShard, ReplicationCheckpoint checkpoint) { String primaryAllocationId = indexShard.routingEntry().allocationId().getId(); long primaryTerm = indexShard.getPendingPrimaryTerm(); - final ThreadContext threadContext = threadPool.getThreadContext(); try (ThreadContext.StoredContext ignore = contextSwitcher.switchContext()) { - // we have to execute under the system context so that if security is enabled the sync is authorized - threadContext.markAsSystemContext(); PublishCheckpointRequest request = new PublishCheckpointRequest(checkpoint); final ReplicationTask task = (ReplicationTask) taskManager.register("transport", "segrep_publish_checkpoint", request); final ReplicationTimer timer = new ReplicationTimer(); diff --git a/server/src/main/java/org/opensearch/transport/NativeMessageHandler.java b/server/src/main/java/org/opensearch/transport/NativeMessageHandler.java index 835734974ca63..ab1f665b05b76 100644 --- a/server/src/main/java/org/opensearch/transport/NativeMessageHandler.java +++ b/server/src/main/java/org/opensearch/transport/NativeMessageHandler.java @@ -40,7 +40,7 @@ import org.opensearch.common.util.BigArrays; import org.opensearch.common.util.concurrent.AbstractRunnable; import org.opensearch.common.util.concurrent.ContextSwitcher; -import org.opensearch.common.util.concurrent.InternalContextSwitcher; +import org.opensearch.common.util.concurrent.SystemContextSwitcher; import org.opensearch.common.util.concurrent.ThreadContext; import org.opensearch.core.common.io.stream.ByteBufferStreamInput; import org.opensearch.core.common.io.stream.NamedWriteableAwareStreamInput; @@ -102,7 +102,7 @@ public class NativeMessageHandler implements ProtocolMessageHandler { TransportKeepAlive keepAlive ) { this.threadPool = threadPool; - this.contextSwitcher = new InternalContextSwitcher(threadPool); + this.contextSwitcher = new SystemContextSwitcher(threadPool); this.outboundHandler = new NativeOutboundHandler(nodeName, version, features, statsTracker, threadPool, bigArrays, outboundHandler); this.namedWriteableRegistry = namedWriteableRegistry; this.handshaker = handshaker; diff --git a/server/src/main/java/org/opensearch/transport/OutboundHandler.java b/server/src/main/java/org/opensearch/transport/OutboundHandler.java index 8ab283fbbef8f..5d89ec5cc2d5c 100644 --- a/server/src/main/java/org/opensearch/transport/OutboundHandler.java +++ b/server/src/main/java/org/opensearch/transport/OutboundHandler.java @@ -41,7 +41,7 @@ import org.opensearch.common.network.CloseableChannel; import org.opensearch.common.transport.NetworkExceptionHelper; import org.opensearch.common.util.concurrent.ContextSwitcher; -import org.opensearch.common.util.concurrent.InternalContextSwitcher; +import org.opensearch.common.util.concurrent.SystemContextSwitcher; import org.opensearch.common.util.concurrent.ThreadContext; import org.opensearch.core.action.ActionListener; import org.opensearch.core.action.NotifyOnceListener; @@ -66,7 +66,7 @@ public final class OutboundHandler { public OutboundHandler(StatsTracker statsTracker, ThreadPool threadPool) { this.statsTracker = statsTracker; this.threadPool = threadPool; - this.contextSwitcher = new InternalContextSwitcher(threadPool); + this.contextSwitcher = new SystemContextSwitcher(threadPool); } void sendBytes(TcpChannel channel, BytesReference bytes, ActionListener listener) { diff --git a/server/src/main/java/org/opensearch/transport/RemoteClusterConnection.java b/server/src/main/java/org/opensearch/transport/RemoteClusterConnection.java index f27ab8132f26c..56cb6e1f51369 100644 --- a/server/src/main/java/org/opensearch/transport/RemoteClusterConnection.java +++ b/server/src/main/java/org/opensearch/transport/RemoteClusterConnection.java @@ -40,7 +40,7 @@ import org.opensearch.common.settings.Settings; import org.opensearch.common.unit.TimeValue; import org.opensearch.common.util.concurrent.ContextSwitcher; -import org.opensearch.common.util.concurrent.InternalContextSwitcher; +import org.opensearch.common.util.concurrent.SystemContextSwitcher; import org.opensearch.common.util.concurrent.ThreadContext; import org.opensearch.common.util.io.IOUtils; import org.opensearch.core.action.ActionListener; @@ -94,7 +94,7 @@ final class RemoteClusterConnection implements Closeable { this.skipUnavailable = RemoteClusterService.REMOTE_CLUSTER_SKIP_UNAVAILABLE.getConcreteSettingForNamespace(clusterAlias) .get(settings); this.threadPool = transportService.threadPool; - this.contextSwitcher = new InternalContextSwitcher(this.threadPool); + this.contextSwitcher = new SystemContextSwitcher(this.threadPool); initialConnectionTimeout = RemoteClusterService.REMOTE_INITIAL_CONNECTION_TIMEOUT_SETTING.get(settings); } @@ -139,8 +139,6 @@ void collectNodes(ActionListener> listener) { final ContextPreservingActionListener> contextPreservingActionListener = new ContextPreservingActionListener<>(threadContext.newRestorableContext(false), listener); try (ThreadContext.StoredContext ignore = contextSwitcher.switchContext()) { - // we stash any context here since this is an internal execution and should not leak any existing context information - threadContext.markAsSystemContext(); final ClusterStateRequest request = new ClusterStateRequest(); request.clear(); diff --git a/server/src/main/java/org/opensearch/transport/SniffConnectionStrategy.java b/server/src/main/java/org/opensearch/transport/SniffConnectionStrategy.java index 57b44d9dd4ccd..7bc876a81b63a 100644 --- a/server/src/main/java/org/opensearch/transport/SniffConnectionStrategy.java +++ b/server/src/main/java/org/opensearch/transport/SniffConnectionStrategy.java @@ -47,7 +47,7 @@ import org.opensearch.common.settings.Setting; import org.opensearch.common.settings.Settings; import org.opensearch.common.util.concurrent.ContextSwitcher; -import org.opensearch.common.util.concurrent.InternalContextSwitcher; +import org.opensearch.common.util.concurrent.SystemContextSwitcher; import org.opensearch.common.util.concurrent.ThreadContext; import org.opensearch.common.util.io.IOUtils; import org.opensearch.core.action.ActionListener; @@ -213,7 +213,7 @@ public class SniffConnectionStrategy extends RemoteConnectionStrategy { this.nodePredicate = nodePredicate; this.configuredSeedNodes = configuredSeedNodes; this.seedNodes = seedNodes; - this.contextSwitcher = new InternalContextSwitcher(transportService.getThreadPool()); + this.contextSwitcher = new SystemContextSwitcher(transportService.getThreadPool()); } static Stream> enablementSettings() { @@ -351,9 +351,6 @@ private void collectRemoteNodes(Iterator> seedNodes, Act new SniffClusterStateResponseHandler(connection, listener, seedNodes) ); try (ThreadContext.StoredContext ignore = contextSwitcher.switchContext()) { - // we stash any context here since this is an internal execution and should not leak any - // existing context information. - threadContext.markAsSystemContext(); transportService.sendRequest( connection, ClusterStateAction.NAME, diff --git a/server/src/test/java/org/opensearch/action/bulk/BulkProcessorTests.java b/server/src/test/java/org/opensearch/action/bulk/BulkProcessorTests.java index 31585d2b7a134..51ad848e9e12c 100644 --- a/server/src/test/java/org/opensearch/action/bulk/BulkProcessorTests.java +++ b/server/src/test/java/org/opensearch/action/bulk/BulkProcessorTests.java @@ -38,7 +38,7 @@ import org.opensearch.action.index.IndexRequest; import org.opensearch.common.unit.TimeValue; import org.opensearch.common.util.concurrent.ContextSwitcher; -import org.opensearch.common.util.concurrent.InternalContextSwitcher; +import org.opensearch.common.util.concurrent.SystemContextSwitcher; import org.opensearch.common.util.concurrent.ThreadContext; import org.opensearch.core.action.ActionListener; import org.opensearch.core.common.bytes.BytesReference; @@ -76,7 +76,7 @@ public class BulkProcessorTests extends OpenSearchTestCase { @Before public void startThreadPool() { threadPool = new TestThreadPool("BulkProcessorTests"); - contextSwitcher = new InternalContextSwitcher(threadPool); + contextSwitcher = new SystemContextSwitcher(threadPool); } @After diff --git a/server/src/test/java/org/opensearch/action/support/ContextPreservingActionListenerTests.java b/server/src/test/java/org/opensearch/action/support/ContextPreservingActionListenerTests.java index f93f66c3aec40..bae24ec3b5970 100644 --- a/server/src/test/java/org/opensearch/action/support/ContextPreservingActionListenerTests.java +++ b/server/src/test/java/org/opensearch/action/support/ContextPreservingActionListenerTests.java @@ -32,7 +32,7 @@ package org.opensearch.action.support; import org.opensearch.common.util.concurrent.ContextSwitcher; -import org.opensearch.common.util.concurrent.InternalContextSwitcher; +import org.opensearch.common.util.concurrent.SystemContextSwitcher; import org.opensearch.common.util.concurrent.ThreadContext; import org.opensearch.core.action.ActionListener; import org.opensearch.test.OpenSearchTestCase; @@ -49,7 +49,7 @@ public class ContextPreservingActionListenerTests extends OpenSearchTestCase { public void testOriginalContextIsPreservedAfterOnResponse() throws IOException { ThreadPool threadPool = new TestThreadPool("ContextPreservingActionListenerTests.testOriginalContextIsPreservedAfterOnResponse"); ThreadContext threadContext = threadPool.getThreadContext(); - ContextSwitcher contextSwitcher = new InternalContextSwitcher(threadPool); + ContextSwitcher contextSwitcher = new SystemContextSwitcher(threadPool); final boolean nonEmptyContext = randomBoolean(); if (nonEmptyContext) { threadContext.putHeader("not empty", "value"); @@ -88,7 +88,7 @@ public void onFailure(Exception e) { public void testOriginalContextIsPreservedAfterOnFailure() throws Exception { ThreadPool threadPool = new TestThreadPool("ContextPreservingActionListenerTests.testOriginalContextIsPreservedAfterOnFailure"); ThreadContext threadContext = threadPool.getThreadContext(); - ContextSwitcher contextSwitcher = new InternalContextSwitcher(threadPool); + ContextSwitcher contextSwitcher = new SystemContextSwitcher(threadPool); final boolean nonEmptyContext = randomBoolean(); if (nonEmptyContext) { threadContext.putHeader("not empty", "value"); @@ -129,7 +129,7 @@ public void onFailure(Exception e) { public void testOriginalContextIsWhenListenerThrows() throws Exception { ThreadPool threadPool = new TestThreadPool("ContextPreservingActionListenerTests.testOriginalContextIsWhenListenerThrows"); ThreadContext threadContext = threadPool.getThreadContext(); - ContextSwitcher contextSwitcher = new InternalContextSwitcher(threadPool); + ContextSwitcher contextSwitcher = new SystemContextSwitcher(threadPool); final boolean nonEmptyContext = randomBoolean(); if (nonEmptyContext) { threadContext.putHeader("not empty", "value"); @@ -179,7 +179,7 @@ public void onFailure(Exception e) { public void testToStringIncludesDelegate() { ThreadPool threadPool = new TestThreadPool("ContextPreservingActionListenerTests.testToStringIncludesDelegate"); ThreadContext threadContext = threadPool.getThreadContext(); - ContextSwitcher contextSwitcher = new InternalContextSwitcher(threadPool); + ContextSwitcher contextSwitcher = new SystemContextSwitcher(threadPool); final ContextPreservingActionListener actionListener; try (ThreadContext.StoredContext ignore = contextSwitcher.switchContext()) { final ActionListener delegate = new ActionListener() { diff --git a/server/src/test/java/org/opensearch/cluster/metadata/TemplateUpgradeServiceTests.java b/server/src/test/java/org/opensearch/cluster/metadata/TemplateUpgradeServiceTests.java index bd61596084374..fe42515846828 100644 --- a/server/src/test/java/org/opensearch/cluster/metadata/TemplateUpgradeServiceTests.java +++ b/server/src/test/java/org/opensearch/cluster/metadata/TemplateUpgradeServiceTests.java @@ -47,7 +47,7 @@ import org.opensearch.cluster.service.ClusterService; import org.opensearch.common.collect.Tuple; import org.opensearch.common.util.concurrent.ContextSwitcher; -import org.opensearch.common.util.concurrent.InternalContextSwitcher; +import org.opensearch.common.util.concurrent.SystemContextSwitcher; import org.opensearch.common.util.concurrent.ThreadContext; import org.opensearch.core.action.ActionListener; import org.opensearch.core.common.bytes.BytesArray; @@ -97,7 +97,7 @@ public class TemplateUpgradeServiceTests extends OpenSearchTestCase { @Before public void setUpTest() throws Exception { threadPool = new TestThreadPool("TemplateUpgradeServiceTests"); - contextSwitcher = new InternalContextSwitcher(threadPool); + contextSwitcher = new SystemContextSwitcher(threadPool); clusterService = createClusterService(threadPool); } @@ -227,9 +227,7 @@ public void testUpdateTemplates() { assertThat(ise.getMessage(), containsString("template upgrade service should always happen in a system context")); service.upgradesInProgress.set(additionsCount + deletionsCount + 2); // +2 to skip tryFinishUpgrade - final ThreadContext threadContext = threadPool.getThreadContext(); try (ThreadContext.StoredContext ignore = contextSwitcher.switchContext()) { - threadContext.markAsSystemContext(); service.upgradeTemplates(additions, deletions); } diff --git a/server/src/test/java/org/opensearch/cluster/service/ClusterApplierServiceTests.java b/server/src/test/java/org/opensearch/cluster/service/ClusterApplierServiceTests.java index 8de8099b9ffd1..f2585312d3a28 100644 --- a/server/src/test/java/org/opensearch/cluster/service/ClusterApplierServiceTests.java +++ b/server/src/test/java/org/opensearch/cluster/service/ClusterApplierServiceTests.java @@ -52,7 +52,7 @@ import org.opensearch.common.settings.Settings; import org.opensearch.common.unit.TimeValue; import org.opensearch.common.util.concurrent.ContextSwitcher; -import org.opensearch.common.util.concurrent.InternalContextSwitcher; +import org.opensearch.common.util.concurrent.SystemContextSwitcher; import org.opensearch.common.util.concurrent.ThreadContext; import org.opensearch.telemetry.metrics.Histogram; import org.opensearch.telemetry.metrics.MetricsRegistry; @@ -102,7 +102,7 @@ public class ClusterApplierServiceTests extends OpenSearchTestCase { @BeforeClass public static void createThreadPool() { threadPool = new TestThreadPool(ClusterApplierServiceTests.class.getName()); - contextSwitcher = new InternalContextSwitcher(threadPool); + contextSwitcher = new SystemContextSwitcher(threadPool); metricsRegistry = mock(MetricsRegistry.class); applierslatencyHistogram = mock(Histogram.class); listenerslatencyHistogram = mock(Histogram.class); diff --git a/server/src/test/java/org/opensearch/cluster/service/MasterServiceTests.java b/server/src/test/java/org/opensearch/cluster/service/MasterServiceTests.java index 41b0ef955fef4..55dab5e71e3d8 100644 --- a/server/src/test/java/org/opensearch/cluster/service/MasterServiceTests.java +++ b/server/src/test/java/org/opensearch/cluster/service/MasterServiceTests.java @@ -61,7 +61,7 @@ import org.opensearch.common.unit.TimeValue; import org.opensearch.common.util.concurrent.BaseFuture; import org.opensearch.common.util.concurrent.ContextSwitcher; -import org.opensearch.common.util.concurrent.InternalContextSwitcher; +import org.opensearch.common.util.concurrent.SystemContextSwitcher; import org.opensearch.common.util.concurrent.ThreadContext; import org.opensearch.node.Node; import org.opensearch.telemetry.metrics.Histogram; @@ -124,7 +124,7 @@ public long preciseRelativeTimeInNanos() { return timeDiffInMillis * TimeValue.NSEC_PER_MSEC; } }; - contextSwitcher = new InternalContextSwitcher(threadPool); + contextSwitcher = new SystemContextSwitcher(threadPool); } @AfterClass diff --git a/server/src/test/java/org/opensearch/common/util/concurrent/ThreadContextTests.java b/server/src/test/java/org/opensearch/common/util/concurrent/ThreadContextTests.java index 4e66575711046..bb0c6061222a9 100644 --- a/server/src/test/java/org/opensearch/common/util/concurrent/ThreadContextTests.java +++ b/server/src/test/java/org/opensearch/common/util/concurrent/ThreadContextTests.java @@ -563,16 +563,12 @@ public void testPreservesThreadsOriginalContextOnRunException() throws IOExcepti // create a abstract runnable, add headers and transient objects and verify in the methods try (ThreadContext.StoredContext ignored = threadContext.stashContext()) { threadContext.putHeader("foo", "bar"); - boolean systemContext = randomBoolean(); - if (systemContext) { - threadContext.markAsSystemContext(); - } threadContext.putTransient("foo", "bar_transient"); withContext = threadContext.preserveContext(new AbstractRunnable() { @Override public void onAfter() { - assertEquals(systemContext, threadContext.isSystemContext()); + assertTrue(threadContext.isSystemContext()); assertEquals("bar", threadContext.getHeader("foo")); assertEquals("bar_transient", threadContext.getTransient("foo")); assertNotNull(threadContext.getTransient("failure")); @@ -583,7 +579,7 @@ public void onAfter() { @Override public void onFailure(Exception e) { - assertEquals(systemContext, threadContext.isSystemContext()); + assertTrue(threadContext.isSystemContext()); assertEquals("exception from doRun", e.getMessage()); assertEquals("bar", threadContext.getHeader("foo")); assertEquals("bar_transient", threadContext.getTransient("foo")); @@ -593,7 +589,7 @@ public void onFailure(Exception e) { @Override protected void doRun() throws Exception { - assertEquals(systemContext, threadContext.isSystemContext()); + assertTrue(threadContext.isSystemContext()); assertEquals("bar", threadContext.getHeader("foo")); assertEquals("bar_transient", threadContext.getTransient("foo")); assertFalse(threadContext.isDefaultContext()); @@ -735,8 +731,6 @@ public void testMarkAsSystemContext() throws IOException { ThreadContext threadContext = new ThreadContext(Settings.EMPTY); assertFalse(threadContext.isSystemContext()); try (ThreadContext.StoredContext context = threadContext.stashContext()) { - assertFalse(threadContext.isSystemContext()); - threadContext.markAsSystemContext(); assertTrue(threadContext.isSystemContext()); } assertFalse(threadContext.isSystemContext()); @@ -761,7 +755,6 @@ public void testSystemContextWithPropagator() { assertEquals(Integer.valueOf(1), threadContext.getTransient("test_transient_propagation_key")); assertEquals("bar", threadContext.getHeader("foo")); try (ThreadContext.StoredContext ctx = threadContext.stashContext()) { - threadContext.markAsSystemContext(); assertNull(threadContext.getHeader("foo")); assertNull(threadContext.getTransient("test_transient_propagation_key")); assertEquals("1", threadContext.getHeader("default")); @@ -793,7 +786,6 @@ public void testSerializeSystemContext() throws IOException { threadContext.writeTo(out); try (ThreadContext.StoredContext ctx = threadContext.stashContext()) { assertEquals("test", threadContext.getTransient("test_transient_propagation_key")); - threadContext.markAsSystemContext(); threadContext.writeTo(outFromSystemContext); assertNull(threadContext.getHeader("foo")); assertNull(threadContext.getTransient("test_transient_propagation_key")); diff --git a/server/src/test/java/org/opensearch/index/shard/RefreshListenersTests.java b/server/src/test/java/org/opensearch/index/shard/RefreshListenersTests.java index d5add99741080..917b6a4843311 100644 --- a/server/src/test/java/org/opensearch/index/shard/RefreshListenersTests.java +++ b/server/src/test/java/org/opensearch/index/shard/RefreshListenersTests.java @@ -50,7 +50,7 @@ import org.opensearch.common.unit.TimeValue; import org.opensearch.common.util.BigArrays; import org.opensearch.common.util.concurrent.ContextSwitcher; -import org.opensearch.common.util.concurrent.InternalContextSwitcher; +import org.opensearch.common.util.concurrent.SystemContextSwitcher; import org.opensearch.common.util.concurrent.ThreadContext; import org.opensearch.common.util.io.IOUtils; import org.opensearch.core.common.bytes.BytesArray; @@ -117,7 +117,7 @@ public void setupListeners() throws Exception { maxListeners = randomIntBetween(1, 1000); // Now setup the InternalEngine which is much more complicated because we aren't mocking anything threadPool = new TestThreadPool(getTestName()); - contextSwitcher = new InternalContextSwitcher(threadPool); + contextSwitcher = new SystemContextSwitcher(threadPool); refreshMetric = new MeanMetric(); listeners = new RefreshListeners(() -> maxListeners, () -> engine.refresh("too-many-listeners"), logger, threadPool, refreshMetric); diff --git a/server/src/test/java/org/opensearch/node/NodeTests.java b/server/src/test/java/org/opensearch/node/NodeTests.java index 37936c18b0226..01c1a5c3b02d3 100644 --- a/server/src/test/java/org/opensearch/node/NodeTests.java +++ b/server/src/test/java/org/opensearch/node/NodeTests.java @@ -44,6 +44,7 @@ import org.opensearch.common.settings.Settings; import org.opensearch.common.settings.SettingsException; import org.opensearch.common.util.FeatureFlags; +import org.opensearch.common.util.concurrent.ContextSwitcher; import org.opensearch.core.common.breaker.CircuitBreaker; import org.opensearch.core.common.io.stream.NamedWriteableRegistry; import org.opensearch.core.common.transport.BoundTransportAddress; @@ -478,7 +479,8 @@ public Collection createComponents( IndexNameExpressionResolver indexNameExpressionResolver, Supplier repositoriesServiceSupplier, Tracer tracer, - MetricsRegistry metricsRegistry + MetricsRegistry metricsRegistry, + ContextSwitcher contextSwitcher ) { return List.of(new MockTelemetryAwareComponent(tracer, metricsRegistry)); } diff --git a/server/src/test/java/org/opensearch/telemetry/tracing/ThreadContextBasedTracerContextStorageTests.java b/server/src/test/java/org/opensearch/telemetry/tracing/ThreadContextBasedTracerContextStorageTests.java index 339c85084fb41..729de1d9f7bc1 100644 --- a/server/src/test/java/org/opensearch/telemetry/tracing/ThreadContextBasedTracerContextStorageTests.java +++ b/server/src/test/java/org/opensearch/telemetry/tracing/ThreadContextBasedTracerContextStorageTests.java @@ -8,10 +8,12 @@ package org.opensearch.telemetry.tracing; +import com.carrotsearch.randomizedtesting.annotations.ThreadLeakScope; + import org.opensearch.common.settings.ClusterSettings; import org.opensearch.common.settings.Settings; import org.opensearch.common.util.concurrent.ContextSwitcher; -import org.opensearch.common.util.concurrent.InternalContextSwitcher; +import org.opensearch.common.util.concurrent.SystemContextSwitcher; import org.opensearch.common.util.concurrent.ThreadContext; import org.opensearch.common.util.concurrent.ThreadContext.StoredContext; import org.opensearch.telemetry.Telemetry; @@ -41,6 +43,7 @@ import static org.hamcrest.CoreMatchers.not; import static org.hamcrest.CoreMatchers.nullValue; +@ThreadLeakScope(ThreadLeakScope.Scope.NONE) public class ThreadContextBasedTracerContextStorageTests extends OpenSearchTestCase { private Tracer tracer; private ThreadPool threadPool; @@ -69,7 +72,7 @@ public void setUp() throws Exception { threadPool = new TestThreadPool(getTestName()); threadContext = threadPool.getThreadContext(); - contextSwitcher = new InternalContextSwitcher(threadPool); + contextSwitcher = new SystemContextSwitcher(threadPool); threadContextStorage = new ThreadContextBasedTracerContextStorage(threadContext, tracingTelemetry); tracer = new TracerFactory(telemetrySettings, Optional.of(new Telemetry() { @@ -268,8 +271,6 @@ public void testSpanNotPropagatedToChildSystemThreadContext() { try (StoredContext ignored = contextSwitcher.switchContext()) { assertThat(threadContext.getTransient(ThreadContextBasedTracerContextStorage.CURRENT_SPAN), is(not(nullValue()))); assertThat(threadContextStorage.get(ThreadContextBasedTracerContextStorage.CURRENT_SPAN), is(span)); - threadContext.markAsSystemContext(); - assertThat(threadContext.getTransient(ThreadContextBasedTracerContextStorage.CURRENT_SPAN), is(nullValue())); } } diff --git a/test/framework/src/main/java/org/opensearch/cluster/service/FakeThreadPoolClusterManagerService.java b/test/framework/src/main/java/org/opensearch/cluster/service/FakeThreadPoolClusterManagerService.java index 0575790a508f4..cf216fc4b2d69 100644 --- a/test/framework/src/main/java/org/opensearch/cluster/service/FakeThreadPoolClusterManagerService.java +++ b/test/framework/src/main/java/org/opensearch/cluster/service/FakeThreadPoolClusterManagerService.java @@ -42,9 +42,9 @@ import org.opensearch.common.settings.Settings; import org.opensearch.common.unit.TimeValue; import org.opensearch.common.util.concurrent.ContextSwitcher; -import org.opensearch.common.util.concurrent.InternalContextSwitcher; import org.opensearch.common.util.concurrent.OpenSearchExecutors; import org.opensearch.common.util.concurrent.PrioritizedOpenSearchThreadPoolExecutor; +import org.opensearch.common.util.concurrent.SystemContextSwitcher; import org.opensearch.common.util.concurrent.ThreadContext; import org.opensearch.core.action.ActionListener; import org.opensearch.node.Node; @@ -84,7 +84,7 @@ public FakeThreadPoolClusterManagerService( ); this.name = serviceName; this.onTaskAvailableToRun = onTaskAvailableToRun; - this.contextSwitcher = new InternalContextSwitcher(threadPool); + this.contextSwitcher = new SystemContextSwitcher(threadPool); } @Override @@ -136,9 +136,7 @@ public void run() { final Runnable task = pendingTasks.remove(taskIndex); taskInProgress = true; scheduledNextTask = false; - final ThreadContext threadContext = threadPool.getThreadContext(); try (ThreadContext.StoredContext ignored = contextSwitcher.switchContext()) { - threadContext.markAsSystemContext(); task.run(); } if (waitForPublish == false) { From b031db9306089872bbf984b66e378790a3852061 Mon Sep 17 00:00:00 2001 From: Craig Perkins Date: Tue, 23 Jul 2024 17:14:46 -0400 Subject: [PATCH 19/65] Add javadoc on param Signed-off-by: Craig Perkins --- server/src/main/java/org/opensearch/plugins/Plugin.java | 2 +- .../main/java/org/opensearch/plugins/TelemetryAwarePlugin.java | 1 + 2 files changed, 2 insertions(+), 1 deletion(-) diff --git a/server/src/main/java/org/opensearch/plugins/Plugin.java b/server/src/main/java/org/opensearch/plugins/Plugin.java index acf1e386732af..6e1017a516925 100644 --- a/server/src/main/java/org/opensearch/plugins/Plugin.java +++ b/server/src/main/java/org/opensearch/plugins/Plugin.java @@ -139,7 +139,7 @@ public Collection> getGuiceServiceClasses() * @param indexNameExpressionResolver A service that resolves expression to index and alias names * @param repositoriesServiceSupplier A supplier for the service that manages snapshot repositories; will return null when this method * is called, but will return the repositories service once the node is initialized. - * @param contextSwitcher + * @param contextSwitcher A client for switching to plugin system context */ public Collection createComponents( Client client, diff --git a/server/src/main/java/org/opensearch/plugins/TelemetryAwarePlugin.java b/server/src/main/java/org/opensearch/plugins/TelemetryAwarePlugin.java index 13f17bc86cb44..01287931719b2 100644 --- a/server/src/main/java/org/opensearch/plugins/TelemetryAwarePlugin.java +++ b/server/src/main/java/org/opensearch/plugins/TelemetryAwarePlugin.java @@ -60,6 +60,7 @@ public interface TelemetryAwarePlugin { * is called, but will return the repositories service once the node is initialized. * @param tracer the tracer to add tracing instrumentation. * @param metricsRegistry the registry for metrics instrumentation. + * @param contextSwitcher A client for switching to plugin system context */ default Collection createComponents( NodeClient client, From 54439a0b96970bf209e2b4a95ed92ac3989143a7 Mon Sep 17 00:00:00 2001 From: Craig Perkins Date: Fri, 2 Aug 2024 16:29:25 -0400 Subject: [PATCH 20/65] Remove SystemContextSwitcher Signed-off-by: Craig Perkins --- README.md | 2 +- .../client/OriginSettingClient.java | 13 ++----- .../client/support/AbstractClient.java | 6 +-- .../service/ClusterApplierService.java | 6 +-- .../cluster/service/MasterService.java | 7 +--- .../concurrent/SystemContextSwitcher.java | 38 ------------------- .../common/util/concurrent/ThreadContext.java | 8 ++-- .../http/AbstractHttpServerTransport.java | 6 +-- .../seqno/GlobalCheckpointSyncAction.java | 8 ++-- .../RetentionLeaseBackgroundSyncAction.java | 10 ++--- .../index/seqno/RetentionLeaseSyncAction.java | 9 ++--- .../opensearch/index/shard/IndexShard.java | 2 +- .../index/shard/RefreshListeners.java | 15 +++----- .../checkpoint/PublishCheckpointAction.java | 9 ++--- .../transport/NativeMessageHandler.java | 6 +-- .../opensearch/transport/OutboundHandler.java | 6 +-- .../transport/RemoteClusterConnection.java | 8 ++-- .../transport/SniffConnectionStrategy.java | 9 ++--- .../action/bulk/BulkProcessorTests.java | 6 +-- .../ContextPreservingActionListenerTests.java | 29 +++++--------- .../metadata/TemplateUpgradeServiceTests.java | 8 ++-- .../service/ClusterApplierServiceTests.java | 6 +-- .../cluster/service/MasterServiceTests.java | 6 +-- .../index/shard/RefreshListenersTests.java | 14 ++++--- ...ContextBasedTracerContextStorageTests.java | 27 ++++++------- .../FakeThreadPoolClusterManagerService.java | 8 ++-- 26 files changed, 82 insertions(+), 190 deletions(-) delete mode 100644 server/src/main/java/org/opensearch/common/util/concurrent/SystemContextSwitcher.java diff --git a/README.md b/README.md index 17af2911b9221..5d4a9a671c013 100644 --- a/README.md +++ b/README.md @@ -7,7 +7,7 @@ [![Security Vulnerabilities](https://img.shields.io/github/issues/opensearch-project/OpenSearch/security%20vulnerability?labelColor=red)](https://github.com/opensearch-project/OpenSearch/issues?q=is%3Aissue+is%3Aopen+label%3A"security%20vulnerability") [![Open Issues](https://img.shields.io/github/issues/opensearch-project/OpenSearch)](https://github.com/opensearch-project/OpenSearch/issues) [![Open Pull Requests](https://img.shields.io/github/issues-pr/opensearch-project/OpenSearch)](https://github.com/opensearch-project/OpenSearch/pulls) -[![2.14.1 Open Issues](https://img.shields.io/github/issues/opensearch-project/OpenSearch/v2.14.1)](https://github.com/opensearch-project/OpenSearch/issues?q=is%3Aissue+is%3Aopen+label%3A"v2.14.1") +[![2.17.0 Open Issues](https://img.shields.io/github/issues/opensearch-project/OpenSearch/v2.17.0)](https://github.com/opensearch-project/OpenSearch/issues?q=is%3Aissue+is%3Aopen+label%3A"v2.17.0") [![3.0.0 Open Issues](https://img.shields.io/github/issues/opensearch-project/OpenSearch/v3.0.0)](https://github.com/opensearch-project/OpenSearch/issues?q=is%3Aissue+is%3Aopen+label%3A"v3.0.0") [![GHA gradle check](https://github.com/opensearch-project/OpenSearch/actions/workflows/gradle-check.yml/badge.svg)](https://github.com/opensearch-project/OpenSearch/actions/workflows/gradle-check.yml) [![GHA validate pull request](https://github.com/opensearch-project/OpenSearch/actions/workflows/wrapper.yml/badge.svg)](https://github.com/opensearch-project/OpenSearch/actions/workflows/wrapper.yml) diff --git a/server/src/main/java/org/opensearch/client/OriginSettingClient.java b/server/src/main/java/org/opensearch/client/OriginSettingClient.java index 073e92122ef8e..1b0e08cc489c4 100644 --- a/server/src/main/java/org/opensearch/client/OriginSettingClient.java +++ b/server/src/main/java/org/opensearch/client/OriginSettingClient.java @@ -35,20 +35,16 @@ import org.opensearch.action.ActionRequest; import org.opensearch.action.ActionType; import org.opensearch.action.support.ContextPreservingActionListener; -import org.opensearch.common.util.concurrent.ContextSwitcher; -import org.opensearch.common.util.concurrent.SystemContextSwitcher; import org.opensearch.common.util.concurrent.ThreadContext; import org.opensearch.core.action.ActionListener; import org.opensearch.core.action.ActionResponse; import java.util.function.Supplier; -import static org.opensearch.common.util.concurrent.ThreadContext.ACTION_ORIGIN_TRANSIENT_NAME; - /** * A {@linkplain Client} that sends requests with the - * origin set to a particular value and calls its {@linkplain ActionListener} - * in its original + * {@link ThreadContext#stashWithOrigin origin} set to a particular + * value and calls its {@linkplain ActionListener} in its original * {@link ThreadContext}. * * @opensearch.internal @@ -56,12 +52,10 @@ public final class OriginSettingClient extends FilterClient { private final String origin; - private final ContextSwitcher contextSwitcher; public OriginSettingClient(Client in, String origin) { super(in); this.origin = origin; - this.contextSwitcher = new SystemContextSwitcher(in().threadPool()); } @Override @@ -71,8 +65,7 @@ protected void ActionListener listener ) { final Supplier supplier = in().threadPool().getThreadContext().newRestorableContext(false); - try (ThreadContext.StoredContext ignore = contextSwitcher.switchContext()) { - in().threadPool().getThreadContext().putTransient(ACTION_ORIGIN_TRANSIENT_NAME, origin); + try (ThreadContext.StoredContext ignore = in().threadPool().getThreadContext().stashWithOrigin(origin)) { super.doExecute(action, request, new ContextPreservingActionListener<>(supplier, listener)); } } diff --git a/server/src/main/java/org/opensearch/client/support/AbstractClient.java b/server/src/main/java/org/opensearch/client/support/AbstractClient.java index 6fcad9c5e95ad..6c6049f04231b 100644 --- a/server/src/main/java/org/opensearch/client/support/AbstractClient.java +++ b/server/src/main/java/org/opensearch/client/support/AbstractClient.java @@ -415,7 +415,6 @@ import org.opensearch.common.Nullable; import org.opensearch.common.action.ActionFuture; import org.opensearch.common.settings.Settings; -import org.opensearch.common.util.concurrent.SystemContextSwitcher; import org.opensearch.common.util.concurrent.ThreadContext; import org.opensearch.core.action.ActionListener; import org.opensearch.core.action.ActionResponse; @@ -438,13 +437,11 @@ public abstract class AbstractClient implements Client { protected final Settings settings; private final ThreadPool threadPool; private final Admin admin; - private final SystemContextSwitcher contextSwitcher; public AbstractClient(Settings settings, ThreadPool threadPool) { this.settings = settings; this.threadPool = threadPool; this.admin = new Admin(this); - this.contextSwitcher = new SystemContextSwitcher(threadPool); this.logger = LogManager.getLogger(this.getClass()); } @@ -2150,7 +2147,8 @@ protected void Request request, ActionListener listener ) { - try (ThreadContext.StoredContext ctx = contextSwitcher.stashAndMergeHeaders(headers)) { + ThreadContext threadContext = threadPool().getThreadContext(); + try (ThreadContext.StoredContext ctx = threadContext.stashAndMergeHeaders(headers)) { super.doExecute(action, request, listener); } } diff --git a/server/src/main/java/org/opensearch/cluster/service/ClusterApplierService.java b/server/src/main/java/org/opensearch/cluster/service/ClusterApplierService.java index d5c65a23507a8..add43edc7365d 100644 --- a/server/src/main/java/org/opensearch/cluster/service/ClusterApplierService.java +++ b/server/src/main/java/org/opensearch/cluster/service/ClusterApplierService.java @@ -58,10 +58,8 @@ import org.opensearch.common.settings.Setting; import org.opensearch.common.settings.Settings; import org.opensearch.common.unit.TimeValue; -import org.opensearch.common.util.concurrent.ContextSwitcher; import org.opensearch.common.util.concurrent.OpenSearchExecutors; import org.opensearch.common.util.concurrent.PrioritizedOpenSearchThreadPoolExecutor; -import org.opensearch.common.util.concurrent.SystemContextSwitcher; import org.opensearch.common.util.concurrent.ThreadContext; import org.opensearch.core.concurrency.OpenSearchRejectedExecutionException; import org.opensearch.telemetry.metrics.noop.NoopMetricsRegistry; @@ -106,7 +104,6 @@ public class ClusterApplierService extends AbstractLifecycleComponent implements private final ClusterSettings clusterSettings; protected final ThreadPool threadPool; - protected final ContextSwitcher contextSwitcher; private volatile TimeValue slowTaskLoggingThreshold; @@ -142,7 +139,6 @@ public ClusterApplierService( ) { this.clusterSettings = clusterSettings; this.threadPool = threadPool; - this.contextSwitcher = new SystemContextSwitcher(threadPool); this.state = new AtomicReference<>(); this.nodeName = nodeName; @@ -399,7 +395,7 @@ private void submitStateUpdateTask( } final ThreadContext threadContext = threadPool.getThreadContext(); final Supplier supplier = threadContext.newRestorableContext(true); - try (ThreadContext.StoredContext ignore = contextSwitcher.switchContext()) { + try (ThreadContext.StoredContext ignore = threadPool.getThreadContext().stashContext()) { final UpdateTask updateTask = new UpdateTask( config.priority(), source, diff --git a/server/src/main/java/org/opensearch/cluster/service/MasterService.java b/server/src/main/java/org/opensearch/cluster/service/MasterService.java index bb820e9a20fe0..4ab8255df7658 100644 --- a/server/src/main/java/org/opensearch/cluster/service/MasterService.java +++ b/server/src/main/java/org/opensearch/cluster/service/MasterService.java @@ -61,12 +61,10 @@ import org.opensearch.common.settings.Setting; import org.opensearch.common.settings.Settings; import org.opensearch.common.unit.TimeValue; -import org.opensearch.common.util.concurrent.ContextSwitcher; import org.opensearch.common.util.concurrent.CountDown; import org.opensearch.common.util.concurrent.FutureUtils; import org.opensearch.common.util.concurrent.OpenSearchExecutors; import org.opensearch.common.util.concurrent.PrioritizedOpenSearchThreadPoolExecutor; -import org.opensearch.common.util.concurrent.SystemContextSwitcher; import org.opensearch.common.util.concurrent.ThreadContext; import org.opensearch.core.Assertions; import org.opensearch.core.common.text.Text; @@ -136,7 +134,6 @@ public class MasterService extends AbstractLifecycleComponent { private volatile TimeValue slowTaskLoggingThreshold; protected final ThreadPool threadPool; - protected final ContextSwitcher contextSwitcher; private volatile PrioritizedOpenSearchThreadPoolExecutor threadPoolExecutor; private volatile Batcher taskBatcher; @@ -172,7 +169,6 @@ public MasterService( ); this.stateStats = new ClusterStateStats(); this.threadPool = threadPool; - this.contextSwitcher = new SystemContextSwitcher(threadPool); this.clusterManagerMetrics = clusterManagerMetrics; } @@ -1025,7 +1021,8 @@ public void submitStateUpdateTasks( } final ThreadContext threadContext = threadPool.getThreadContext(); final Supplier supplier = threadContext.newRestorableContext(true); - try (ThreadContext.StoredContext ignore = contextSwitcher.switchContext()) { + try (ThreadContext.StoredContext ignore = threadContext.stashContext()) { + threadContext.markAsSystemContext(); List safeTasks = tasks.entrySet() .stream() diff --git a/server/src/main/java/org/opensearch/common/util/concurrent/SystemContextSwitcher.java b/server/src/main/java/org/opensearch/common/util/concurrent/SystemContextSwitcher.java deleted file mode 100644 index 363f0900ea294..0000000000000 --- a/server/src/main/java/org/opensearch/common/util/concurrent/SystemContextSwitcher.java +++ /dev/null @@ -1,38 +0,0 @@ -/* - * SPDX-License-Identifier: Apache-2.0 - * - * The OpenSearch Contributors require contributions made to - * this file be licensed under the Apache-2.0 license or a - * compatible open source license. - */ - -package org.opensearch.common.util.concurrent; - -import org.opensearch.common.annotation.InternalApi; -import org.opensearch.threadpool.ThreadPool; - -import java.util.Map; - -/** - * InternalContextSwitcher is an internal class used to switch into a fresh - * internal system context - * - * @opensearch.internal - */ -@InternalApi -public class SystemContextSwitcher implements ContextSwitcher { - private final ThreadPool threadPool; - - public SystemContextSwitcher(ThreadPool threadPool) { - this.threadPool = threadPool; - } - - @Override - public ThreadContext.StoredContext switchContext() { - return threadPool.getThreadContext().stashContext(); - } - - public ThreadContext.StoredContext stashAndMergeHeaders(Map headers) { - return threadPool.getThreadContext().stashAndMergeHeaders(headers); - } -} diff --git a/server/src/main/java/org/opensearch/common/util/concurrent/ThreadContext.java b/server/src/main/java/org/opensearch/common/util/concurrent/ThreadContext.java index af7bfbe3c8c8e..0d63798d51cb1 100644 --- a/server/src/main/java/org/opensearch/common/util/concurrent/ThreadContext.java +++ b/server/src/main/java/org/opensearch/common/util/concurrent/ThreadContext.java @@ -145,7 +145,7 @@ public void unregisterThreadContextStatePropagator(final ThreadContextStatePropa * Removes the current context and resets a default context. The removed context can be * restored by closing the returned {@link StoredContext}. */ - StoredContext stashContext() { + public StoredContext stashContext() { final ThreadContextStruct context = threadLocal.get(); /* X-Opaque-ID should be preserved in a threadContext in order to propagate this across threads. @@ -247,7 +247,7 @@ public Writeable captureAsWriteable() { * but the tasks API will perform a get on their behalf using this method * if it can't find the task in memory. */ - StoredContext stashWithOrigin(String origin) { + public StoredContext stashWithOrigin(String origin) { final ThreadContext.StoredContext storedContext = stashContext(); putTransient(ACTION_ORIGIN_TRANSIENT_NAME, origin); return storedContext; @@ -258,7 +258,7 @@ StoredContext stashWithOrigin(String origin) { * The removed context can be restored when closing the returned {@link StoredContext}. The merge strategy is that headers * that are already existing are preserved unless they are defaults. */ - StoredContext stashAndMergeHeaders(Map headers) { + public StoredContext stashAndMergeHeaders(Map headers) { final ThreadContextStruct context = threadLocal.get(); Map newHeader = new HashMap<>(headers); newHeader.putAll(context.requestHeaders); @@ -596,7 +596,7 @@ boolean isDefaultContext() { * Marks this thread context as an internal system context. This signals that actions in this context are issued * by the system itself rather than by a user action. */ - void markAsSystemContext() { + public void markAsSystemContext() { threadLocal.set(threadLocal.get().setSystemContext(propagators)); } diff --git a/server/src/main/java/org/opensearch/http/AbstractHttpServerTransport.java b/server/src/main/java/org/opensearch/http/AbstractHttpServerTransport.java index c4b53fb048211..991fbf12072be 100644 --- a/server/src/main/java/org/opensearch/http/AbstractHttpServerTransport.java +++ b/server/src/main/java/org/opensearch/http/AbstractHttpServerTransport.java @@ -45,8 +45,6 @@ import org.opensearch.common.transport.NetworkExceptionHelper; import org.opensearch.common.transport.PortsRange; import org.opensearch.common.util.BigArrays; -import org.opensearch.common.util.concurrent.ContextSwitcher; -import org.opensearch.common.util.concurrent.SystemContextSwitcher; import org.opensearch.common.util.concurrent.ThreadContext; import org.opensearch.core.action.ActionListener; import org.opensearch.core.common.Strings; @@ -101,7 +99,6 @@ public abstract class AbstractHttpServerTransport extends AbstractLifecycleCompo protected final NetworkService networkService; protected final BigArrays bigArrays; protected final ThreadPool threadPool; - protected final ContextSwitcher contextSwitcher; protected final Dispatcher dispatcher; protected final CorsHandler corsHandler; private final NamedXContentRegistry xContentRegistry; @@ -133,7 +130,6 @@ protected AbstractHttpServerTransport( this.networkService = networkService; this.bigArrays = bigArrays; this.threadPool = threadPool; - this.contextSwitcher = new SystemContextSwitcher(threadPool); this.xContentRegistry = xContentRegistry; this.dispatcher = dispatcher; this.handlingSettings = HttpHandlingSettings.fromSettings(settings); @@ -389,7 +385,7 @@ public void incomingRequest(final HttpRequest httpRequest, final HttpChannel htt void dispatchRequest(final RestRequest restRequest, final RestChannel channel, final Throwable badRequestCause) { RestChannel traceableRestChannel = channel; final ThreadContext threadContext = threadPool.getThreadContext(); - try (ThreadContext.StoredContext ignore = contextSwitcher.switchContext()) { + try (ThreadContext.StoredContext ignore = threadContext.stashContext()) { final Span span = tracer.startSpan(SpanBuilder.from(restRequest)); try (final SpanScope spanScope = tracer.withSpanInScope(span)) { if (channel != null) { diff --git a/server/src/main/java/org/opensearch/index/seqno/GlobalCheckpointSyncAction.java b/server/src/main/java/org/opensearch/index/seqno/GlobalCheckpointSyncAction.java index 8f077050bbcb8..c6a1f5f27a875 100644 --- a/server/src/main/java/org/opensearch/index/seqno/GlobalCheckpointSyncAction.java +++ b/server/src/main/java/org/opensearch/index/seqno/GlobalCheckpointSyncAction.java @@ -43,8 +43,6 @@ import org.opensearch.cluster.service.ClusterService; import org.opensearch.common.inject.Inject; import org.opensearch.common.settings.Settings; -import org.opensearch.common.util.concurrent.ContextSwitcher; -import org.opensearch.common.util.concurrent.SystemContextSwitcher; import org.opensearch.common.util.concurrent.ThreadContext; import org.opensearch.core.action.ActionListener; import org.opensearch.core.common.io.stream.StreamInput; @@ -71,7 +69,6 @@ public class GlobalCheckpointSyncAction extends TransportReplicationAction< ReplicationResponse> { public static String ACTION_NAME = "indices:admin/seq_no/global_checkpoint_sync"; - private final ContextSwitcher contextSwitcher; @Inject public GlobalCheckpointSyncAction( @@ -96,11 +93,12 @@ public GlobalCheckpointSyncAction( Request::new, ThreadPool.Names.MANAGEMENT ); - this.contextSwitcher = new SystemContextSwitcher(threadPool); } public void updateGlobalCheckpointForShard(final ShardId shardId) { - try (ThreadContext.StoredContext ignore = contextSwitcher.switchContext()) { + final ThreadContext threadContext = threadPool.getThreadContext(); + try (ThreadContext.StoredContext ignore = threadContext.stashContext()) { + threadContext.markAsSystemContext(); execute(new Request(shardId), ActionListener.wrap(r -> {}, e -> { if (ExceptionsHelper.unwrap(e, AlreadyClosedException.class, IndexShardClosedException.class) == null) { logger.info(new ParameterizedMessage("{} global checkpoint sync failed", shardId), e); diff --git a/server/src/main/java/org/opensearch/index/seqno/RetentionLeaseBackgroundSyncAction.java b/server/src/main/java/org/opensearch/index/seqno/RetentionLeaseBackgroundSyncAction.java index 7bdd2bbbb0af0..5fa0a1a6459e7 100644 --- a/server/src/main/java/org/opensearch/index/seqno/RetentionLeaseBackgroundSyncAction.java +++ b/server/src/main/java/org/opensearch/index/seqno/RetentionLeaseBackgroundSyncAction.java @@ -47,8 +47,6 @@ import org.opensearch.cluster.service.ClusterService; import org.opensearch.common.inject.Inject; import org.opensearch.common.settings.Settings; -import org.opensearch.common.util.concurrent.ContextSwitcher; -import org.opensearch.common.util.concurrent.SystemContextSwitcher; import org.opensearch.common.util.concurrent.ThreadContext; import org.opensearch.core.action.ActionListener; import org.opensearch.core.common.io.stream.StreamInput; @@ -86,8 +84,6 @@ public class RetentionLeaseBackgroundSyncAction extends TransportReplicationActi public static final String ACTION_NAME = "indices:admin/seq_no/retention_lease_background_sync"; private static final Logger LOGGER = LogManager.getLogger(RetentionLeaseSyncAction.class); - private final ContextSwitcher contextSwitcher; - protected Logger getLogger() { return LOGGER; } @@ -115,7 +111,6 @@ public RetentionLeaseBackgroundSyncAction( Request::new, ThreadPool.Names.MANAGEMENT ); - this.contextSwitcher = new SystemContextSwitcher(threadPool); } @Override @@ -124,7 +119,10 @@ protected void doExecute(Task task, Request request, ActionListener listener ) { - try (ThreadContext.StoredContext ignore = contextSwitcher.switchContext()) { + final ThreadContext threadContext = threadPool.getThreadContext(); + try (ThreadContext.StoredContext ignore = threadContext.stashContext()) { + // we have to execute under the system context so that if security is enabled the sync is authorized + threadContext.markAsSystemContext(); final Request request = new Request(shardId, retentionLeases); final ReplicationTask task = (ReplicationTask) taskManager.register("transport", "retention_lease_sync", request); transportService.sendChildRequest( diff --git a/server/src/main/java/org/opensearch/index/shard/IndexShard.java b/server/src/main/java/org/opensearch/index/shard/IndexShard.java index 10a5e34bf23f2..82b68b32f3bf8 100644 --- a/server/src/main/java/org/opensearch/index/shard/IndexShard.java +++ b/server/src/main/java/org/opensearch/index/shard/IndexShard.java @@ -4566,7 +4566,7 @@ private RefreshListeners buildRefreshListeners() { indexSettings::getMaxRefreshListeners, () -> refresh("too_many_listeners"), logger, - threadPool, + threadPool.getThreadContext(), externalRefreshMetric ); } diff --git a/server/src/main/java/org/opensearch/index/shard/RefreshListeners.java b/server/src/main/java/org/opensearch/index/shard/RefreshListeners.java index 38fe617e75157..aa3de72e4232e 100644 --- a/server/src/main/java/org/opensearch/index/shard/RefreshListeners.java +++ b/server/src/main/java/org/opensearch/index/shard/RefreshListeners.java @@ -37,12 +37,9 @@ import org.opensearch.common.collect.Tuple; import org.opensearch.common.lease.Releasable; import org.opensearch.common.metrics.MeanMetric; -import org.opensearch.common.util.concurrent.ContextSwitcher; import org.opensearch.common.util.concurrent.RunOnce; -import org.opensearch.common.util.concurrent.SystemContextSwitcher; import org.opensearch.common.util.concurrent.ThreadContext; import org.opensearch.index.translog.Translog; -import org.opensearch.threadpool.ThreadPool; import java.io.Closeable; import java.io.IOException; @@ -66,8 +63,7 @@ public final class RefreshListeners implements ReferenceManager.RefreshListener, private final IntSupplier getMaxRefreshListeners; private final Runnable forceRefresh; private final Logger logger; - private final ThreadPool threadPool; - private final ContextSwitcher contextSwitcher; + private final ThreadContext threadContext; private final MeanMetric refreshMetric; /** @@ -103,14 +99,13 @@ public RefreshListeners( final IntSupplier getMaxRefreshListeners, final Runnable forceRefresh, final Logger logger, - final ThreadPool threadPool, + ThreadContext threadContext, final MeanMetric refreshMetric ) { this.getMaxRefreshListeners = getMaxRefreshListeners; this.forceRefresh = forceRefresh; this.logger = logger; - this.threadPool = threadPool; - this.contextSwitcher = new SystemContextSwitcher(threadPool); + this.threadContext = threadContext; this.refreshMetric = refreshMetric; } @@ -165,9 +160,9 @@ public boolean addOrNotify(Translog.Location location, Consumer listene List>> listeners = refreshListeners; final int maxRefreshes = getMaxRefreshListeners.getAsInt(); if (refreshForcers == 0 && maxRefreshes > 0 && (listeners == null || listeners.size() < maxRefreshes)) { - ThreadContext.StoredContext storedContext = threadPool.getThreadContext().newStoredContext(true); + ThreadContext.StoredContext storedContext = threadContext.newStoredContext(true); Consumer contextPreservingListener = forced -> { - try (ThreadContext.StoredContext ignore = contextSwitcher.switchContext()) { + try (ThreadContext.StoredContext ignore = threadContext.stashContext()) { storedContext.restore(); listener.accept(forced); } diff --git a/server/src/main/java/org/opensearch/indices/replication/checkpoint/PublishCheckpointAction.java b/server/src/main/java/org/opensearch/indices/replication/checkpoint/PublishCheckpointAction.java index 364a7ffce5c42..8f39aa194b06c 100644 --- a/server/src/main/java/org/opensearch/indices/replication/checkpoint/PublishCheckpointAction.java +++ b/server/src/main/java/org/opensearch/indices/replication/checkpoint/PublishCheckpointAction.java @@ -23,8 +23,6 @@ import org.opensearch.common.annotation.PublicApi; import org.opensearch.common.inject.Inject; import org.opensearch.common.settings.Settings; -import org.opensearch.common.util.concurrent.ContextSwitcher; -import org.opensearch.common.util.concurrent.SystemContextSwitcher; import org.opensearch.common.util.concurrent.ThreadContext; import org.opensearch.core.action.ActionListener; import org.opensearch.core.common.io.stream.StreamInput; @@ -60,7 +58,6 @@ public class PublishCheckpointAction extends TransportReplicationAction< protected static Logger logger = LogManager.getLogger(PublishCheckpointAction.class); private final SegmentReplicationTargetService replicationService; - private final ContextSwitcher contextSwitcher; @Inject public PublishCheckpointAction( @@ -87,7 +84,6 @@ public PublishCheckpointAction( ThreadPool.Names.REFRESH ); this.replicationService = targetService; - this.contextSwitcher = new SystemContextSwitcher(threadPool); } @Override @@ -114,7 +110,10 @@ public ReplicationMode getReplicationMode(IndexShard indexShard) { final void publish(IndexShard indexShard, ReplicationCheckpoint checkpoint) { String primaryAllocationId = indexShard.routingEntry().allocationId().getId(); long primaryTerm = indexShard.getPendingPrimaryTerm(); - try (ThreadContext.StoredContext ignore = contextSwitcher.switchContext()) { + final ThreadContext threadContext = threadPool.getThreadContext(); + try (ThreadContext.StoredContext ignore = threadContext.stashContext()) { + // we have to execute under the system context so that if security is enabled the sync is authorized + threadContext.markAsSystemContext(); PublishCheckpointRequest request = new PublishCheckpointRequest(checkpoint); final ReplicationTask task = (ReplicationTask) taskManager.register("transport", "segrep_publish_checkpoint", request); final ReplicationTimer timer = new ReplicationTimer(); diff --git a/server/src/main/java/org/opensearch/transport/NativeMessageHandler.java b/server/src/main/java/org/opensearch/transport/NativeMessageHandler.java index ab1f665b05b76..4c972fdc14fa5 100644 --- a/server/src/main/java/org/opensearch/transport/NativeMessageHandler.java +++ b/server/src/main/java/org/opensearch/transport/NativeMessageHandler.java @@ -39,8 +39,6 @@ import org.opensearch.Version; import org.opensearch.common.util.BigArrays; import org.opensearch.common.util.concurrent.AbstractRunnable; -import org.opensearch.common.util.concurrent.ContextSwitcher; -import org.opensearch.common.util.concurrent.SystemContextSwitcher; import org.opensearch.common.util.concurrent.ThreadContext; import org.opensearch.core.common.io.stream.ByteBufferStreamInput; import org.opensearch.core.common.io.stream.NamedWriteableAwareStreamInput; @@ -76,7 +74,6 @@ public class NativeMessageHandler implements ProtocolMessageHandler { private static final Logger logger = LogManager.getLogger(NativeMessageHandler.class); private final ThreadPool threadPool; - private final ContextSwitcher contextSwitcher; private final NativeOutboundHandler outboundHandler; private final NamedWriteableRegistry namedWriteableRegistry; private final TransportHandshaker handshaker; @@ -102,7 +99,6 @@ public class NativeMessageHandler implements ProtocolMessageHandler { TransportKeepAlive keepAlive ) { this.threadPool = threadPool; - this.contextSwitcher = new SystemContextSwitcher(threadPool); this.outboundHandler = new NativeOutboundHandler(nodeName, version, features, statsTracker, threadPool, bigArrays, outboundHandler); this.namedWriteableRegistry = namedWriteableRegistry; this.handshaker = handshaker; @@ -143,7 +139,7 @@ private void handleMessage( final Header header = message.getHeader(); assert header.needsToReadVariableHeader() == false; ThreadContext threadContext = threadPool.getThreadContext(); - try (ThreadContext.StoredContext existing = contextSwitcher.switchContext()) { + try (ThreadContext.StoredContext existing = threadContext.stashContext()) { // Place the context with the headers from the message threadContext.setHeaders(header.getHeaders()); threadContext.putTransient("_remote_address", remoteAddress); diff --git a/server/src/main/java/org/opensearch/transport/OutboundHandler.java b/server/src/main/java/org/opensearch/transport/OutboundHandler.java index 5d89ec5cc2d5c..43f53e4011260 100644 --- a/server/src/main/java/org/opensearch/transport/OutboundHandler.java +++ b/server/src/main/java/org/opensearch/transport/OutboundHandler.java @@ -40,8 +40,6 @@ import org.opensearch.common.lease.Releasables; import org.opensearch.common.network.CloseableChannel; import org.opensearch.common.transport.NetworkExceptionHelper; -import org.opensearch.common.util.concurrent.ContextSwitcher; -import org.opensearch.common.util.concurrent.SystemContextSwitcher; import org.opensearch.common.util.concurrent.ThreadContext; import org.opensearch.core.action.ActionListener; import org.opensearch.core.action.NotifyOnceListener; @@ -61,12 +59,10 @@ public final class OutboundHandler { private final StatsTracker statsTracker; private final ThreadPool threadPool; - private final ContextSwitcher contextSwitcher; public OutboundHandler(StatsTracker statsTracker, ThreadPool threadPool) { this.statsTracker = statsTracker; this.threadPool = threadPool; - this.contextSwitcher = new SystemContextSwitcher(threadPool); } void sendBytes(TcpChannel channel, BytesReference bytes, ActionListener listener) { @@ -83,7 +79,7 @@ public void sendBytes(TcpChannel channel, SendContext sendContext) throws IOExce channel.getChannelStats().markAccessed(threadPool.relativeTimeInMillis()); BytesReference reference = sendContext.get(); // stash thread context so that channel event loop is not polluted by thread context - try (ThreadContext.StoredContext existing = contextSwitcher.switchContext()) { + try (ThreadContext.StoredContext existing = threadPool.getThreadContext().stashContext()) { channel.sendMessage(reference, sendContext); } catch (RuntimeException ex) { sendContext.onFailure(ex); diff --git a/server/src/main/java/org/opensearch/transport/RemoteClusterConnection.java b/server/src/main/java/org/opensearch/transport/RemoteClusterConnection.java index 56cb6e1f51369..8a5f6dfffb036 100644 --- a/server/src/main/java/org/opensearch/transport/RemoteClusterConnection.java +++ b/server/src/main/java/org/opensearch/transport/RemoteClusterConnection.java @@ -39,8 +39,6 @@ import org.opensearch.cluster.node.DiscoveryNodes; import org.opensearch.common.settings.Settings; import org.opensearch.common.unit.TimeValue; -import org.opensearch.common.util.concurrent.ContextSwitcher; -import org.opensearch.common.util.concurrent.SystemContextSwitcher; import org.opensearch.common.util.concurrent.ThreadContext; import org.opensearch.common.util.io.IOUtils; import org.opensearch.core.action.ActionListener; @@ -73,7 +71,6 @@ final class RemoteClusterConnection implements Closeable { private final RemoteConnectionStrategy connectionStrategy; private final String clusterAlias; private final ThreadPool threadPool; - private final ContextSwitcher contextSwitcher; private volatile boolean skipUnavailable; private final TimeValue initialConnectionTimeout; @@ -94,7 +91,6 @@ final class RemoteClusterConnection implements Closeable { this.skipUnavailable = RemoteClusterService.REMOTE_CLUSTER_SKIP_UNAVAILABLE.getConcreteSettingForNamespace(clusterAlias) .get(settings); this.threadPool = transportService.threadPool; - this.contextSwitcher = new SystemContextSwitcher(this.threadPool); initialConnectionTimeout = RemoteClusterService.REMOTE_INITIAL_CONNECTION_TIMEOUT_SETTING.get(settings); } @@ -138,7 +134,9 @@ void collectNodes(ActionListener> listener) { final ThreadContext threadContext = threadPool.getThreadContext(); final ContextPreservingActionListener> contextPreservingActionListener = new ContextPreservingActionListener<>(threadContext.newRestorableContext(false), listener); - try (ThreadContext.StoredContext ignore = contextSwitcher.switchContext()) { + try (ThreadContext.StoredContext ignore = threadContext.stashContext()) { + // we stash any context here since this is an internal execution and should not leak any existing context information + threadContext.markAsSystemContext(); final ClusterStateRequest request = new ClusterStateRequest(); request.clear(); diff --git a/server/src/main/java/org/opensearch/transport/SniffConnectionStrategy.java b/server/src/main/java/org/opensearch/transport/SniffConnectionStrategy.java index 7bc876a81b63a..07ba96b135189 100644 --- a/server/src/main/java/org/opensearch/transport/SniffConnectionStrategy.java +++ b/server/src/main/java/org/opensearch/transport/SniffConnectionStrategy.java @@ -46,8 +46,6 @@ import org.opensearch.common.UUIDs; import org.opensearch.common.settings.Setting; import org.opensearch.common.settings.Settings; -import org.opensearch.common.util.concurrent.ContextSwitcher; -import org.opensearch.common.util.concurrent.SystemContextSwitcher; import org.opensearch.common.util.concurrent.ThreadContext; import org.opensearch.common.util.io.IOUtils; import org.opensearch.core.action.ActionListener; @@ -151,7 +149,6 @@ public class SniffConnectionStrategy extends RemoteConnectionStrategy { private final Predicate nodePredicate; private final SetOnce remoteClusterName = new SetOnce<>(); private final String proxyAddress; - private final ContextSwitcher contextSwitcher; SniffConnectionStrategy( String clusterAlias, @@ -213,7 +210,6 @@ public class SniffConnectionStrategy extends RemoteConnectionStrategy { this.nodePredicate = nodePredicate; this.configuredSeedNodes = configuredSeedNodes; this.seedNodes = seedNodes; - this.contextSwitcher = new SystemContextSwitcher(transportService.getThreadPool()); } static Stream> enablementSettings() { @@ -350,7 +346,10 @@ private void collectRemoteNodes(Iterator> seedNodes, Act threadContext.newRestorableContext(false), new SniffClusterStateResponseHandler(connection, listener, seedNodes) ); - try (ThreadContext.StoredContext ignore = contextSwitcher.switchContext()) { + try (ThreadContext.StoredContext ignore = threadContext.stashContext()) { + // we stash any context here since this is an internal execution and should not leak any + // existing context information. + threadContext.markAsSystemContext(); transportService.sendRequest( connection, ClusterStateAction.NAME, diff --git a/server/src/test/java/org/opensearch/action/bulk/BulkProcessorTests.java b/server/src/test/java/org/opensearch/action/bulk/BulkProcessorTests.java index 51ad848e9e12c..6ff3ba473b5e9 100644 --- a/server/src/test/java/org/opensearch/action/bulk/BulkProcessorTests.java +++ b/server/src/test/java/org/opensearch/action/bulk/BulkProcessorTests.java @@ -37,8 +37,6 @@ import org.opensearch.ExceptionsHelper; import org.opensearch.action.index.IndexRequest; import org.opensearch.common.unit.TimeValue; -import org.opensearch.common.util.concurrent.ContextSwitcher; -import org.opensearch.common.util.concurrent.SystemContextSwitcher; import org.opensearch.common.util.concurrent.ThreadContext; import org.opensearch.core.action.ActionListener; import org.opensearch.core.common.bytes.BytesReference; @@ -70,13 +68,11 @@ public class BulkProcessorTests extends OpenSearchTestCase { private ThreadPool threadPool; - private ContextSwitcher contextSwitcher; private final Logger logger = LogManager.getLogger(BulkProcessorTests.class); @Before public void startThreadPool() { threadPool = new TestThreadPool("BulkProcessorTests"); - contextSwitcher = new SystemContextSwitcher(threadPool); } @After @@ -103,7 +99,7 @@ public void testBulkProcessorFlushPreservesContext() throws InterruptedException final BulkProcessor bulkProcessor; assertNull(threadPool.getThreadContext().getHeader(headerKey)); assertNull(threadPool.getThreadContext().getTransient(transientKey)); - try (ThreadContext.StoredContext ignore = contextSwitcher.switchContext()) { + try (ThreadContext.StoredContext ignore = threadPool.getThreadContext().stashContext()) { threadPool.getThreadContext().putHeader(headerKey, headerValue); threadPool.getThreadContext().putTransient(transientKey, transientValue); bulkProcessor = new BulkProcessor( diff --git a/server/src/test/java/org/opensearch/action/support/ContextPreservingActionListenerTests.java b/server/src/test/java/org/opensearch/action/support/ContextPreservingActionListenerTests.java index bae24ec3b5970..0b9f2c6707c02 100644 --- a/server/src/test/java/org/opensearch/action/support/ContextPreservingActionListenerTests.java +++ b/server/src/test/java/org/opensearch/action/support/ContextPreservingActionListenerTests.java @@ -31,13 +31,10 @@ package org.opensearch.action.support; -import org.opensearch.common.util.concurrent.ContextSwitcher; -import org.opensearch.common.util.concurrent.SystemContextSwitcher; +import org.opensearch.common.settings.Settings; import org.opensearch.common.util.concurrent.ThreadContext; import org.opensearch.core.action.ActionListener; import org.opensearch.test.OpenSearchTestCase; -import org.opensearch.threadpool.TestThreadPool; -import org.opensearch.threadpool.ThreadPool; import java.io.IOException; @@ -47,15 +44,13 @@ public class ContextPreservingActionListenerTests extends OpenSearchTestCase { public void testOriginalContextIsPreservedAfterOnResponse() throws IOException { - ThreadPool threadPool = new TestThreadPool("ContextPreservingActionListenerTests.testOriginalContextIsPreservedAfterOnResponse"); - ThreadContext threadContext = threadPool.getThreadContext(); - ContextSwitcher contextSwitcher = new SystemContextSwitcher(threadPool); + ThreadContext threadContext = new ThreadContext(Settings.EMPTY); final boolean nonEmptyContext = randomBoolean(); if (nonEmptyContext) { threadContext.putHeader("not empty", "value"); } final ContextPreservingActionListener actionListener; - try (ThreadContext.StoredContext ignore = contextSwitcher.switchContext()) { + try (ThreadContext.StoredContext ignore = threadContext.stashContext()) { threadContext.putHeader("foo", "bar"); final ActionListener delegate = new ActionListener() { @Override @@ -86,15 +81,13 @@ public void onFailure(Exception e) { } public void testOriginalContextIsPreservedAfterOnFailure() throws Exception { - ThreadPool threadPool = new TestThreadPool("ContextPreservingActionListenerTests.testOriginalContextIsPreservedAfterOnFailure"); - ThreadContext threadContext = threadPool.getThreadContext(); - ContextSwitcher contextSwitcher = new SystemContextSwitcher(threadPool); + ThreadContext threadContext = new ThreadContext(Settings.EMPTY); final boolean nonEmptyContext = randomBoolean(); if (nonEmptyContext) { threadContext.putHeader("not empty", "value"); } final ContextPreservingActionListener actionListener; - try (ThreadContext.StoredContext ignore = contextSwitcher.switchContext()) { + try (ThreadContext.StoredContext ignore = threadContext.stashContext()) { threadContext.putHeader("foo", "bar"); final ActionListener delegate = new ActionListener() { @Override @@ -127,15 +120,13 @@ public void onFailure(Exception e) { } public void testOriginalContextIsWhenListenerThrows() throws Exception { - ThreadPool threadPool = new TestThreadPool("ContextPreservingActionListenerTests.testOriginalContextIsWhenListenerThrows"); - ThreadContext threadContext = threadPool.getThreadContext(); - ContextSwitcher contextSwitcher = new SystemContextSwitcher(threadPool); + ThreadContext threadContext = new ThreadContext(Settings.EMPTY); final boolean nonEmptyContext = randomBoolean(); if (nonEmptyContext) { threadContext.putHeader("not empty", "value"); } final ContextPreservingActionListener actionListener; - try (ThreadContext.StoredContext ignore = contextSwitcher.switchContext()) { + try (ThreadContext.StoredContext ignore = threadContext.stashContext()) { threadContext.putHeader("foo", "bar"); final ActionListener delegate = new ActionListener() { @Override @@ -177,11 +168,9 @@ public void onFailure(Exception e) { } public void testToStringIncludesDelegate() { - ThreadPool threadPool = new TestThreadPool("ContextPreservingActionListenerTests.testToStringIncludesDelegate"); - ThreadContext threadContext = threadPool.getThreadContext(); - ContextSwitcher contextSwitcher = new SystemContextSwitcher(threadPool); + ThreadContext threadContext = new ThreadContext(Settings.EMPTY); final ContextPreservingActionListener actionListener; - try (ThreadContext.StoredContext ignore = contextSwitcher.switchContext()) { + try (ThreadContext.StoredContext ignore = threadContext.stashContext()) { final ActionListener delegate = new ActionListener() { @Override public void onResponse(Void aVoid) {} diff --git a/server/src/test/java/org/opensearch/cluster/metadata/TemplateUpgradeServiceTests.java b/server/src/test/java/org/opensearch/cluster/metadata/TemplateUpgradeServiceTests.java index fe42515846828..36d984b7eb99b 100644 --- a/server/src/test/java/org/opensearch/cluster/metadata/TemplateUpgradeServiceTests.java +++ b/server/src/test/java/org/opensearch/cluster/metadata/TemplateUpgradeServiceTests.java @@ -46,8 +46,6 @@ import org.opensearch.cluster.node.DiscoveryNodes; import org.opensearch.cluster.service.ClusterService; import org.opensearch.common.collect.Tuple; -import org.opensearch.common.util.concurrent.ContextSwitcher; -import org.opensearch.common.util.concurrent.SystemContextSwitcher; import org.opensearch.common.util.concurrent.ThreadContext; import org.opensearch.core.action.ActionListener; import org.opensearch.core.common.bytes.BytesArray; @@ -92,12 +90,10 @@ public class TemplateUpgradeServiceTests extends OpenSearchTestCase { private ThreadPool threadPool; private ClusterService clusterService; - private ContextSwitcher contextSwitcher; @Before public void setUpTest() throws Exception { threadPool = new TestThreadPool("TemplateUpgradeServiceTests"); - contextSwitcher = new SystemContextSwitcher(threadPool); clusterService = createClusterService(threadPool); } @@ -227,7 +223,9 @@ public void testUpdateTemplates() { assertThat(ise.getMessage(), containsString("template upgrade service should always happen in a system context")); service.upgradesInProgress.set(additionsCount + deletionsCount + 2); // +2 to skip tryFinishUpgrade - try (ThreadContext.StoredContext ignore = contextSwitcher.switchContext()) { + final ThreadContext threadContext = threadPool.getThreadContext(); + try (ThreadContext.StoredContext ignore = threadContext.stashContext()) { + threadContext.markAsSystemContext(); service.upgradeTemplates(additions, deletions); } diff --git a/server/src/test/java/org/opensearch/cluster/service/ClusterApplierServiceTests.java b/server/src/test/java/org/opensearch/cluster/service/ClusterApplierServiceTests.java index f2585312d3a28..be6057a391b2e 100644 --- a/server/src/test/java/org/opensearch/cluster/service/ClusterApplierServiceTests.java +++ b/server/src/test/java/org/opensearch/cluster/service/ClusterApplierServiceTests.java @@ -51,8 +51,6 @@ import org.opensearch.common.settings.ClusterSettings; import org.opensearch.common.settings.Settings; import org.opensearch.common.unit.TimeValue; -import org.opensearch.common.util.concurrent.ContextSwitcher; -import org.opensearch.common.util.concurrent.SystemContextSwitcher; import org.opensearch.common.util.concurrent.ThreadContext; import org.opensearch.telemetry.metrics.Histogram; import org.opensearch.telemetry.metrics.MetricsRegistry; @@ -93,7 +91,6 @@ public class ClusterApplierServiceTests extends OpenSearchTestCase { private static ThreadPool threadPool; - private static ContextSwitcher contextSwitcher; private TimedClusterApplierService clusterApplierService; private static MetricsRegistry metricsRegistry; private static Histogram applierslatencyHistogram; @@ -102,7 +99,6 @@ public class ClusterApplierServiceTests extends OpenSearchTestCase { @BeforeClass public static void createThreadPool() { threadPool = new TestThreadPool(ClusterApplierServiceTests.class.getName()); - contextSwitcher = new SystemContextSwitcher(threadPool); metricsRegistry = mock(MetricsRegistry.class); applierslatencyHistogram = mock(Histogram.class); listenerslatencyHistogram = mock(Histogram.class); @@ -638,7 +634,7 @@ public void onFailure(String source, Exception e) { public void testThreadContext() throws InterruptedException { final CountDownLatch latch = new CountDownLatch(1); - try (ThreadContext.StoredContext ignored = contextSwitcher.switchContext()) { + try (ThreadContext.StoredContext ignored = threadPool.getThreadContext().stashContext()) { final Map expectedHeaders = Collections.singletonMap("test", "test"); final Map> expectedResponseHeaders = Collections.singletonMap( "testResponse", diff --git a/server/src/test/java/org/opensearch/cluster/service/MasterServiceTests.java b/server/src/test/java/org/opensearch/cluster/service/MasterServiceTests.java index 6a464f56b0669..7562dfc2e9d33 100644 --- a/server/src/test/java/org/opensearch/cluster/service/MasterServiceTests.java +++ b/server/src/test/java/org/opensearch/cluster/service/MasterServiceTests.java @@ -60,8 +60,6 @@ import org.opensearch.common.settings.Settings; import org.opensearch.common.unit.TimeValue; import org.opensearch.common.util.concurrent.BaseFuture; -import org.opensearch.common.util.concurrent.ContextSwitcher; -import org.opensearch.common.util.concurrent.SystemContextSwitcher; import org.opensearch.common.util.concurrent.ThreadContext; import org.opensearch.node.Node; import org.opensearch.telemetry.metrics.Histogram; @@ -113,7 +111,6 @@ public class MasterServiceTests extends OpenSearchTestCase { private static ThreadPool threadPool; - private static ContextSwitcher contextSwitcher; private static long timeDiffInMillis; @BeforeClass @@ -124,7 +121,6 @@ public long preciseRelativeTimeInNanos() { return timeDiffInMillis * TimeValue.NSEC_PER_MSEC; } }; - contextSwitcher = new SystemContextSwitcher(threadPool); } @AfterClass @@ -250,7 +246,7 @@ public void testThreadContext() throws InterruptedException { final ClusterManagerService clusterManagerService = createClusterManagerService(true); final CountDownLatch latch = new CountDownLatch(1); - try (ThreadContext.StoredContext ignored = contextSwitcher.switchContext()) { + try (ThreadContext.StoredContext ignored = threadPool.getThreadContext().stashContext()) { final Map expectedHeaders = Collections.singletonMap("test", "test"); final Map> expectedResponseHeaders = Collections.singletonMap( "testResponse", diff --git a/server/src/test/java/org/opensearch/index/shard/RefreshListenersTests.java b/server/src/test/java/org/opensearch/index/shard/RefreshListenersTests.java index 917b6a4843311..8a77fbca2915d 100644 --- a/server/src/test/java/org/opensearch/index/shard/RefreshListenersTests.java +++ b/server/src/test/java/org/opensearch/index/shard/RefreshListenersTests.java @@ -49,8 +49,6 @@ import org.opensearch.common.settings.Settings; import org.opensearch.common.unit.TimeValue; import org.opensearch.common.util.BigArrays; -import org.opensearch.common.util.concurrent.ContextSwitcher; -import org.opensearch.common.util.concurrent.SystemContextSwitcher; import org.opensearch.common.util.concurrent.ThreadContext; import org.opensearch.common.util.io.IOUtils; import org.opensearch.core.common.bytes.BytesArray; @@ -107,7 +105,6 @@ public class RefreshListenersTests extends OpenSearchTestCase { private Engine engine; private volatile int maxListeners; private ThreadPool threadPool; - private ContextSwitcher contextSwitcher; private Store store; private MeanMetric refreshMetric; @@ -117,9 +114,14 @@ public void setupListeners() throws Exception { maxListeners = randomIntBetween(1, 1000); // Now setup the InternalEngine which is much more complicated because we aren't mocking anything threadPool = new TestThreadPool(getTestName()); - contextSwitcher = new SystemContextSwitcher(threadPool); refreshMetric = new MeanMetric(); - listeners = new RefreshListeners(() -> maxListeners, () -> engine.refresh("too-many-listeners"), logger, threadPool, refreshMetric); + listeners = new RefreshListeners( + () -> maxListeners, + () -> engine.refresh("too-many-listeners"), + logger, + threadPool.getThreadContext(), + refreshMetric + ); IndexSettings indexSettings = IndexSettingsModule.newIndexSettings("index", Settings.EMPTY); ShardId shardId = new ShardId(new Index("index", "_na_"), 1); @@ -216,7 +218,7 @@ public void testContextIsPreserved() throws IOException, InterruptedException { assertEquals(0, listeners.pendingCount()); Engine.IndexResult index = index("1"); CountDownLatch latch = new CountDownLatch(1); - try (ThreadContext.StoredContext ignore = contextSwitcher.switchContext()) { + try (ThreadContext.StoredContext ignore = threadPool.getThreadContext().stashContext()) { threadPool.getThreadContext().putHeader("test", "foobar"); assertFalse(listeners.addOrNotify(index.getTranslogLocation(), forced -> { assertEquals("foobar", threadPool.getThreadContext().getHeader("test")); diff --git a/server/src/test/java/org/opensearch/telemetry/tracing/ThreadContextBasedTracerContextStorageTests.java b/server/src/test/java/org/opensearch/telemetry/tracing/ThreadContextBasedTracerContextStorageTests.java index 729de1d9f7bc1..4c7480fe468fb 100644 --- a/server/src/test/java/org/opensearch/telemetry/tracing/ThreadContextBasedTracerContextStorageTests.java +++ b/server/src/test/java/org/opensearch/telemetry/tracing/ThreadContextBasedTracerContextStorageTests.java @@ -12,8 +12,6 @@ import org.opensearch.common.settings.ClusterSettings; import org.opensearch.common.settings.Settings; -import org.opensearch.common.util.concurrent.ContextSwitcher; -import org.opensearch.common.util.concurrent.SystemContextSwitcher; import org.opensearch.common.util.concurrent.ThreadContext; import org.opensearch.common.util.concurrent.ThreadContext.StoredContext; import org.opensearch.telemetry.Telemetry; @@ -22,7 +20,6 @@ import org.opensearch.telemetry.tracing.noop.NoopTracer; import org.opensearch.test.OpenSearchTestCase; import org.opensearch.test.telemetry.tracing.MockTracingTelemetry; -import org.opensearch.threadpool.TestThreadPool; import org.opensearch.threadpool.ThreadPool; import org.junit.After; import org.junit.Before; @@ -70,9 +67,7 @@ public void setUp() throws Exception { final TracingTelemetry tracingTelemetry = new MockTracingTelemetry(); - threadPool = new TestThreadPool(getTestName()); - threadContext = threadPool.getThreadContext(); - contextSwitcher = new SystemContextSwitcher(threadPool); + threadContext = new ThreadContext(Settings.EMPTY); threadContextStorage = new ThreadContextBasedTracerContextStorage(threadContext, tracingTelemetry); tracer = new TracerFactory(telemetrySettings, Optional.of(new Telemetry() { @@ -127,7 +122,7 @@ public void testStashingPropagatesThreadContext() { final Span span = tracer.startSpan(SpanCreationContext.internal().name("test")); try (SpanScope scope = tracer.withSpanInScope(span)) { - try (StoredContext ignored = contextSwitcher.switchContext()) { + try (StoredContext ignored = threadContext.stashContext()) { assertThat(threadContext.getTransient(ThreadContextBasedTracerContextStorage.CURRENT_SPAN), is(not(nullValue()))); assertThat(threadContextStorage.get(ThreadContextBasedTracerContextStorage.CURRENT_SPAN), is(span)); } @@ -165,7 +160,7 @@ public void run() { final Span local1 = tracer.startSpan(SpanCreationContext.internal().name("test-local-1")); try (SpanScope localScope = tracer.withSpanInScope(local1)) { - try (StoredContext ignored = contextSwitcher.switchContext()) { + try (StoredContext ignored = threadContext.stashContext()) { assertThat(local1.getParentSpan(), is(nullValue())); assertThat(threadContextStorage.get(ThreadContextBasedTracerContextStorage.CURRENT_SPAN), is(local1)); } @@ -173,7 +168,7 @@ public void run() { final Span local2 = tracer.startSpan(SpanCreationContext.internal().name("test-local-2")); try (SpanScope localScope = tracer.withSpanInScope(local2)) { - try (StoredContext ignored = contextSwitcher.switchContext()) { + try (StoredContext ignored = threadContext.stashContext()) { assertThat(local2.getParentSpan(), is(nullValue())); assertThat(threadContextStorage.get(ThreadContextBasedTracerContextStorage.CURRENT_SPAN), is(local2)); } @@ -181,7 +176,7 @@ public void run() { final Span local3 = tracer.startSpan(SpanCreationContext.internal().name("test-local-3")); try (SpanScope localScope = tracer.withSpanInScope(local3)) { - try (StoredContext ignored = contextSwitcher.switchContext()) { + try (StoredContext ignored = threadContext.stashContext()) { assertThat(local3.getParentSpan(), is(nullValue())); assertThat(threadContextStorage.get(ThreadContextBasedTracerContextStorage.CURRENT_SPAN), is(local3)); } @@ -206,7 +201,7 @@ public void run() { final Span local1 = tracer.startSpan(SpanCreationContext.internal().name("test-local-1")); try (SpanScope localScope = tracer.withSpanInScope(local1)) { - try (StoredContext ignored = contextSwitcher.switchContext()) { + try (StoredContext ignored = threadContext.stashContext()) { assertThat(local1.getParentSpan(), is(span)); assertThat(threadContextStorage.get(ThreadContextBasedTracerContextStorage.CURRENT_SPAN), is(local1)); } @@ -214,7 +209,7 @@ public void run() { final Span local2 = tracer.startSpan(SpanCreationContext.internal().name("test-local-2")); try (SpanScope localScope = tracer.withSpanInScope(local2)) { - try (StoredContext ignored = contextSwitcher.switchContext()) { + try (StoredContext ignored = threadContext.stashContext()) { assertThat(local2.getParentSpan(), is(span)); assertThat(threadContextStorage.get(ThreadContextBasedTracerContextStorage.CURRENT_SPAN), is(local2)); } @@ -222,7 +217,7 @@ public void run() { final Span local3 = tracer.startSpan(SpanCreationContext.internal().name("test-local-3")); try (SpanScope localScope = tracer.withSpanInScope(local3)) { - try (StoredContext ignored = contextSwitcher.switchContext()) { + try (StoredContext ignored = threadContext.stashContext()) { assertThat(local3.getParentSpan(), is(span)); assertThat(threadContextStorage.get(ThreadContextBasedTracerContextStorage.CURRENT_SPAN), is(local3)); } @@ -246,7 +241,7 @@ public void testPreservingContextAndStashingThreadContext() throws InterruptedEx public void run() { final Span local = tracer.startSpan(SpanCreationContext.internal().name("test-local")); try (SpanScope localScope = tracer.withSpanInScope(local)) { - try (StoredContext ignored = contextSwitcher.switchContext()) { + try (StoredContext ignored = threadContext.stashContext()) { assertThat( threadContext.getTransient(ThreadContextBasedTracerContextStorage.CURRENT_SPAN), is(not(nullValue())) @@ -268,9 +263,11 @@ public void testSpanNotPropagatedToChildSystemThreadContext() { final Span span = tracer.startSpan(SpanCreationContext.internal().name("test")); try (SpanScope scope = tracer.withSpanInScope(span)) { - try (StoredContext ignored = contextSwitcher.switchContext()) { + try (StoredContext ignored = threadContext.stashContext()) { assertThat(threadContext.getTransient(ThreadContextBasedTracerContextStorage.CURRENT_SPAN), is(not(nullValue()))); assertThat(threadContextStorage.get(ThreadContextBasedTracerContextStorage.CURRENT_SPAN), is(span)); + threadContext.markAsSystemContext(); + assertThat(threadContext.getTransient(ThreadContextBasedTracerContextStorage.CURRENT_SPAN), is(nullValue())); } } diff --git a/test/framework/src/main/java/org/opensearch/cluster/service/FakeThreadPoolClusterManagerService.java b/test/framework/src/main/java/org/opensearch/cluster/service/FakeThreadPoolClusterManagerService.java index cf216fc4b2d69..53ef595c7931e 100644 --- a/test/framework/src/main/java/org/opensearch/cluster/service/FakeThreadPoolClusterManagerService.java +++ b/test/framework/src/main/java/org/opensearch/cluster/service/FakeThreadPoolClusterManagerService.java @@ -41,10 +41,8 @@ import org.opensearch.common.settings.ClusterSettings; import org.opensearch.common.settings.Settings; import org.opensearch.common.unit.TimeValue; -import org.opensearch.common.util.concurrent.ContextSwitcher; import org.opensearch.common.util.concurrent.OpenSearchExecutors; import org.opensearch.common.util.concurrent.PrioritizedOpenSearchThreadPoolExecutor; -import org.opensearch.common.util.concurrent.SystemContextSwitcher; import org.opensearch.common.util.concurrent.ThreadContext; import org.opensearch.core.action.ActionListener; import org.opensearch.node.Node; @@ -65,7 +63,6 @@ public class FakeThreadPoolClusterManagerService extends ClusterManagerService { private final String name; private final List pendingTasks = new ArrayList<>(); private final Consumer onTaskAvailableToRun; - private final ContextSwitcher contextSwitcher; private boolean scheduledNextTask = false; private boolean taskInProgress = false; private boolean waitForPublish = false; @@ -84,7 +81,6 @@ public FakeThreadPoolClusterManagerService( ); this.name = serviceName; this.onTaskAvailableToRun = onTaskAvailableToRun; - this.contextSwitcher = new SystemContextSwitcher(threadPool); } @Override @@ -136,7 +132,9 @@ public void run() { final Runnable task = pendingTasks.remove(taskIndex); taskInProgress = true; scheduledNextTask = false; - try (ThreadContext.StoredContext ignored = contextSwitcher.switchContext()) { + final ThreadContext threadContext = threadPool.getThreadContext(); + try (ThreadContext.StoredContext ignored = threadContext.stashContext()) { + threadContext.markAsSystemContext(); task.run(); } if (waitForPublish == false) { From dd8e7c3b2563e30cf2f4c622f54ca3d2d75ad981 Mon Sep 17 00:00:00 2001 From: Craig Perkins Date: Fri, 2 Aug 2024 16:33:37 -0400 Subject: [PATCH 21/65] Merge with main Signed-off-by: Craig Perkins --- .../test/java/org/opensearch/action/bulk/RetryTests.java | 2 +- .../common/util/concurrent/ThreadContextTests.java | 6 +++--- 2 files changed, 4 insertions(+), 4 deletions(-) diff --git a/server/src/test/java/org/opensearch/action/bulk/RetryTests.java b/server/src/test/java/org/opensearch/action/bulk/RetryTests.java index 6d90e910c6ce4..aa33372239fed 100644 --- a/server/src/test/java/org/opensearch/action/bulk/RetryTests.java +++ b/server/src/test/java/org/opensearch/action/bulk/RetryTests.java @@ -72,7 +72,7 @@ public void setUp() throws Exception { super.setUp(); this.bulkClient = new MockBulkClient(getTestName(), CALLS_TO_FAIL); // Stash some random headers so we can assert that we preserve them - // bulkClient.threadPool().getThreadContext().stashContext(); + bulkClient.threadPool().getThreadContext().stashContext(); expectedHeaders.clear(); expectedHeaders.put(randomAlphaOfLength(5), randomAlphaOfLength(5)); bulkClient.threadPool().getThreadContext().putHeader(expectedHeaders); diff --git a/server/src/test/java/org/opensearch/common/util/concurrent/ThreadContextTests.java b/server/src/test/java/org/opensearch/common/util/concurrent/ThreadContextTests.java index c8415766e9381..5992ffa1465b4 100644 --- a/server/src/test/java/org/opensearch/common/util/concurrent/ThreadContextTests.java +++ b/server/src/test/java/org/opensearch/common/util/concurrent/ThreadContextTests.java @@ -584,7 +584,7 @@ public void testPreservesThreadsOriginalContextOnRunException() throws IOExcepti @Override public void onAfter() { - assertTrue(threadContext.isSystemContext()); + assertEquals(systemContext, threadContext.isSystemContext()); assertEquals("bar", threadContext.getHeader("foo")); assertEquals("bar_transient", threadContext.getTransient("foo")); assertNotNull(threadContext.getTransient("failure")); @@ -595,7 +595,7 @@ public void onAfter() { @Override public void onFailure(Exception e) { - assertTrue(threadContext.isSystemContext()); + assertEquals(systemContext, threadContext.isSystemContext()); assertEquals("exception from doRun", e.getMessage()); assertEquals("bar", threadContext.getHeader("foo")); assertEquals("bar_transient", threadContext.getTransient("foo")); @@ -605,7 +605,7 @@ public void onFailure(Exception e) { @Override protected void doRun() throws Exception { - assertTrue(threadContext.isSystemContext()); + assertEquals(systemContext, threadContext.isSystemContext()); assertEquals("bar", threadContext.getHeader("foo")); assertEquals("bar_transient", threadContext.getTransient("foo")); assertFalse(threadContext.isDefaultContext()); From 2ff8f86fbc999a990bd31eb0b6e9b9937ac01fdc Mon Sep 17 00:00:00 2001 From: Craig Perkins Date: Fri, 2 Aug 2024 16:36:18 -0400 Subject: [PATCH 22/65] Cleanup Signed-off-by: Craig Perkins --- .../tracing/ThreadContextBasedTracerContextStorageTests.java | 1 - 1 file changed, 1 deletion(-) diff --git a/server/src/test/java/org/opensearch/telemetry/tracing/ThreadContextBasedTracerContextStorageTests.java b/server/src/test/java/org/opensearch/telemetry/tracing/ThreadContextBasedTracerContextStorageTests.java index 66b87c04cc021..b48f02217f0d0 100644 --- a/server/src/test/java/org/opensearch/telemetry/tracing/ThreadContextBasedTracerContextStorageTests.java +++ b/server/src/test/java/org/opensearch/telemetry/tracing/ThreadContextBasedTracerContextStorageTests.java @@ -45,7 +45,6 @@ public class ThreadContextBasedTracerContextStorageTests extends OpenSearchTestCase { private Tracer tracer; private ThreadPool threadPool; - private ContextSwitcher contextSwitcher; private ThreadContext threadContext; private TracerContextStorage threadContextStorage; private ExecutorService executorService; From b006ed5bf934e95b87a0f8fd22441fb87cc7804e Mon Sep 17 00:00:00 2001 From: Craig Perkins Date: Fri, 2 Aug 2024 16:38:38 -0400 Subject: [PATCH 23/65] Remove SystemIndexFilter Signed-off-by: Craig Perkins --- README.md | 2 +- .../opensearch/action/SystemIndexFilter.java | 66 ------------------- 2 files changed, 1 insertion(+), 67 deletions(-) delete mode 100644 server/src/main/java/org/opensearch/action/SystemIndexFilter.java diff --git a/README.md b/README.md index 5d4a9a671c013..17af2911b9221 100644 --- a/README.md +++ b/README.md @@ -7,7 +7,7 @@ [![Security Vulnerabilities](https://img.shields.io/github/issues/opensearch-project/OpenSearch/security%20vulnerability?labelColor=red)](https://github.com/opensearch-project/OpenSearch/issues?q=is%3Aissue+is%3Aopen+label%3A"security%20vulnerability") [![Open Issues](https://img.shields.io/github/issues/opensearch-project/OpenSearch)](https://github.com/opensearch-project/OpenSearch/issues) [![Open Pull Requests](https://img.shields.io/github/issues-pr/opensearch-project/OpenSearch)](https://github.com/opensearch-project/OpenSearch/pulls) -[![2.17.0 Open Issues](https://img.shields.io/github/issues/opensearch-project/OpenSearch/v2.17.0)](https://github.com/opensearch-project/OpenSearch/issues?q=is%3Aissue+is%3Aopen+label%3A"v2.17.0") +[![2.14.1 Open Issues](https://img.shields.io/github/issues/opensearch-project/OpenSearch/v2.14.1)](https://github.com/opensearch-project/OpenSearch/issues?q=is%3Aissue+is%3Aopen+label%3A"v2.14.1") [![3.0.0 Open Issues](https://img.shields.io/github/issues/opensearch-project/OpenSearch/v3.0.0)](https://github.com/opensearch-project/OpenSearch/issues?q=is%3Aissue+is%3Aopen+label%3A"v3.0.0") [![GHA gradle check](https://github.com/opensearch-project/OpenSearch/actions/workflows/gradle-check.yml/badge.svg)](https://github.com/opensearch-project/OpenSearch/actions/workflows/gradle-check.yml) [![GHA validate pull request](https://github.com/opensearch-project/OpenSearch/actions/workflows/wrapper.yml/badge.svg)](https://github.com/opensearch-project/OpenSearch/actions/workflows/wrapper.yml) diff --git a/server/src/main/java/org/opensearch/action/SystemIndexFilter.java b/server/src/main/java/org/opensearch/action/SystemIndexFilter.java deleted file mode 100644 index e5f800e162293..0000000000000 --- a/server/src/main/java/org/opensearch/action/SystemIndexFilter.java +++ /dev/null @@ -1,66 +0,0 @@ -/* - * SPDX-License-Identifier: Apache-2.0 - * - * The OpenSearch Contributors require contributions made to - * this file be licensed under the Apache-2.0 license or a - * compatible open source license. - */ - -package org.opensearch.action; - -import org.opensearch.action.support.ActionFilter; -import org.opensearch.action.support.ActionFilterChain; -import org.opensearch.cluster.metadata.IndexNameExpressionResolver; -import org.opensearch.common.util.concurrent.ThreadContext; -import org.opensearch.core.action.ActionListener; -import org.opensearch.core.action.ActionResponse; -import org.opensearch.tasks.Task; - -/** - * Action filter that limits system index interaction for plugins - * - * Plugins are passed a PluginAwareNodeClient that allows a plugin to switch context and securely - * interact with system indices it registers through SystemIndexPlugin.getSystemIndexDescriptors - */ -public class SystemIndexFilter implements ActionFilter { - - private final ThreadContext threadContext; - private final IndexNameExpressionResolver resolver; - - public SystemIndexFilter(ThreadContext threadContext, IndexNameExpressionResolver resolver) { - this.threadContext = threadContext; - this.resolver = resolver; - } - - @Override - public int order() { - return Integer.MIN_VALUE + 100; - } - - @Override - public void apply( - Task task, - String action, - Request request, - ActionListener listener, - ActionFilterChain chain - ) { - // String pluginExecutionContext = threadContext.getHeader(ThreadContext.PLUGIN_EXECUTION_CONTEXT); - // if (pluginExecutionContext != null) { - // IndexResolverReplacer.Resolved requestedResolved = indexResolverReplacer.resolveRequest(request); - // if (!requestedResolved.getAllIndices().isEmpty()) { - // Set matchingSystemIndices = SystemIndexRegistry.matchesPluginSystemIndexPattern( - // pluginExecutionContext, - // requestedResolved.getAllIndices() - // ); - // if (!matchingSystemIndices.equals(requestedResolved.getAllIndices())) { - // String err = "Plugin " + pluginExecutionContext + " can only interact with its own system indices"; - // listener.onFailure(new OpenSearchSecurityException(err, RestStatus.FORBIDDEN)); - // return; - // } - // } - // } - // TODO Figure out how to resolve Request -> Indices - chain.proceed(task, action, request, listener); - } -} From f718299f79b347168dc9708336d0b790a5dddac0 Mon Sep 17 00:00:00 2001 From: Craig Perkins Date: Fri, 2 Aug 2024 16:57:40 -0400 Subject: [PATCH 24/65] Add notion of Forbidden Headers to the ThreadContext Signed-off-by: Craig Perkins --- .../common/util/concurrent/ThreadContext.java | 18 +++++++++++++++++- .../util/concurrent/ThreadContextTests.java | 5 +++++ 2 files changed, 22 insertions(+), 1 deletion(-) diff --git a/server/src/main/java/org/opensearch/common/util/concurrent/ThreadContext.java b/server/src/main/java/org/opensearch/common/util/concurrent/ThreadContext.java index a5c6e80193eb9..0a525b4cb427d 100644 --- a/server/src/main/java/org/opensearch/common/util/concurrent/ThreadContext.java +++ b/server/src/main/java/org/opensearch/common/util/concurrent/ThreadContext.java @@ -115,6 +115,8 @@ public final class ThreadContext implements Writeable { public static final String PLUGIN_EXECUTION_CONTEXT = "_plugin_execution_context"; + private static final Set FORBIDDEN_HEADRES = Set.of(PLUGIN_EXECUTION_CONTEXT); + // thread context permissions private static final Permission ACCESS_SYSTEM_THREAD_CONTEXT_PERMISSION = new ThreadContextPermission("markAsSystemContext"); @@ -214,7 +216,7 @@ StoredContext stashContext(Class pluginClass) { threadContextStruct = threadContextStruct.putTransient(transientHeaders); } - threadContextStruct = threadContextStruct.putRequest(PLUGIN_EXECUTION_CONTEXT, pluginClass.getCanonicalName()); + threadContextStruct = threadContextStruct.putPluginExecutionContext(pluginClass); threadLocal.set(threadContextStruct); return () -> { @@ -505,6 +507,9 @@ public void copyHeaders(Iterable> headers) { * Puts a header into the context */ public void putHeader(String key, String value) { + if (FORBIDDEN_HEADRES.contains(key)) { + throw new IllegalArgumentException("Cannot set forbidden header: " + key); + } threadLocal.set(threadLocal.get().putRequest(key, value)); } @@ -754,6 +759,14 @@ private ThreadContextStruct() { this(Collections.emptyMap(), Collections.emptyMap(), Collections.emptyMap(), Collections.emptyMap(), false); } + private ThreadContextStruct putPluginExecutionContext(Class pluginClass) { + Map newRequestHeaders = new HashMap<>(this.requestHeaders); + if (newRequestHeaders.putIfAbsent(PLUGIN_EXECUTION_CONTEXT, pluginClass.getCanonicalName()) != null) { + throw new IllegalArgumentException("value for key [" + PLUGIN_EXECUTION_CONTEXT + "] already present"); + } + return new ThreadContextStruct(newRequestHeaders, responseHeaders, transientHeaders, persistentHeaders, isSystemContext); + } + private ThreadContextStruct putRequest(String key, String value) { Map newRequestHeaders = new HashMap<>(this.requestHeaders); putSingleHeader(key, value, newRequestHeaders); @@ -761,6 +774,9 @@ private ThreadContextStruct putRequest(String key, String value) { } private static void putSingleHeader(String key, T value, Map newHeaders) { + if (FORBIDDEN_HEADRES.contains(key)) { + throw new IllegalArgumentException("Cannot set forbidden header: " + key); + } if (newHeaders.putIfAbsent(key, value) != null) { throw new IllegalArgumentException("value for key [" + key + "] already present"); } diff --git a/server/src/test/java/org/opensearch/common/util/concurrent/ThreadContextTests.java b/server/src/test/java/org/opensearch/common/util/concurrent/ThreadContextTests.java index 5992ffa1465b4..177bfc2415319 100644 --- a/server/src/test/java/org/opensearch/common/util/concurrent/ThreadContextTests.java +++ b/server/src/test/java/org/opensearch/common/util/concurrent/ThreadContextTests.java @@ -830,6 +830,11 @@ public void testPutHeaders() { () -> threadContext.putHeader(Collections.singletonMap("foo", "boom")) ); assertEquals("value for key [foo] already present", e.getMessage()); + IllegalArgumentException e2 = expectThrows( + IllegalArgumentException.class, + () -> threadContext.putHeader(Collections.singletonMap("_plugin_execution_context", "org.foo.bar.pluginA")) + ); + assertEquals("Cannot set forbidden header: _plugin_execution_context", e2.getMessage()); } /** From 7458969f70d8477b43fe1082e8f1e3c27c9cd417 Mon Sep 17 00:00:00 2001 From: Craig Perkins Date: Mon, 5 Aug 2024 21:32:37 -0400 Subject: [PATCH 25/65] Fix tests Signed-off-by: Craig Perkins --- .../reindex/remote/RemoteScrollableHitSourceTests.java | 2 ++ .../org/opensearch/common/logging/JsonLoggerTests.java | 9 ++++++--- .../org/opensearch/index/shard/RefreshListeners.java | 2 +- .../org/opensearch/plugins/TelemetryAwarePlugin.java | 4 ++-- server/src/test/java/org/opensearch/node/NodeTests.java | 4 ++-- .../admin/indices/RestValidateQueryActionTests.java | 7 +++++++ .../ThreadContextBasedTracerContextStorageTests.java | 5 ----- .../java/org/opensearch/test/OpenSearchTestCase.java | 2 +- 8 files changed, 21 insertions(+), 14 deletions(-) diff --git a/modules/reindex/src/test/java/org/opensearch/index/reindex/remote/RemoteScrollableHitSourceTests.java b/modules/reindex/src/test/java/org/opensearch/index/reindex/remote/RemoteScrollableHitSourceTests.java index 325de0cef1f8c..8aa66fc3cfd8c 100644 --- a/modules/reindex/src/test/java/org/opensearch/index/reindex/remote/RemoteScrollableHitSourceTests.java +++ b/modules/reindex/src/test/java/org/opensearch/index/reindex/remote/RemoteScrollableHitSourceTests.java @@ -606,6 +606,8 @@ protected Future doExecute( FutureCallback callback ) { try { + // Throw away the current thread context to simulate running async httpclient's thread pool + threadPool.getThreadContext().stashContext(); ClassicHttpRequest request = getRequest(requestProducer); URL resource = resources[responseCount]; String path = paths[responseCount++]; diff --git a/qa/logging-config/src/test/java/org/opensearch/common/logging/JsonLoggerTests.java b/qa/logging-config/src/test/java/org/opensearch/common/logging/JsonLoggerTests.java index 3a1d699aee863..7fbfd6929ebdf 100644 --- a/qa/logging-config/src/test/java/org/opensearch/common/logging/JsonLoggerTests.java +++ b/qa/logging-config/src/test/java/org/opensearch/common/logging/JsonLoggerTests.java @@ -408,8 +408,11 @@ protected List featureValueOf(JsonLogLine actual) { private void withThreadContext(CheckedConsumer consumer) throws Exception { final ThreadContext threadContext = new ThreadContext(Settings.EMPTY); - HeaderWarning.setThreadContext(threadContext); - consumer.accept(threadContext); - HeaderWarning.removeThreadContext(threadContext); + try (ThreadContext.StoredContext ignore = threadContext.stashContext()) { + HeaderWarning.setThreadContext(threadContext); + consumer.accept(threadContext); + } finally { + HeaderWarning.removeThreadContext(threadContext); + } } } diff --git a/server/src/main/java/org/opensearch/index/shard/RefreshListeners.java b/server/src/main/java/org/opensearch/index/shard/RefreshListeners.java index aa3de72e4232e..803db773efe6c 100644 --- a/server/src/main/java/org/opensearch/index/shard/RefreshListeners.java +++ b/server/src/main/java/org/opensearch/index/shard/RefreshListeners.java @@ -99,7 +99,7 @@ public RefreshListeners( final IntSupplier getMaxRefreshListeners, final Runnable forceRefresh, final Logger logger, - ThreadContext threadContext, + final ThreadContext threadContext, final MeanMetric refreshMetric ) { this.getMaxRefreshListeners = getMaxRefreshListeners; diff --git a/server/src/main/java/org/opensearch/plugins/TelemetryAwarePlugin.java b/server/src/main/java/org/opensearch/plugins/TelemetryAwarePlugin.java index 01287931719b2..4069b2f9768f1 100644 --- a/server/src/main/java/org/opensearch/plugins/TelemetryAwarePlugin.java +++ b/server/src/main/java/org/opensearch/plugins/TelemetryAwarePlugin.java @@ -8,7 +8,7 @@ package org.opensearch.plugins; -import org.opensearch.client.node.NodeClient; +import org.opensearch.client.Client; import org.opensearch.cluster.metadata.IndexNameExpressionResolver; import org.opensearch.cluster.service.ClusterService; import org.opensearch.common.annotation.ExperimentalApi; @@ -63,7 +63,7 @@ public interface TelemetryAwarePlugin { * @param contextSwitcher A client for switching to plugin system context */ default Collection createComponents( - NodeClient client, + Client client, ClusterService clusterService, ThreadPool threadPool, ResourceWatcherService resourceWatcherService, diff --git a/server/src/test/java/org/opensearch/node/NodeTests.java b/server/src/test/java/org/opensearch/node/NodeTests.java index 01c1a5c3b02d3..1a43185c7cde1 100644 --- a/server/src/test/java/org/opensearch/node/NodeTests.java +++ b/server/src/test/java/org/opensearch/node/NodeTests.java @@ -34,7 +34,7 @@ import org.apache.lucene.tests.util.LuceneTestCase; import org.opensearch.bootstrap.BootstrapCheck; import org.opensearch.bootstrap.BootstrapContext; -import org.opensearch.client.node.NodeClient; +import org.opensearch.client.Client; import org.opensearch.cluster.ClusterName; import org.opensearch.cluster.metadata.IndexNameExpressionResolver; import org.opensearch.cluster.node.DiscoveryNodeRole; @@ -467,7 +467,7 @@ public MetricsRegistry getMetricsRegistry() { public static class MockTelemetryAwarePlugin extends Plugin implements TelemetryAwarePlugin { @Override public Collection createComponents( - NodeClient client, + Client client, ClusterService clusterService, ThreadPool threadPool, ResourceWatcherService resourceWatcherService, diff --git a/server/src/test/java/org/opensearch/rest/action/admin/indices/RestValidateQueryActionTests.java b/server/src/test/java/org/opensearch/rest/action/admin/indices/RestValidateQueryActionTests.java index 1468f5d0f0b61..3fb6764846da6 100644 --- a/server/src/test/java/org/opensearch/rest/action/admin/indices/RestValidateQueryActionTests.java +++ b/server/src/test/java/org/opensearch/rest/action/admin/indices/RestValidateQueryActionTests.java @@ -56,6 +56,7 @@ import org.opensearch.threadpool.ThreadPool; import org.opensearch.usage.UsageService; import org.junit.AfterClass; +import org.junit.Before; import org.junit.BeforeClass; import java.util.Collections; @@ -112,6 +113,12 @@ protected void doExecute(Task task, ActionRequest request, ActionListener listen controller.registerHandler(action); } + @Before + public void ensureCleanContext() { + // Make sure we have a clean context for each test + threadPool.getThreadContext().stashContext(); + } + @AfterClass public static void terminateThreadPool() throws InterruptedException { terminate(threadPool); diff --git a/server/src/test/java/org/opensearch/telemetry/tracing/ThreadContextBasedTracerContextStorageTests.java b/server/src/test/java/org/opensearch/telemetry/tracing/ThreadContextBasedTracerContextStorageTests.java index b48f02217f0d0..98dfc367c20f5 100644 --- a/server/src/test/java/org/opensearch/telemetry/tracing/ThreadContextBasedTracerContextStorageTests.java +++ b/server/src/test/java/org/opensearch/telemetry/tracing/ThreadContextBasedTracerContextStorageTests.java @@ -8,8 +8,6 @@ package org.opensearch.telemetry.tracing; -import com.carrotsearch.randomizedtesting.annotations.ThreadLeakScope; - import org.opensearch.common.settings.ClusterSettings; import org.opensearch.common.settings.Settings; import org.opensearch.common.util.concurrent.ThreadContext; @@ -21,7 +19,6 @@ import org.opensearch.telemetry.tracing.noop.NoopTracer; import org.opensearch.test.OpenSearchTestCase; import org.opensearch.test.telemetry.tracing.MockTracingTelemetry; -import org.opensearch.threadpool.ThreadPool; import org.junit.After; import org.junit.Before; @@ -41,10 +38,8 @@ import static org.hamcrest.CoreMatchers.not; import static org.hamcrest.CoreMatchers.nullValue; -@ThreadLeakScope(ThreadLeakScope.Scope.NONE) public class ThreadContextBasedTracerContextStorageTests extends OpenSearchTestCase { private Tracer tracer; - private ThreadPool threadPool; private ThreadContext threadContext; private TracerContextStorage threadContextStorage; private ExecutorService executorService; diff --git a/test/framework/src/main/java/org/opensearch/test/OpenSearchTestCase.java b/test/framework/src/main/java/org/opensearch/test/OpenSearchTestCase.java index e0d4f91355f88..6afc7c23d9e66 100644 --- a/test/framework/src/main/java/org/opensearch/test/OpenSearchTestCase.java +++ b/test/framework/src/main/java/org/opensearch/test/OpenSearchTestCase.java @@ -618,7 +618,7 @@ private void assertWarnings(boolean stripXContentPosition, List actualWa */ private void resetDeprecationLogger() { // "clear" context by stashing current values and dropping the returned StoredContext - // threadContext.stashContext(); + threadContext.stashContext(); } private static final List statusData = new ArrayList<>(); From 5c1d94e1d58adbb4d70625adcdfef4f7d9134394 Mon Sep 17 00:00:00 2001 From: Craig Perkins Date: Tue, 6 Aug 2024 11:29:08 -0400 Subject: [PATCH 26/65] Fix test Signed-off-by: Craig Perkins --- .../java/org/opensearch/http/TestExecutionContextPlugin.java | 3 +-- 1 file changed, 1 insertion(+), 2 deletions(-) diff --git a/qa/smoke-test-http/src/test/java/org/opensearch/http/TestExecutionContextPlugin.java b/qa/smoke-test-http/src/test/java/org/opensearch/http/TestExecutionContextPlugin.java index 27879c6d2a6c7..c97182dc626eb 100644 --- a/qa/smoke-test-http/src/test/java/org/opensearch/http/TestExecutionContextPlugin.java +++ b/qa/smoke-test-http/src/test/java/org/opensearch/http/TestExecutionContextPlugin.java @@ -54,8 +54,7 @@ public Collection createComponents( IndexNameExpressionResolver expressionResolver, Supplier repositoriesServiceSupplier, ContextSwitcher contextSwitcher) { - // TODO Fix this - this.contextSwitcher = null; + this.contextSwitcher = contextSwitcher; this.threadPool = threadPool; return Collections.emptyList(); } From 8fbf024be2c12d2f7231a12f8899fc3e1f639f4b Mon Sep 17 00:00:00 2001 From: Craig Perkins Date: Tue, 6 Aug 2024 17:10:25 -0400 Subject: [PATCH 27/65] Add method to initialize plugins Signed-off-by: Craig Perkins --- .../common/CommonAnalysisModulePlugin.java | 4 +- .../PredicateTokenScriptFilterTests.java | 2 +- .../ScriptedConditionTokenFilterTests.java | 2 +- .../painless/PainlessModulePlugin.java | 4 +- .../index/reindex/ReindexModulePlugin.java | 4 +- .../ReindexFromRemoteWithAuthTests.java | 4 +- .../systemd/SystemdModulePlugin.java | 4 +- .../systemd/SystemdModulePluginTests.java | 6 +-- .../correlation/EventsCorrelationPlugin.java | 4 +- .../repositories/s3/S3RepositoryPlugin.java | 4 +- .../http/TestExecutionContextPlugin.java | 6 +-- .../action/ingest/AsyncIngestProcessorIT.java | 4 +- .../cluster/SimpleClusterStateIT.java | 4 +- .../metadata/TemplateUpgradeServiceIT.java | 7 +-- .../org/opensearch/index/FinalPipelineIT.java | 4 +- .../main/java/org/opensearch/node/Node.java | 50 +++++++++---------- .../java/org/opensearch/plugins/Plugin.java | 19 +++++-- .../opensearch/plugins/PluginsService.java | 10 ++++ .../plugins/TelemetryAwarePlugin.java | 5 +- .../java/org/opensearch/node/NodeTests.java | 4 +- .../util/concurrent/TestContextSwitcher.java | 29 ----------- 21 files changed, 70 insertions(+), 110 deletions(-) delete mode 100644 test/framework/src/main/java/org/opensearch/common/util/concurrent/TestContextSwitcher.java diff --git a/modules/analysis-common/src/main/java/org/opensearch/analysis/common/CommonAnalysisModulePlugin.java b/modules/analysis-common/src/main/java/org/opensearch/analysis/common/CommonAnalysisModulePlugin.java index 1b17d45eab6ff..f14e499081ce9 100644 --- a/modules/analysis-common/src/main/java/org/opensearch/analysis/common/CommonAnalysisModulePlugin.java +++ b/modules/analysis-common/src/main/java/org/opensearch/analysis/common/CommonAnalysisModulePlugin.java @@ -133,7 +133,6 @@ import org.opensearch.common.logging.DeprecationLogger; import org.opensearch.common.regex.Regex; import org.opensearch.common.settings.Settings; -import org.opensearch.common.util.concurrent.ContextSwitcher; import org.opensearch.core.common.io.stream.NamedWriteableRegistry; import org.opensearch.core.xcontent.NamedXContentRegistry; import org.opensearch.env.Environment; @@ -189,8 +188,7 @@ public Collection createComponents( NodeEnvironment nodeEnvironment, NamedWriteableRegistry namedWriteableRegistry, IndexNameExpressionResolver expressionResolver, - Supplier repositoriesServiceSupplier, - ContextSwitcher contextSwitcher + Supplier repositoriesServiceSupplier ) { this.scriptService.set(scriptService); return Collections.emptyList(); diff --git a/modules/analysis-common/src/test/java/org/opensearch/analysis/common/PredicateTokenScriptFilterTests.java b/modules/analysis-common/src/test/java/org/opensearch/analysis/common/PredicateTokenScriptFilterTests.java index 451f0e8dd3afb..d88b5bc93c28f 100644 --- a/modules/analysis-common/src/test/java/org/opensearch/analysis/common/PredicateTokenScriptFilterTests.java +++ b/modules/analysis-common/src/test/java/org/opensearch/analysis/common/PredicateTokenScriptFilterTests.java @@ -82,7 +82,7 @@ public FactoryType compile(Script script, ScriptContext FactoryType compile(Script script, ScriptContext createComponents( NodeEnvironment nodeEnvironment, NamedWriteableRegistry namedWriteableRegistry, IndexNameExpressionResolver expressionResolver, - Supplier repositoriesServiceSupplier, - ContextSwitcher contextSwitcher + Supplier repositoriesServiceSupplier ) { // this is a hack to bind the painless script engine in guice (all components are added to guice), so that // the painless context api. this is a temporary measure until transport actions do no require guice diff --git a/modules/reindex/src/main/java/org/opensearch/index/reindex/ReindexModulePlugin.java b/modules/reindex/src/main/java/org/opensearch/index/reindex/ReindexModulePlugin.java index 11a968b99c3b6..aa48da4cb2421 100644 --- a/modules/reindex/src/main/java/org/opensearch/index/reindex/ReindexModulePlugin.java +++ b/modules/reindex/src/main/java/org/opensearch/index/reindex/ReindexModulePlugin.java @@ -44,7 +44,6 @@ import org.opensearch.common.settings.Setting; import org.opensearch.common.settings.Settings; import org.opensearch.common.settings.SettingsFilter; -import org.opensearch.common.util.concurrent.ContextSwitcher; import org.opensearch.core.action.ActionResponse; import org.opensearch.core.common.io.stream.NamedWriteableRegistry; import org.opensearch.core.xcontent.NamedXContentRegistry; @@ -123,8 +122,7 @@ public Collection createComponents( NodeEnvironment nodeEnvironment, NamedWriteableRegistry namedWriteableRegistry, IndexNameExpressionResolver expressionResolver, - Supplier repositoriesServiceSupplier, - ContextSwitcher contextSwitcher + Supplier repositoriesServiceSupplier ) { return Collections.singletonList(new ReindexSslConfig(environment.settings(), environment, resourceWatcherService)); } diff --git a/modules/reindex/src/test/java/org/opensearch/index/reindex/ReindexFromRemoteWithAuthTests.java b/modules/reindex/src/test/java/org/opensearch/index/reindex/ReindexFromRemoteWithAuthTests.java index 62ed9c6da4cda..0d3cf208aabfb 100644 --- a/modules/reindex/src/test/java/org/opensearch/index/reindex/ReindexFromRemoteWithAuthTests.java +++ b/modules/reindex/src/test/java/org/opensearch/index/reindex/ReindexFromRemoteWithAuthTests.java @@ -46,7 +46,6 @@ import org.opensearch.common.SetOnce; import org.opensearch.common.network.NetworkModule; import org.opensearch.common.settings.Settings; -import org.opensearch.common.util.concurrent.ContextSwitcher; import org.opensearch.common.util.concurrent.ThreadContext; import org.opensearch.core.action.ActionListener; import org.opensearch.core.action.ActionResponse; @@ -187,8 +186,7 @@ public Collection createComponents( NodeEnvironment nodeEnvironment, NamedWriteableRegistry namedWriteableRegistry, IndexNameExpressionResolver expressionResolver, - Supplier repositoriesServiceSupplier, - ContextSwitcher contextSwitcher + Supplier repositoriesServiceSupplier ) { testFilter.set(new ReindexFromRemoteWithAuthTests.TestFilter(threadPool)); return Collections.emptyList(); diff --git a/modules/systemd/src/main/java/org/opensearch/systemd/SystemdModulePlugin.java b/modules/systemd/src/main/java/org/opensearch/systemd/SystemdModulePlugin.java index 967852c682b45..6e291027fa35f 100644 --- a/modules/systemd/src/main/java/org/opensearch/systemd/SystemdModulePlugin.java +++ b/modules/systemd/src/main/java/org/opensearch/systemd/SystemdModulePlugin.java @@ -39,7 +39,6 @@ import org.opensearch.cluster.service.ClusterService; import org.opensearch.common.SetOnce; import org.opensearch.common.unit.TimeValue; -import org.opensearch.common.util.concurrent.ContextSwitcher; import org.opensearch.core.common.io.stream.NamedWriteableRegistry; import org.opensearch.core.xcontent.NamedXContentRegistry; import org.opensearch.env.Environment; @@ -101,8 +100,7 @@ public Collection createComponents( final NodeEnvironment nodeEnvironment, final NamedWriteableRegistry namedWriteableRegistry, final IndexNameExpressionResolver expressionResolver, - final Supplier repositoriesServiceSupplier, - ContextSwitcher contextSwitcher + final Supplier repositoriesServiceSupplier ) { if (enabled == false) { extender.set(null); diff --git a/modules/systemd/src/test/java/org/opensearch/systemd/SystemdModulePluginTests.java b/modules/systemd/src/test/java/org/opensearch/systemd/SystemdModulePluginTests.java index 1148be0577a0e..532d47cd009e0 100644 --- a/modules/systemd/src/test/java/org/opensearch/systemd/SystemdModulePluginTests.java +++ b/modules/systemd/src/test/java/org/opensearch/systemd/SystemdModulePluginTests.java @@ -68,14 +68,14 @@ public class SystemdModulePluginTests extends OpenSearchTestCase { public void testIsImplicitlyNotEnabled() { final SystemdModulePlugin plugin = new SystemdModulePlugin(null); - plugin.createComponents(null, null, threadPool, null, null, null, null, null, null, null, null, null); + plugin.createComponents(null, null, threadPool, null, null, null, null, null, null, null, null); assertFalse(plugin.isEnabled()); assertNull(plugin.extender()); } public void testIsExplicitlyNotEnabled() { final SystemdModulePlugin plugin = new SystemdModulePlugin(Boolean.FALSE.toString()); - plugin.createComponents(null, null, threadPool, null, null, null, null, null, null, null, null, null); + plugin.createComponents(null, null, threadPool, null, null, null, null, null, null, null, null); assertFalse(plugin.isEnabled()); assertNull(plugin.extender()); } @@ -167,7 +167,7 @@ int sd_notify(final int unset_environment, final String state) { } }; - plugin.createComponents(null, null, threadPool, null, null, null, null, null, null, null, null, null); + plugin.createComponents(null, null, threadPool, null, null, null, null, null, null, null, null); if (Boolean.TRUE.toString().equals(esSDNotify)) { assertNotNull(plugin.extender()); } else { diff --git a/plugins/events-correlation-engine/src/main/java/org/opensearch/plugin/correlation/EventsCorrelationPlugin.java b/plugins/events-correlation-engine/src/main/java/org/opensearch/plugin/correlation/EventsCorrelationPlugin.java index c73d619f5ad8c..9637042974d03 100644 --- a/plugins/events-correlation-engine/src/main/java/org/opensearch/plugin/correlation/EventsCorrelationPlugin.java +++ b/plugins/events-correlation-engine/src/main/java/org/opensearch/plugin/correlation/EventsCorrelationPlugin.java @@ -18,7 +18,6 @@ import org.opensearch.common.settings.Setting; import org.opensearch.common.settings.Settings; import org.opensearch.common.settings.SettingsFilter; -import org.opensearch.common.util.concurrent.ContextSwitcher; import org.opensearch.core.action.ActionResponse; import org.opensearch.core.common.io.stream.NamedWriteableRegistry; import org.opensearch.core.xcontent.NamedXContentRegistry; @@ -88,8 +87,7 @@ public Collection createComponents( NodeEnvironment nodeEnvironment, NamedWriteableRegistry namedWriteableRegistry, IndexNameExpressionResolver indexNameExpressionResolver, - Supplier repositoriesServiceSupplier, - ContextSwitcher contextSwitcher + Supplier repositoriesServiceSupplier ) { correlationRuleIndices = new CorrelationRuleIndices(client, clusterService); return List.of(correlationRuleIndices); diff --git a/plugins/repository-s3/src/main/java/org/opensearch/repositories/s3/S3RepositoryPlugin.java b/plugins/repository-s3/src/main/java/org/opensearch/repositories/s3/S3RepositoryPlugin.java index 0d72c554caee1..110d91bfbd822 100644 --- a/plugins/repository-s3/src/main/java/org/opensearch/repositories/s3/S3RepositoryPlugin.java +++ b/plugins/repository-s3/src/main/java/org/opensearch/repositories/s3/S3RepositoryPlugin.java @@ -39,7 +39,6 @@ import org.opensearch.common.settings.Setting; import org.opensearch.common.settings.Settings; import org.opensearch.common.unit.TimeValue; -import org.opensearch.common.util.concurrent.ContextSwitcher; import org.opensearch.common.util.concurrent.OpenSearchExecutors; import org.opensearch.core.common.io.stream.NamedWriteableRegistry; import org.opensearch.core.common.unit.ByteSizeUnit; @@ -212,8 +211,7 @@ public Collection createComponents( final NodeEnvironment nodeEnvironment, final NamedWriteableRegistry namedWriteableRegistry, final IndexNameExpressionResolver expressionResolver, - final Supplier repositoriesServiceSupplier, - final ContextSwitcher contextSwitcher + final Supplier repositoriesServiceSupplier ) { int urgentEventLoopThreads = urgentPoolCount(clusterService.getSettings()); int priorityEventLoopThreads = priorityPoolCount(clusterService.getSettings()); diff --git a/qa/smoke-test-http/src/test/java/org/opensearch/http/TestExecutionContextPlugin.java b/qa/smoke-test-http/src/test/java/org/opensearch/http/TestExecutionContextPlugin.java index c97182dc626eb..ce95b4553a130 100644 --- a/qa/smoke-test-http/src/test/java/org/opensearch/http/TestExecutionContextPlugin.java +++ b/qa/smoke-test-http/src/test/java/org/opensearch/http/TestExecutionContextPlugin.java @@ -36,8 +36,6 @@ import java.util.function.Supplier; public class TestExecutionContextPlugin extends Plugin implements ActionPlugin { - - private ContextSwitcher contextSwitcher; private ThreadPool threadPool; @Override @@ -52,9 +50,7 @@ public Collection createComponents( NodeEnvironment nodeEnvironment, NamedWriteableRegistry namedWriteableRegistry, IndexNameExpressionResolver expressionResolver, - Supplier repositoriesServiceSupplier, - ContextSwitcher contextSwitcher) { - this.contextSwitcher = contextSwitcher; + Supplier repositoriesServiceSupplier) { this.threadPool = threadPool; return Collections.emptyList(); } diff --git a/server/src/internalClusterTest/java/org/opensearch/action/ingest/AsyncIngestProcessorIT.java b/server/src/internalClusterTest/java/org/opensearch/action/ingest/AsyncIngestProcessorIT.java index 773d660adeeb3..aefabcb9bc14f 100644 --- a/server/src/internalClusterTest/java/org/opensearch/action/ingest/AsyncIngestProcessorIT.java +++ b/server/src/internalClusterTest/java/org/opensearch/action/ingest/AsyncIngestProcessorIT.java @@ -39,7 +39,6 @@ import org.opensearch.client.Client; import org.opensearch.cluster.metadata.IndexNameExpressionResolver; import org.opensearch.cluster.service.ClusterService; -import org.opensearch.common.util.concurrent.ContextSwitcher; import org.opensearch.core.common.bytes.BytesArray; import org.opensearch.core.common.bytes.BytesReference; import org.opensearch.core.common.io.stream.NamedWriteableRegistry; @@ -121,8 +120,7 @@ public Collection createComponents( NodeEnvironment nodeEnvironment, NamedWriteableRegistry namedWriteableRegistry, IndexNameExpressionResolver expressionResolver, - Supplier repositoriesServiceSupplier, - ContextSwitcher contextSwitcher + Supplier repositoriesServiceSupplier ) { this.threadPool = threadPool; return Collections.emptyList(); diff --git a/server/src/internalClusterTest/java/org/opensearch/cluster/SimpleClusterStateIT.java b/server/src/internalClusterTest/java/org/opensearch/cluster/SimpleClusterStateIT.java index 3f57ec9e421c8..af5900b1cba6c 100644 --- a/server/src/internalClusterTest/java/org/opensearch/cluster/SimpleClusterStateIT.java +++ b/server/src/internalClusterTest/java/org/opensearch/cluster/SimpleClusterStateIT.java @@ -47,7 +47,6 @@ import org.opensearch.common.Priority; import org.opensearch.common.UUIDs; import org.opensearch.common.settings.Settings; -import org.opensearch.common.util.concurrent.ContextSwitcher; import org.opensearch.common.xcontent.XContentFactory; import org.opensearch.core.common.Strings; import org.opensearch.core.common.io.stream.NamedWriteableRegistry; @@ -470,8 +469,7 @@ public Collection createComponents( final NodeEnvironment nodeEnvironment, final NamedWriteableRegistry namedWriteableRegistry, final IndexNameExpressionResolver expressionResolver, - final Supplier repositoriesServiceSupplier, - final ContextSwitcher contextSwitcher + final Supplier repositoriesServiceSupplier ) { clusterService.addListener(event -> { final ClusterState state = event.state(); diff --git a/server/src/internalClusterTest/java/org/opensearch/cluster/metadata/TemplateUpgradeServiceIT.java b/server/src/internalClusterTest/java/org/opensearch/cluster/metadata/TemplateUpgradeServiceIT.java index 0e051b82c5685..ba1679d873bf4 100644 --- a/server/src/internalClusterTest/java/org/opensearch/cluster/metadata/TemplateUpgradeServiceIT.java +++ b/server/src/internalClusterTest/java/org/opensearch/cluster/metadata/TemplateUpgradeServiceIT.java @@ -38,7 +38,6 @@ import org.opensearch.cluster.service.ClusterService; import org.opensearch.common.settings.Setting; import org.opensearch.common.settings.Settings; -import org.opensearch.common.util.concurrent.ContextSwitcher; import org.opensearch.core.common.io.stream.NamedWriteableRegistry; import org.opensearch.core.xcontent.NamedXContentRegistry; import org.opensearch.env.Environment; @@ -98,8 +97,7 @@ public Collection createComponents( NodeEnvironment nodeEnvironment, NamedWriteableRegistry namedWriteableRegistry, IndexNameExpressionResolver expressionResolver, - Supplier repositoriesServiceSupplier, - ContextSwitcher contextSwitcher + Supplier repositoriesServiceSupplier ) { clusterService.getClusterSettings().addSettingsUpdateConsumer(UPDATE_TEMPLATE_DUMMY_SETTING, integer -> { logger.debug("the template dummy setting was updated to {}", integer); @@ -115,8 +113,7 @@ public Collection createComponents( nodeEnvironment, namedWriteableRegistry, expressionResolver, - repositoriesServiceSupplier, - contextSwitcher + repositoriesServiceSupplier ); } diff --git a/server/src/internalClusterTest/java/org/opensearch/index/FinalPipelineIT.java b/server/src/internalClusterTest/java/org/opensearch/index/FinalPipelineIT.java index 2b6931c3ade4a..03b8fb5ff7afc 100644 --- a/server/src/internalClusterTest/java/org/opensearch/index/FinalPipelineIT.java +++ b/server/src/internalClusterTest/java/org/opensearch/index/FinalPipelineIT.java @@ -46,7 +46,6 @@ import org.opensearch.cluster.metadata.IndexNameExpressionResolver; import org.opensearch.cluster.service.ClusterService; import org.opensearch.common.settings.Settings; -import org.opensearch.common.util.concurrent.ContextSwitcher; import org.opensearch.core.common.bytes.BytesArray; import org.opensearch.core.common.bytes.BytesReference; import org.opensearch.core.common.io.stream.NamedWriteableRegistry; @@ -374,8 +373,7 @@ public Collection createComponents( final NodeEnvironment nodeEnvironment, final NamedWriteableRegistry namedWriteableRegistry, final IndexNameExpressionResolver expressionResolver, - final Supplier repositoriesServiceSupplier, - final ContextSwitcher contextSwitcher + final Supplier repositoriesServiceSupplier ) { return Collections.emptyList(); } diff --git a/server/src/main/java/org/opensearch/node/Node.java b/server/src/main/java/org/opensearch/node/Node.java index 66d6f701f215e..9b2f4add1fdd1 100644 --- a/server/src/main/java/org/opensearch/node/Node.java +++ b/server/src/main/java/org/opensearch/node/Node.java @@ -117,8 +117,6 @@ import org.opensearch.common.util.BigArrays; import org.opensearch.common.util.FeatureFlags; import org.opensearch.common.util.PageCacheRecycler; -import org.opensearch.common.util.concurrent.ContextSwitcher; -import org.opensearch.common.util.concurrent.PluginContextSwitcher; import org.opensearch.common.util.io.IOUtils; import org.opensearch.core.Assertions; import org.opensearch.core.common.breaker.CircuitBreaker; @@ -572,6 +570,7 @@ protected Node( runnableTaskListener = new AtomicReference<>(); final ThreadPool threadPool = new ThreadPool(settings, runnableTaskListener, executorBuilders.toArray(new ExecutorBuilder[0])); + pluginsService.initializePlugins(threadPool); final SetOnce repositoriesServiceReference = new SetOnce<>(); final RemoteStoreNodeService remoteStoreNodeService = new RemoteStoreNodeService(repositoriesServiceReference::get, threadPool); @@ -954,29 +953,29 @@ protected Node( final ViewService viewService = new ViewService(clusterService, client, null); - Collection pluginComponents = pluginsService.filterPlugins(Plugin.class).stream().flatMap(p -> { - ContextSwitcher contextSwitcher = new PluginContextSwitcher(threadPool, p); - return p.createComponents( - client, - clusterService, - threadPool, - resourceWatcherService, - scriptService, - xContentRegistry, - environment, - nodeEnvironment, - namedWriteableRegistry, - clusterModule.getIndexNameExpressionResolver(), - repositoriesServiceReference::get, - contextSwitcher - ).stream(); - }).collect(Collectors.toList()); + Collection pluginComponents = pluginsService.filterPlugins(Plugin.class) + .stream() + .flatMap( + p -> p.createComponents( + client, + clusterService, + threadPool, + resourceWatcherService, + scriptService, + xContentRegistry, + environment, + nodeEnvironment, + namedWriteableRegistry, + clusterModule.getIndexNameExpressionResolver(), + repositoriesServiceReference::get + ).stream() + ) + .collect(Collectors.toList()); Collection telemetryAwarePluginComponents = pluginsService.filterPlugins(TelemetryAwarePlugin.class) .stream() - .flatMap(p -> { - ContextSwitcher contextSwitcher = new PluginContextSwitcher(threadPool, (Plugin) p); - return p.createComponents( + .flatMap( + p -> p.createComponents( client, clusterService, threadPool, @@ -989,10 +988,9 @@ protected Node( clusterModule.getIndexNameExpressionResolver(), repositoriesServiceReference::get, tracer, - metricsRegistry, - contextSwitcher - ).stream(); - }) + metricsRegistry + ).stream() + ) .collect(Collectors.toList()); // Add the telemetryAwarePlugin components to the existing pluginComponents collection. diff --git a/server/src/main/java/org/opensearch/plugins/Plugin.java b/server/src/main/java/org/opensearch/plugins/Plugin.java index 6e1017a516925..46b2f0111fceb 100644 --- a/server/src/main/java/org/opensearch/plugins/Plugin.java +++ b/server/src/main/java/org/opensearch/plugins/Plugin.java @@ -47,6 +47,7 @@ import org.opensearch.common.settings.SettingUpgrader; import org.opensearch.common.settings.Settings; import org.opensearch.common.util.concurrent.ContextSwitcher; +import org.opensearch.common.util.concurrent.PluginContextSwitcher; import org.opensearch.core.common.io.stream.NamedWriteable; import org.opensearch.core.common.io.stream.NamedWriteableRegistry; import org.opensearch.core.xcontent.NamedXContentRegistry; @@ -94,6 +95,8 @@ @PublicApi(since = "1.0.0") public abstract class Plugin implements Closeable { + protected ContextSwitcher contextSwitcher; + /** * A feature exposed by the plugin. This should be used if a plugin exposes {@link ClusterState.Custom} or {@link Metadata.Custom}; see * also {@link ClusterState.FeatureAware}. @@ -120,6 +123,18 @@ public Collection> getGuiceServiceClasses() return Collections.emptyList(); } + /** + * Setter for PluginContextSwitcher. + * + * @param contextSwitcher A client for switching to plugin system context + */ + final void setContextSwitcher(PluginContextSwitcher contextSwitcher) { + if (this.contextSwitcher != null) { + throw new IllegalStateException("contextSwitcher can only be set once"); + } + this.contextSwitcher = contextSwitcher; + } + /** * Returns components added by this plugin. *

@@ -139,7 +154,6 @@ public Collection> getGuiceServiceClasses() * @param indexNameExpressionResolver A service that resolves expression to index and alias names * @param repositoriesServiceSupplier A supplier for the service that manages snapshot repositories; will return null when this method * is called, but will return the repositories service once the node is initialized. - * @param contextSwitcher A client for switching to plugin system context */ public Collection createComponents( Client client, @@ -152,8 +166,7 @@ public Collection createComponents( NodeEnvironment nodeEnvironment, NamedWriteableRegistry namedWriteableRegistry, IndexNameExpressionResolver indexNameExpressionResolver, - Supplier repositoriesServiceSupplier, - ContextSwitcher contextSwitcher + Supplier repositoriesServiceSupplier ) { return Collections.emptyList(); } diff --git a/server/src/main/java/org/opensearch/plugins/PluginsService.java b/server/src/main/java/org/opensearch/plugins/PluginsService.java index f08c9c738f1b4..886777ffa4720 100644 --- a/server/src/main/java/org/opensearch/plugins/PluginsService.java +++ b/server/src/main/java/org/opensearch/plugins/PluginsService.java @@ -50,11 +50,13 @@ import org.opensearch.common.settings.Setting; import org.opensearch.common.settings.Setting.Property; import org.opensearch.common.settings.Settings; +import org.opensearch.common.util.concurrent.PluginContextSwitcher; import org.opensearch.core.common.Strings; import org.opensearch.core.service.ReportingService; import org.opensearch.index.IndexModule; import org.opensearch.semver.SemverRange; import org.opensearch.threadpool.ExecutorBuilder; +import org.opensearch.threadpool.ThreadPool; import org.opensearch.transport.TransportSettings; import java.io.IOException; @@ -775,6 +777,14 @@ private Class loadPluginClass(String className, ClassLoader lo } } + public void initializePlugins(ThreadPool threadPool) { + List pluginList = filterPlugins(Plugin.class); + for (Plugin p : pluginList) { + PluginContextSwitcher contextSwitcher = new PluginContextSwitcher(threadPool, p); + p.setContextSwitcher(contextSwitcher); + } + } + private Plugin loadPlugin(Class pluginClass, Settings settings, Path configPath) { final Constructor[] constructors = pluginClass.getConstructors(); if (constructors.length == 0) { diff --git a/server/src/main/java/org/opensearch/plugins/TelemetryAwarePlugin.java b/server/src/main/java/org/opensearch/plugins/TelemetryAwarePlugin.java index 4069b2f9768f1..42cab326f88bf 100644 --- a/server/src/main/java/org/opensearch/plugins/TelemetryAwarePlugin.java +++ b/server/src/main/java/org/opensearch/plugins/TelemetryAwarePlugin.java @@ -13,7 +13,6 @@ import org.opensearch.cluster.service.ClusterService; import org.opensearch.common.annotation.ExperimentalApi; import org.opensearch.common.lifecycle.LifecycleComponent; -import org.opensearch.common.util.concurrent.ContextSwitcher; import org.opensearch.core.common.io.stream.NamedWriteable; import org.opensearch.core.common.io.stream.NamedWriteableRegistry; import org.opensearch.core.xcontent.NamedXContentRegistry; @@ -60,7 +59,6 @@ public interface TelemetryAwarePlugin { * is called, but will return the repositories service once the node is initialized. * @param tracer the tracer to add tracing instrumentation. * @param metricsRegistry the registry for metrics instrumentation. - * @param contextSwitcher A client for switching to plugin system context */ default Collection createComponents( Client client, @@ -75,8 +73,7 @@ default Collection createComponents( IndexNameExpressionResolver indexNameExpressionResolver, Supplier repositoriesServiceSupplier, Tracer tracer, - MetricsRegistry metricsRegistry, - ContextSwitcher contextSwitcher + MetricsRegistry metricsRegistry ) { return Collections.emptyList(); } diff --git a/server/src/test/java/org/opensearch/node/NodeTests.java b/server/src/test/java/org/opensearch/node/NodeTests.java index 1a43185c7cde1..0093091f61a1c 100644 --- a/server/src/test/java/org/opensearch/node/NodeTests.java +++ b/server/src/test/java/org/opensearch/node/NodeTests.java @@ -44,7 +44,6 @@ import org.opensearch.common.settings.Settings; import org.opensearch.common.settings.SettingsException; import org.opensearch.common.util.FeatureFlags; -import org.opensearch.common.util.concurrent.ContextSwitcher; import org.opensearch.core.common.breaker.CircuitBreaker; import org.opensearch.core.common.io.stream.NamedWriteableRegistry; import org.opensearch.core.common.transport.BoundTransportAddress; @@ -479,8 +478,7 @@ public Collection createComponents( IndexNameExpressionResolver indexNameExpressionResolver, Supplier repositoriesServiceSupplier, Tracer tracer, - MetricsRegistry metricsRegistry, - ContextSwitcher contextSwitcher + MetricsRegistry metricsRegistry ) { return List.of(new MockTelemetryAwareComponent(tracer, metricsRegistry)); } diff --git a/test/framework/src/main/java/org/opensearch/common/util/concurrent/TestContextSwitcher.java b/test/framework/src/main/java/org/opensearch/common/util/concurrent/TestContextSwitcher.java deleted file mode 100644 index 6e0ffb610d202..0000000000000 --- a/test/framework/src/main/java/org/opensearch/common/util/concurrent/TestContextSwitcher.java +++ /dev/null @@ -1,29 +0,0 @@ -/* - * SPDX-License-Identifier: Apache-2.0 - * - * The OpenSearch Contributors require contributions made to - * this file be licensed under the Apache-2.0 license or a - * compatible open source license. - */ - -package org.opensearch.common.util.concurrent; - -import org.opensearch.threadpool.ThreadPool; - -/** - * Test Context Switcher - */ -public class TestContextSwitcher implements ContextSwitcher { - private final ThreadPool threadPool; - private final Class pluginClass; - - public TestContextSwitcher(ThreadPool threadPool, Class pluginClass) { - this.threadPool = threadPool; - this.pluginClass = pluginClass; - } - - @Override - public ThreadContext.StoredContext switchContext() { - return threadPool.getThreadContext().stashContext(pluginClass); - } -} From 76e8b04482d3046f22ff69ee6e330a46606ba65c Mon Sep 17 00:00:00 2001 From: Craig Perkins Date: Wed, 7 Aug 2024 11:32:55 -0400 Subject: [PATCH 28/65] Create concept of pluginNodeClient that can be used for executing transport actions as the plugin Signed-off-by: Craig Perkins --- qa/smoke-test-http/build.gradle | 1 + .../http/ExecutionContextPluginGetIT.java | 2 +- .../TestExecutionContextPlugin.java | 12 ++- .../TestGetExecutionContextAction.java | 29 ++++++ .../TestGetExecutionContextRequest.java | 46 ++++++++++ .../TestGetExecutionContextResponse.java | 55 ++++++++++++ .../TestGetExecutionContextRestAction.java | 23 ++--- ...estGetExecutionContextTransportAction.java | 38 ++++++++ .../opensearch/client/node/NodeClient.java | 2 +- .../client/node/PluginNodeClient.java | 89 +++++++++++++++++++ .../util/concurrent/ContextSwitcher.java | 5 +- .../concurrent/PluginContextSwitcher.java | 4 +- .../main/java/org/opensearch/node/Node.java | 9 +- .../java/org/opensearch/plugins/Plugin.java | 17 ++-- .../opensearch/plugins/PluginsService.java | 20 ++++- 15 files changed, 311 insertions(+), 41 deletions(-) rename qa/smoke-test-http/src/test/java/org/opensearch/http/{ => executioncontextplugin}/TestExecutionContextPlugin.java (83%) create mode 100644 qa/smoke-test-http/src/test/java/org/opensearch/http/executioncontextplugin/TestGetExecutionContextAction.java create mode 100644 qa/smoke-test-http/src/test/java/org/opensearch/http/executioncontextplugin/TestGetExecutionContextRequest.java create mode 100644 qa/smoke-test-http/src/test/java/org/opensearch/http/executioncontextplugin/TestGetExecutionContextResponse.java rename qa/smoke-test-http/src/test/java/org/opensearch/http/{ => executioncontextplugin}/TestGetExecutionContextRestAction.java (53%) create mode 100644 qa/smoke-test-http/src/test/java/org/opensearch/http/executioncontextplugin/TestGetExecutionContextTransportAction.java create mode 100644 server/src/main/java/org/opensearch/client/node/PluginNodeClient.java diff --git a/qa/smoke-test-http/build.gradle b/qa/smoke-test-http/build.gradle index 496fda6bb717d..709ed049e9d0f 100644 --- a/qa/smoke-test-http/build.gradle +++ b/qa/smoke-test-http/build.gradle @@ -38,6 +38,7 @@ dependencies { testImplementation project(path: ':plugins:transport-reactor-netty4') // for http testImplementation project(path: ':plugins:transport-nio') testImplementation project(path: ':plugins:identity-shiro') // for http + testImplementation project(path: ':server') } integTest { diff --git a/qa/smoke-test-http/src/test/java/org/opensearch/http/ExecutionContextPluginGetIT.java b/qa/smoke-test-http/src/test/java/org/opensearch/http/ExecutionContextPluginGetIT.java index 95f8898862357..08cc59b868fdc 100644 --- a/qa/smoke-test-http/src/test/java/org/opensearch/http/ExecutionContextPluginGetIT.java +++ b/qa/smoke-test-http/src/test/java/org/opensearch/http/ExecutionContextPluginGetIT.java @@ -10,7 +10,7 @@ import org.opensearch.client.Request; import org.opensearch.client.Response; -import org.opensearch.client.ResponseException; +import org.opensearch.http.executioncontextplugin.TestExecutionContextPlugin; import org.opensearch.plugins.Plugin; import org.opensearch.test.OpenSearchIntegTestCase.ClusterScope; import org.opensearch.test.OpenSearchIntegTestCase.Scope; diff --git a/qa/smoke-test-http/src/test/java/org/opensearch/http/TestExecutionContextPlugin.java b/qa/smoke-test-http/src/test/java/org/opensearch/http/executioncontextplugin/TestExecutionContextPlugin.java similarity index 83% rename from qa/smoke-test-http/src/test/java/org/opensearch/http/TestExecutionContextPlugin.java rename to qa/smoke-test-http/src/test/java/org/opensearch/http/executioncontextplugin/TestExecutionContextPlugin.java index ce95b4553a130..c41bd1f65a8a7 100644 --- a/qa/smoke-test-http/src/test/java/org/opensearch/http/TestExecutionContextPlugin.java +++ b/qa/smoke-test-http/src/test/java/org/opensearch/http/executioncontextplugin/TestExecutionContextPlugin.java @@ -6,8 +6,9 @@ * compatible open source license. */ -package org.opensearch.http; +package org.opensearch.http.executioncontextplugin; +import org.opensearch.action.ActionRequest; import org.opensearch.client.Client; import org.opensearch.cluster.metadata.IndexNameExpressionResolver; import org.opensearch.cluster.node.DiscoveryNodes; @@ -16,7 +17,7 @@ import org.opensearch.common.settings.IndexScopedSettings; import org.opensearch.common.settings.Settings; import org.opensearch.common.settings.SettingsFilter; -import org.opensearch.common.util.concurrent.ContextSwitcher; +import org.opensearch.core.action.ActionResponse; import org.opensearch.core.common.io.stream.NamedWriteableRegistry; import org.opensearch.core.xcontent.NamedXContentRegistry; import org.opensearch.env.Environment; @@ -59,6 +60,11 @@ public Collection createComponents( public List getRestHandlers(Settings settings, RestController restController, ClusterSettings clusterSettings, IndexScopedSettings indexScopedSettings, SettingsFilter settingsFilter, IndexNameExpressionResolver indexNameExpressionResolver, Supplier nodesInCluster) { - return List.of(new TestGetExecutionContextRestAction(contextSwitcher, threadPool)); + return List.of(new TestGetExecutionContextRestAction(pluginNodeClient, threadPool)); + } + + @Override + public List> getActions() { + return List.of(new ActionHandler<>(TestGetExecutionContextAction.INSTANCE, TestGetExecutionContextTransportAction.class)); } } diff --git a/qa/smoke-test-http/src/test/java/org/opensearch/http/executioncontextplugin/TestGetExecutionContextAction.java b/qa/smoke-test-http/src/test/java/org/opensearch/http/executioncontextplugin/TestGetExecutionContextAction.java new file mode 100644 index 0000000000000..83248bc672114 --- /dev/null +++ b/qa/smoke-test-http/src/test/java/org/opensearch/http/executioncontextplugin/TestGetExecutionContextAction.java @@ -0,0 +1,29 @@ +/* + * SPDX-License-Identifier: Apache-2.0 + * + * The OpenSearch Contributors require contributions made to + * this file be licensed under the Apache-2.0 license or a + * compatible open source license. + */ + +package org.opensearch.http.executioncontextplugin; + +import org.opensearch.action.ActionType; + +/** + * Test action to get the name of the plugin executing transport actions + */ +public class TestGetExecutionContextAction extends ActionType { + /** + * Get execution context action instance + */ + public static final TestGetExecutionContextAction INSTANCE = new TestGetExecutionContextAction(); + /** + * Get execution context action name + */ + public static final String NAME = "cluster:admin/executioncontext"; + + private TestGetExecutionContextAction() { + super(NAME, TestGetExecutionContextResponse::new); + } +} diff --git a/qa/smoke-test-http/src/test/java/org/opensearch/http/executioncontextplugin/TestGetExecutionContextRequest.java b/qa/smoke-test-http/src/test/java/org/opensearch/http/executioncontextplugin/TestGetExecutionContextRequest.java new file mode 100644 index 0000000000000..da6deb384f38f --- /dev/null +++ b/qa/smoke-test-http/src/test/java/org/opensearch/http/executioncontextplugin/TestGetExecutionContextRequest.java @@ -0,0 +1,46 @@ +/* + * SPDX-License-Identifier: Apache-2.0 + * + * The OpenSearch Contributors require contributions made to + * this file be licensed under the Apache-2.0 license or a + * compatible open source license. + */ + +package org.opensearch.http.executioncontextplugin; + +import org.opensearch.action.ActionRequest; +import org.opensearch.action.ActionRequestValidationException; +import org.opensearch.core.common.io.stream.StreamInput; +import org.opensearch.core.common.io.stream.StreamOutput; + +import java.io.IOException; + +/** + * Request object for GetExecutionContext transport action + */ +public class TestGetExecutionContextRequest extends ActionRequest { + + /** + * Default constructor + */ + public TestGetExecutionContextRequest() {} + + /** + * Constructor with stream input + * @param in the stream input + * @throws IOException IOException + */ + public TestGetExecutionContextRequest(final StreamInput in) throws IOException { + super(in); + } + + @Override + public void writeTo(final StreamOutput out) throws IOException { + super.writeTo(out); + } + + @Override + public ActionRequestValidationException validate() { + return null; + } +} diff --git a/qa/smoke-test-http/src/test/java/org/opensearch/http/executioncontextplugin/TestGetExecutionContextResponse.java b/qa/smoke-test-http/src/test/java/org/opensearch/http/executioncontextplugin/TestGetExecutionContextResponse.java new file mode 100644 index 0000000000000..335c29b673ee4 --- /dev/null +++ b/qa/smoke-test-http/src/test/java/org/opensearch/http/executioncontextplugin/TestGetExecutionContextResponse.java @@ -0,0 +1,55 @@ +/* + * SPDX-License-Identifier: Apache-2.0 + * + * The OpenSearch Contributors require contributions made to + * this file be licensed under the Apache-2.0 license or a + * compatible open source license. + */ + +package org.opensearch.http.executioncontextplugin; + +import org.opensearch.core.action.ActionResponse; +import org.opensearch.core.common.io.stream.StreamInput; +import org.opensearch.core.common.io.stream.StreamOutput; +import org.opensearch.core.xcontent.ToXContentObject; +import org.opensearch.core.xcontent.XContentBuilder; + +import java.io.IOException; + +/** + * Response object containing the name of the plugin executing the transport action + */ +public class TestGetExecutionContextResponse extends ActionResponse implements ToXContentObject { + private final String pluginClassName; + + /** + * Default constructor + * + * @param pluginClassName the canonical class name of the plugin executing the transport action + */ + public TestGetExecutionContextResponse(String pluginClassName) { + this.pluginClassName = pluginClassName; + } + + @Override + public void writeTo(StreamOutput out) throws IOException { + out.writeString(pluginClassName); + } + + /** + * Constructor with StreamInput + * + * @param in the stream input + */ + public TestGetExecutionContextResponse(final StreamInput in) throws IOException { + pluginClassName = in.readString(); + } + + @Override + public XContentBuilder toXContent(XContentBuilder builder, Params params) throws IOException { + builder.startObject(); + builder.field("plugin_execution_context", pluginClassName); + builder.endObject(); + return builder; + } +} diff --git a/qa/smoke-test-http/src/test/java/org/opensearch/http/TestGetExecutionContextRestAction.java b/qa/smoke-test-http/src/test/java/org/opensearch/http/executioncontextplugin/TestGetExecutionContextRestAction.java similarity index 53% rename from qa/smoke-test-http/src/test/java/org/opensearch/http/TestGetExecutionContextRestAction.java rename to qa/smoke-test-http/src/test/java/org/opensearch/http/executioncontextplugin/TestGetExecutionContextRestAction.java index ca9a8fc295c67..bb86f78d4baea 100644 --- a/qa/smoke-test-http/src/test/java/org/opensearch/http/TestGetExecutionContextRestAction.java +++ b/qa/smoke-test-http/src/test/java/org/opensearch/http/executioncontextplugin/TestGetExecutionContextRestAction.java @@ -6,16 +6,13 @@ * compatible open source license. */ -package org.opensearch.http; +package org.opensearch.http.executioncontextplugin; import org.opensearch.client.node.NodeClient; -import org.opensearch.common.util.concurrent.ContextSwitcher; -import org.opensearch.common.util.concurrent.ThreadContext; -import org.opensearch.core.rest.RestStatus; +import org.opensearch.client.node.PluginNodeClient; import org.opensearch.rest.BaseRestHandler; -import org.opensearch.rest.BytesRestResponse; import org.opensearch.rest.RestRequest; -import org.opensearch.rest.RestResponse; +import org.opensearch.rest.action.RestToXContentListener; import org.opensearch.threadpool.ThreadPool; import java.util.List; @@ -25,11 +22,11 @@ public class TestGetExecutionContextRestAction extends BaseRestHandler { - private final ContextSwitcher contextSwitcher; + private final PluginNodeClient pluginNodeClient; private final ThreadPool threadPool; - public TestGetExecutionContextRestAction(ContextSwitcher contextSwitcher, ThreadPool threadPool) { - this.contextSwitcher = contextSwitcher; + public TestGetExecutionContextRestAction(PluginNodeClient pluginNodeClient, ThreadPool threadPool) { + this.pluginNodeClient = pluginNodeClient; this.threadPool = threadPool; } @@ -45,11 +42,7 @@ public String getName() { @Override public RestChannelConsumer prepareRequest(RestRequest request, NodeClient client) { - String stashedContext; - try (ThreadContext.StoredContext storedContext = contextSwitcher.switchContext()) { - stashedContext = threadPool.getThreadContext().getHeader(ThreadContext.PLUGIN_EXECUTION_CONTEXT); - } - RestResponse response = new BytesRestResponse(RestStatus.OK, stashedContext); - return channel -> channel.sendResponse(response); + final TestGetExecutionContextRequest getExecutionContextRequest = new TestGetExecutionContextRequest(); + return channel -> pluginNodeClient.executeLocally(TestGetExecutionContextAction.INSTANCE, getExecutionContextRequest, new RestToXContentListener<>(channel)); } } diff --git a/qa/smoke-test-http/src/test/java/org/opensearch/http/executioncontextplugin/TestGetExecutionContextTransportAction.java b/qa/smoke-test-http/src/test/java/org/opensearch/http/executioncontextplugin/TestGetExecutionContextTransportAction.java new file mode 100644 index 0000000000000..22c051e75ce33 --- /dev/null +++ b/qa/smoke-test-http/src/test/java/org/opensearch/http/executioncontextplugin/TestGetExecutionContextTransportAction.java @@ -0,0 +1,38 @@ +/* + * SPDX-License-Identifier: Apache-2.0 + * + * The OpenSearch Contributors require contributions made to + * this file be licensed under the Apache-2.0 license or a + * compatible open source license. + */ + +package org.opensearch.http.executioncontextplugin; + +import org.opensearch.action.support.ActionFilters; +import org.opensearch.action.support.HandledTransportAction; +import org.opensearch.common.inject.Inject; +import org.opensearch.common.util.concurrent.ThreadContext; +import org.opensearch.core.action.ActionListener; +import org.opensearch.tasks.Task; +import org.opensearch.transport.TransportService; + +/** + * Transport action for GetExecutionContext. + * + * Returns the canonical class name of the plugin that is currently executing the transport action. + */ +public class TestGetExecutionContextTransportAction extends HandledTransportAction { + private final TransportService transportService; + + @Inject + public TestGetExecutionContextTransportAction(TransportService transportService, ActionFilters actionFilters) { + super(TestGetExecutionContextAction.NAME, transportService, actionFilters, TestGetExecutionContextRequest::new); + this.transportService = transportService; + } + + @Override + protected void doExecute(Task task, TestGetExecutionContextRequest request, ActionListener listener) { + String pluginClassName = transportService.getThreadPool().getThreadContext().getHeader(ThreadContext.PLUGIN_EXECUTION_CONTEXT); + listener.onResponse(new TestGetExecutionContextResponse(pluginClassName)); + } +} diff --git a/server/src/main/java/org/opensearch/client/node/NodeClient.java b/server/src/main/java/org/opensearch/client/node/NodeClient.java index 5780e4c1e648a..e7f50e77cb8bb 100644 --- a/server/src/main/java/org/opensearch/client/node/NodeClient.java +++ b/server/src/main/java/org/opensearch/client/node/NodeClient.java @@ -136,7 +136,7 @@ public String getLocalNodeId() { * Get the {@link TransportAction} for an {@link ActionType}, throwing exceptions if the action isn't available. */ @SuppressWarnings("unchecked") - private TransportAction transportAction( + protected TransportAction transportAction( ActionType action ) { if (actionRegistry == null) { diff --git a/server/src/main/java/org/opensearch/client/node/PluginNodeClient.java b/server/src/main/java/org/opensearch/client/node/PluginNodeClient.java new file mode 100644 index 0000000000000..2da1375bfa0fb --- /dev/null +++ b/server/src/main/java/org/opensearch/client/node/PluginNodeClient.java @@ -0,0 +1,89 @@ +/* + * SPDX-License-Identifier: Apache-2.0 + * + * The OpenSearch Contributors require contributions made to + * this file be licensed under the Apache-2.0 license or a + * compatible open source license. + */ + +package org.opensearch.client.node; + +import org.opensearch.action.ActionRequest; +import org.opensearch.action.ActionType; +import org.opensearch.client.Client; +import org.opensearch.common.settings.Settings; +import org.opensearch.common.util.concurrent.PluginContextSwitcher; +import org.opensearch.common.util.concurrent.ThreadContext; +import org.opensearch.core.action.ActionListener; +import org.opensearch.core.action.ActionResponse; +import org.opensearch.plugins.Plugin; +import org.opensearch.tasks.Task; +import org.opensearch.tasks.TaskListener; +import org.opensearch.threadpool.ThreadPool; + +/** + * Client that executes actions on the local node with contextual information about the plugin executing + * transport actions. + * + * @opensearch.api + */ +public class PluginNodeClient extends NodeClient { + private final PluginContextSwitcher contextSwitcher; + + public PluginNodeClient(Settings settings, ThreadPool threadPool, Plugin plugin) { + super(settings, threadPool); + contextSwitcher = new PluginContextSwitcher(threadPool, plugin); + } + + @Override + public void doExecute( + ActionType action, + Request request, + ActionListener listener + ) { + try (ThreadContext.StoredContext storedContext = contextSwitcher.switchContext()) { + // Discard the task because the Client interface doesn't use it. + executeLocally(action, request, listener); + } + } + + /** + * Execute an {@link ActionType} locally, returning that {@link Task} used to track it, and linking an {@link ActionListener}. + * Prefer this method if you don't need access to the task when listening for the response. This is the method used to implement + * the {@link Client} interface. + * + * This client will execute the transport action in the context of the plugin executing this action + */ + @Override + public Task executeLocally( + ActionType action, + Request request, + ActionListener listener + ) { + Task task; + try (ThreadContext.StoredContext storedContext = contextSwitcher.switchContext()) { + // Discard the task because the Client interface doesn't use it. + task = transportAction(action).execute(request, listener); + } + return task; + } + + /** + * Execute an {@link ActionType} locally, returning that {@link Task} used to track it, and linking an {@link TaskListener}. Prefer this + * method if you need access to the task when listening for the response. + * + * This client will execute the transport action in the context of the plugin executing this action + */ + @Override + public Task executeLocally( + ActionType action, + Request request, + TaskListener listener + ) { + Task task; + try (ThreadContext.StoredContext storedContext = contextSwitcher.switchContext()) { + task = transportAction(action).execute(request, listener); + } + return task; + } +} diff --git a/server/src/main/java/org/opensearch/common/util/concurrent/ContextSwitcher.java b/server/src/main/java/org/opensearch/common/util/concurrent/ContextSwitcher.java index c1976add3f05c..d2e706e00845c 100644 --- a/server/src/main/java/org/opensearch/common/util/concurrent/ContextSwitcher.java +++ b/server/src/main/java/org/opensearch/common/util/concurrent/ContextSwitcher.java @@ -8,14 +8,11 @@ package org.opensearch.common.util.concurrent; -import org.opensearch.common.annotation.PublicApi; - /** * ContextSwitcher interface * - * @opensearch.api + * @opensearch.internal */ -@PublicApi(since = "2.17.0") public interface ContextSwitcher { ThreadContext.StoredContext switchContext(); } diff --git a/server/src/main/java/org/opensearch/common/util/concurrent/PluginContextSwitcher.java b/server/src/main/java/org/opensearch/common/util/concurrent/PluginContextSwitcher.java index 7a2c245a27cf2..2ca9b221d5a82 100644 --- a/server/src/main/java/org/opensearch/common/util/concurrent/PluginContextSwitcher.java +++ b/server/src/main/java/org/opensearch/common/util/concurrent/PluginContextSwitcher.java @@ -8,7 +8,6 @@ package org.opensearch.common.util.concurrent; -import org.opensearch.common.annotation.PublicApi; import org.opensearch.plugins.Plugin; import org.opensearch.threadpool.ThreadPool; @@ -16,9 +15,8 @@ * ContextSwitcher that is passed to plugins in order to switch to a fresh context * from any existing context * - * @opensearch.api + * @opensearch.internal */ -@PublicApi(since = "2.17.0") public class PluginContextSwitcher implements ContextSwitcher { private final ThreadPool threadPool; diff --git a/server/src/main/java/org/opensearch/node/Node.java b/server/src/main/java/org/opensearch/node/Node.java index 9b2f4add1fdd1..37cb3bf08b63c 100644 --- a/server/src/main/java/org/opensearch/node/Node.java +++ b/server/src/main/java/org/opensearch/node/Node.java @@ -570,7 +570,6 @@ protected Node( runnableTaskListener = new AtomicReference<>(); final ThreadPool threadPool = new ThreadPool(settings, runnableTaskListener, executorBuilders.toArray(new ExecutorBuilder[0])); - pluginsService.initializePlugins(threadPool); final SetOnce repositoriesServiceReference = new SetOnce<>(); final RemoteStoreNodeService remoteStoreNodeService = new RemoteStoreNodeService(repositoriesServiceReference::get, threadPool); @@ -1453,6 +1452,14 @@ protected Node( transportService.getRemoteClusterService(), namedWriteableRegistry ); + pluginsService.initializePlugins( + settings, + threadPool, + dynamicActionRegistry, + () -> clusterService.localNode().getId(), + transportService.getRemoteClusterService(), + namedWriteableRegistry + ); this.namedWriteableRegistry = namedWriteableRegistry; logger.debug("initializing HTTP handlers ..."); diff --git a/server/src/main/java/org/opensearch/plugins/Plugin.java b/server/src/main/java/org/opensearch/plugins/Plugin.java index 46b2f0111fceb..300f3aba4aff1 100644 --- a/server/src/main/java/org/opensearch/plugins/Plugin.java +++ b/server/src/main/java/org/opensearch/plugins/Plugin.java @@ -34,6 +34,7 @@ import org.opensearch.bootstrap.BootstrapCheck; import org.opensearch.client.Client; +import org.opensearch.client.node.PluginNodeClient; import org.opensearch.cluster.ClusterState; import org.opensearch.cluster.metadata.IndexNameExpressionResolver; import org.opensearch.cluster.metadata.IndexTemplateMetadata; @@ -46,8 +47,6 @@ import org.opensearch.common.settings.Setting; import org.opensearch.common.settings.SettingUpgrader; import org.opensearch.common.settings.Settings; -import org.opensearch.common.util.concurrent.ContextSwitcher; -import org.opensearch.common.util.concurrent.PluginContextSwitcher; import org.opensearch.core.common.io.stream.NamedWriteable; import org.opensearch.core.common.io.stream.NamedWriteableRegistry; import org.opensearch.core.xcontent.NamedXContentRegistry; @@ -95,7 +94,7 @@ @PublicApi(since = "1.0.0") public abstract class Plugin implements Closeable { - protected ContextSwitcher contextSwitcher; + protected PluginNodeClient pluginNodeClient; /** * A feature exposed by the plugin. This should be used if a plugin exposes {@link ClusterState.Custom} or {@link Metadata.Custom}; see @@ -124,15 +123,15 @@ public Collection> getGuiceServiceClasses() } /** - * Setter for PluginContextSwitcher. + * Setter for PluginNodeClient. * - * @param contextSwitcher A client for switching to plugin system context + * @param pluginNodeClient A client for executing transport actions as the plugin */ - final void setContextSwitcher(PluginContextSwitcher contextSwitcher) { - if (this.contextSwitcher != null) { - throw new IllegalStateException("contextSwitcher can only be set once"); + final void setPluginNodeClient(PluginNodeClient pluginNodeClient) { + if (this.pluginNodeClient != null) { + throw new IllegalStateException("pluginNodeClient can only be set once"); } - this.contextSwitcher = contextSwitcher; + this.pluginNodeClient = pluginNodeClient; } /** diff --git a/server/src/main/java/org/opensearch/plugins/PluginsService.java b/server/src/main/java/org/opensearch/plugins/PluginsService.java index 886777ffa4720..54bd9cc7a70d6 100644 --- a/server/src/main/java/org/opensearch/plugins/PluginsService.java +++ b/server/src/main/java/org/opensearch/plugins/PluginsService.java @@ -42,21 +42,24 @@ import org.opensearch.Build; import org.opensearch.OpenSearchException; import org.opensearch.Version; +import org.opensearch.action.ActionModule; import org.opensearch.action.admin.cluster.node.info.PluginsAndModules; import org.opensearch.bootstrap.JarHell; +import org.opensearch.client.node.PluginNodeClient; import org.opensearch.common.collect.Tuple; import org.opensearch.common.inject.Module; import org.opensearch.common.lifecycle.LifecycleComponent; import org.opensearch.common.settings.Setting; import org.opensearch.common.settings.Setting.Property; import org.opensearch.common.settings.Settings; -import org.opensearch.common.util.concurrent.PluginContextSwitcher; import org.opensearch.core.common.Strings; +import org.opensearch.core.common.io.stream.NamedWriteableRegistry; import org.opensearch.core.service.ReportingService; import org.opensearch.index.IndexModule; import org.opensearch.semver.SemverRange; import org.opensearch.threadpool.ExecutorBuilder; import org.opensearch.threadpool.ThreadPool; +import org.opensearch.transport.RemoteClusterService; import org.opensearch.transport.TransportSettings; import java.io.IOException; @@ -83,6 +86,7 @@ import java.util.Set; import java.util.TreeMap; import java.util.function.Function; +import java.util.function.Supplier; import java.util.stream.Collectors; import static org.opensearch.core.util.FileSystemUtils.isAccessibleDirectory; @@ -777,11 +781,19 @@ private Class loadPluginClass(String className, ClassLoader lo } } - public void initializePlugins(ThreadPool threadPool) { + public void initializePlugins( + Settings settings, + ThreadPool threadPool, + ActionModule.DynamicActionRegistry actionRegistry, + Supplier localNodeId, + RemoteClusterService remoteClusterService, + NamedWriteableRegistry namedWriteableRegistry + ) { List pluginList = filterPlugins(Plugin.class); for (Plugin p : pluginList) { - PluginContextSwitcher contextSwitcher = new PluginContextSwitcher(threadPool, p); - p.setContextSwitcher(contextSwitcher); + PluginNodeClient client = new PluginNodeClient(settings, threadPool, p); + client.initialize(actionRegistry, localNodeId, remoteClusterService, namedWriteableRegistry); + p.setPluginNodeClient(client); } } From 84a325d397b259d26a54850ae6634608157f8bda Mon Sep 17 00:00:00 2001 From: Craig Perkins Date: Wed, 7 Aug 2024 13:31:00 -0400 Subject: [PATCH 29/65] Add test Signed-off-by: Craig Perkins --- .../opensearch/http/ExecutionContextPluginGetIT.java | 2 +- .../common/util/concurrent/ThreadContextTests.java | 12 ++++++++++++ 2 files changed, 13 insertions(+), 1 deletion(-) diff --git a/qa/smoke-test-http/src/test/java/org/opensearch/http/ExecutionContextPluginGetIT.java b/qa/smoke-test-http/src/test/java/org/opensearch/http/ExecutionContextPluginGetIT.java index 08cc59b868fdc..6b259e104a72e 100644 --- a/qa/smoke-test-http/src/test/java/org/opensearch/http/ExecutionContextPluginGetIT.java +++ b/qa/smoke-test-http/src/test/java/org/opensearch/http/ExecutionContextPluginGetIT.java @@ -24,7 +24,7 @@ import static org.hamcrest.Matchers.equalTo; /** - * Test a rest action that sets special response headers + * Test to ensure that plugin execution context is set when plugin uses pluginNodeClient */ @ClusterScope(scope = Scope.SUITE, supportsDedicatedMasters = false, numDataNodes = 1) public class ExecutionContextPluginGetIT extends HttpSmokeTestCase { diff --git a/server/src/test/java/org/opensearch/common/util/concurrent/ThreadContextTests.java b/server/src/test/java/org/opensearch/common/util/concurrent/ThreadContextTests.java index 177bfc2415319..316b6be606cbe 100644 --- a/server/src/test/java/org/opensearch/common/util/concurrent/ThreadContextTests.java +++ b/server/src/test/java/org/opensearch/common/util/concurrent/ThreadContextTests.java @@ -34,6 +34,7 @@ import org.opensearch.common.io.stream.BytesStreamOutput; import org.opensearch.common.logging.HeaderWarning; import org.opensearch.common.settings.Settings; +import org.opensearch.plugins.Plugin; import org.opensearch.test.OpenSearchTestCase; import java.io.IOException; @@ -73,6 +74,17 @@ public void testStashContext() { assertEquals("1", threadContext.getHeader("default")); } + public void testStashContextWithPluginInfo() { + ThreadContext threadContext = new ThreadContext(Settings.EMPTY); + threadContext.putHeader("foo", "bar"); + try (ThreadContext.StoredContext ctx = threadContext.stashContext(Plugin.class)) { + assertNull(threadContext.getHeader("foo")); + assertEquals(Plugin.class.getCanonicalName(), threadContext.getHeader("_plugin_execution_context")); + } + + assertNull(threadContext.getHeader("_plugin_execution_context")); + } + public void testStashContextWithPersistentHeaders() { Settings build = Settings.builder().put("request.headers.default", "1").build(); ThreadContext threadContext = new ThreadContext(build); From 45c4a3e6228283e1209eadd8c274f136f5198f8b Mon Sep 17 00:00:00 2001 From: Craig Perkins Date: Wed, 7 Aug 2024 14:43:52 -0400 Subject: [PATCH 30/65] Add another test for setPluginNodeClient Signed-off-by: Craig Perkins --- .../org/opensearch/plugins/PluginsServiceTests.java | 10 ++++++++++ 1 file changed, 10 insertions(+) diff --git a/server/src/test/java/org/opensearch/plugins/PluginsServiceTests.java b/server/src/test/java/org/opensearch/plugins/PluginsServiceTests.java index bd9ee33856f14..ae69342f90362 100644 --- a/server/src/test/java/org/opensearch/plugins/PluginsServiceTests.java +++ b/server/src/test/java/org/opensearch/plugins/PluginsServiceTests.java @@ -39,6 +39,7 @@ import org.opensearch.LegacyESVersion; import org.opensearch.Version; import org.opensearch.bootstrap.JarHell; +import org.opensearch.client.node.PluginNodeClient; import org.opensearch.common.collect.Tuple; import org.opensearch.common.io.PathUtils; import org.opensearch.common.settings.Settings; @@ -928,6 +929,15 @@ public void testPluginLoadFailure() throws IOException { assertThat(exception, hasToString(containsString("Unable to load plugin class [DummyClass]"))); } + public void testSetPluginNodeClient() { + TestPlugin testPlugin = new TestPlugin(); + PluginNodeClient pluginNodeClient = new PluginNodeClient(Settings.EMPTY, null, testPlugin); + testPlugin.setPluginNodeClient(pluginNodeClient); // should succeed + IllegalStateException e = expectThrows(IllegalStateException.class, () -> testPlugin.setPluginNodeClient(pluginNodeClient)); + assertThat(e.getMessage(), containsString("pluginNodeClient can only be set once")); + + } + public void testExtensiblePlugin() { TestExtensiblePlugin extensiblePlugin = new TestExtensiblePlugin(); PluginsService.loadExtensions( From e41496a7aa8c63a3d0f778aa04da66b68f7256fe Mon Sep 17 00:00:00 2001 From: Craig Perkins Date: Wed, 7 Aug 2024 16:53:08 -0400 Subject: [PATCH 31/65] Remove newline Signed-off-by: Craig Perkins --- .../test/java/org/opensearch/plugins/PluginsServiceTests.java | 1 - 1 file changed, 1 deletion(-) diff --git a/server/src/test/java/org/opensearch/plugins/PluginsServiceTests.java b/server/src/test/java/org/opensearch/plugins/PluginsServiceTests.java index ae69342f90362..0b47c21fa4e55 100644 --- a/server/src/test/java/org/opensearch/plugins/PluginsServiceTests.java +++ b/server/src/test/java/org/opensearch/plugins/PluginsServiceTests.java @@ -935,7 +935,6 @@ public void testSetPluginNodeClient() { testPlugin.setPluginNodeClient(pluginNodeClient); // should succeed IllegalStateException e = expectThrows(IllegalStateException.class, () -> testPlugin.setPluginNodeClient(pluginNodeClient)); assertThat(e.getMessage(), containsString("pluginNodeClient can only be set once")); - } public void testExtensiblePlugin() { From bccf5eb777849a97fe9102c2692b4e0bd8b45620 Mon Sep 17 00:00:00 2001 From: Craig Perkins Date: Thu, 8 Aug 2024 11:36:34 -0400 Subject: [PATCH 32/65] Add another test Signed-off-by: Craig Perkins --- .../plugins/PluginsServiceTests.java | 25 +++++++++++++++++++ 1 file changed, 25 insertions(+) diff --git a/server/src/test/java/org/opensearch/plugins/PluginsServiceTests.java b/server/src/test/java/org/opensearch/plugins/PluginsServiceTests.java index 0b47c21fa4e55..148b2cc09783e 100644 --- a/server/src/test/java/org/opensearch/plugins/PluginsServiceTests.java +++ b/server/src/test/java/org/opensearch/plugins/PluginsServiceTests.java @@ -38,11 +38,13 @@ import org.apache.lucene.util.Constants; import org.opensearch.LegacyESVersion; import org.opensearch.Version; +import org.opensearch.action.ActionModule; import org.opensearch.bootstrap.JarHell; import org.opensearch.client.node.PluginNodeClient; import org.opensearch.common.collect.Tuple; import org.opensearch.common.io.PathUtils; import org.opensearch.common.settings.Settings; +import org.opensearch.core.common.io.stream.NamedWriteableRegistry; import org.opensearch.env.Environment; import org.opensearch.env.TestEnvironment; import org.opensearch.index.IndexModule; @@ -50,6 +52,7 @@ import org.opensearch.test.MockLogAppender; import org.opensearch.test.OpenSearchTestCase; import org.opensearch.test.VersionUtils; +import org.opensearch.threadpool.ThreadPool; import org.hamcrest.Matchers; import java.io.IOException; @@ -67,6 +70,7 @@ import java.util.Locale; import java.util.Map; import java.util.Set; +import java.util.function.Supplier; import java.util.zip.ZipEntry; import java.util.zip.ZipInputStream; import java.util.zip.ZipOutputStream; @@ -78,6 +82,7 @@ import static org.hamcrest.Matchers.instanceOf; import static org.hamcrest.Matchers.notNullValue; import static org.hamcrest.Matchers.sameInstance; +import static org.mockito.Mockito.mock; @LuceneTestCase.SuppressFileSystems(value = "ExtrasFS") public class PluginsServiceTests extends OpenSearchTestCase { @@ -937,6 +942,26 @@ public void testSetPluginNodeClient() { assertThat(e.getMessage(), containsString("pluginNodeClient can only be set once")); } + public void testInitializePlugins() { + Settings settings = Settings.builder().put(Environment.PATH_HOME_SETTING.getKey(), createTempDir()).build(); + PluginsService service = newPluginsService(settings, TestPlugin.class); + + service.initializePlugins( + Settings.EMPTY, + mock(ThreadPool.class), + mock(ActionModule.DynamicActionRegistry.class), + mock(Supplier.class), + null, + mock(NamedWriteableRegistry.class) + ); + + Plugin testPlugin = service.filterPlugins(Plugin.class).get(0); + PluginNodeClient pluginNodeClient = new PluginNodeClient(Settings.EMPTY, null, testPlugin); + // pluginNodeClient should have previously been set in service.initializePlugins + IllegalStateException e = expectThrows(IllegalStateException.class, () -> testPlugin.setPluginNodeClient(pluginNodeClient)); + assertThat(e.getMessage(), containsString("pluginNodeClient can only be set once")); + } + public void testExtensiblePlugin() { TestExtensiblePlugin extensiblePlugin = new TestExtensiblePlugin(); PluginsService.loadExtensions( From e685c5cf4662e07d6e149414c2cb41b39dc61ca2 Mon Sep 17 00:00:00 2001 From: Craig Perkins Date: Tue, 13 Aug 2024 14:52:15 -0400 Subject: [PATCH 33/65] Subject.runAs and introduce PluginSubject Signed-off-by: Craig Perkins --- .../identity/shiro/ShiroSubject.java | 5 ++ .../http/ExecutionContextPluginGetIT.java | 2 +- .../TestExecutionContextPlugin.java | 6 +- .../TestGetExecutionContextRestAction.java | 13 ++- ...estGetExecutionContextTransportAction.java | 11 ++- .../client/node/PluginNodeClient.java | 89 ------------------- .../util/concurrent/ContextSwitcher.java | 18 ---- .../concurrent/PluginContextSwitcher.java | 34 ------- .../common/util/concurrent/ThreadContext.java | 56 ------------ .../java/org/opensearch/identity/Subject.java | 21 +++++ .../opensearch/identity/noop/NoopSubject.java | 5 ++ .../main/java/org/opensearch/node/Node.java | 9 +- .../java/org/opensearch/plugins/Plugin.java | 15 ++-- .../org/opensearch/plugins/PluginSubject.java | 52 +++++++++++ .../opensearch/plugins/PluginsService.java | 19 +--- .../util/concurrent/ThreadContextTests.java | 17 ---- .../plugins/PluginsServiceTests.java | 31 +++---- 17 files changed, 124 insertions(+), 279 deletions(-) delete mode 100644 server/src/main/java/org/opensearch/client/node/PluginNodeClient.java delete mode 100644 server/src/main/java/org/opensearch/common/util/concurrent/ContextSwitcher.java delete mode 100644 server/src/main/java/org/opensearch/common/util/concurrent/PluginContextSwitcher.java create mode 100644 server/src/main/java/org/opensearch/plugins/PluginSubject.java diff --git a/plugins/identity-shiro/src/main/java/org/opensearch/identity/shiro/ShiroSubject.java b/plugins/identity-shiro/src/main/java/org/opensearch/identity/shiro/ShiroSubject.java index e55204593621c..76ee2808fdfd0 100644 --- a/plugins/identity-shiro/src/main/java/org/opensearch/identity/shiro/ShiroSubject.java +++ b/plugins/identity-shiro/src/main/java/org/opensearch/identity/shiro/ShiroSubject.java @@ -88,4 +88,9 @@ public void authenticate(AuthToken authenticationToken) { .orElseThrow(() -> new UnsupportedAuthenticationToken()); shiroSubject.login(authToken); } + + @Override + public Session runAs() { + return null; + } } diff --git a/qa/smoke-test-http/src/test/java/org/opensearch/http/ExecutionContextPluginGetIT.java b/qa/smoke-test-http/src/test/java/org/opensearch/http/ExecutionContextPluginGetIT.java index 6b259e104a72e..ea627196f1052 100644 --- a/qa/smoke-test-http/src/test/java/org/opensearch/http/ExecutionContextPluginGetIT.java +++ b/qa/smoke-test-http/src/test/java/org/opensearch/http/ExecutionContextPluginGetIT.java @@ -24,7 +24,7 @@ import static org.hamcrest.Matchers.equalTo; /** - * Test to ensure that plugin execution context is set when plugin uses pluginNodeClient + * Test to ensure that plugin execution context is set when plugin runs transport action with PluginSubject */ @ClusterScope(scope = Scope.SUITE, supportsDedicatedMasters = false, numDataNodes = 1) public class ExecutionContextPluginGetIT extends HttpSmokeTestCase { diff --git a/qa/smoke-test-http/src/test/java/org/opensearch/http/executioncontextplugin/TestExecutionContextPlugin.java b/qa/smoke-test-http/src/test/java/org/opensearch/http/executioncontextplugin/TestExecutionContextPlugin.java index c41bd1f65a8a7..bfd8dab1aca5f 100644 --- a/qa/smoke-test-http/src/test/java/org/opensearch/http/executioncontextplugin/TestExecutionContextPlugin.java +++ b/qa/smoke-test-http/src/test/java/org/opensearch/http/executioncontextplugin/TestExecutionContextPlugin.java @@ -37,6 +37,7 @@ import java.util.function.Supplier; public class TestExecutionContextPlugin extends Plugin implements ActionPlugin { + private Client client; private ThreadPool threadPool; @Override @@ -52,15 +53,16 @@ public Collection createComponents( NamedWriteableRegistry namedWriteableRegistry, IndexNameExpressionResolver expressionResolver, Supplier repositoriesServiceSupplier) { + this.client = client; this.threadPool = threadPool; - return Collections.emptyList(); + return Collections.singletonList(pluginSubject); } @Override public List getRestHandlers(Settings settings, RestController restController, ClusterSettings clusterSettings, IndexScopedSettings indexScopedSettings, SettingsFilter settingsFilter, IndexNameExpressionResolver indexNameExpressionResolver, Supplier nodesInCluster) { - return List.of(new TestGetExecutionContextRestAction(pluginNodeClient, threadPool)); + return List.of(new TestGetExecutionContextRestAction(client)); } @Override diff --git a/qa/smoke-test-http/src/test/java/org/opensearch/http/executioncontextplugin/TestGetExecutionContextRestAction.java b/qa/smoke-test-http/src/test/java/org/opensearch/http/executioncontextplugin/TestGetExecutionContextRestAction.java index bb86f78d4baea..03d2940f68602 100644 --- a/qa/smoke-test-http/src/test/java/org/opensearch/http/executioncontextplugin/TestGetExecutionContextRestAction.java +++ b/qa/smoke-test-http/src/test/java/org/opensearch/http/executioncontextplugin/TestGetExecutionContextRestAction.java @@ -8,8 +8,9 @@ package org.opensearch.http.executioncontextplugin; +import org.opensearch.client.Client; import org.opensearch.client.node.NodeClient; -import org.opensearch.client.node.PluginNodeClient; +import org.opensearch.plugins.PluginSubject; import org.opensearch.rest.BaseRestHandler; import org.opensearch.rest.RestRequest; import org.opensearch.rest.action.RestToXContentListener; @@ -22,12 +23,10 @@ public class TestGetExecutionContextRestAction extends BaseRestHandler { - private final PluginNodeClient pluginNodeClient; - private final ThreadPool threadPool; + private final Client client; - public TestGetExecutionContextRestAction(PluginNodeClient pluginNodeClient, ThreadPool threadPool) { - this.pluginNodeClient = pluginNodeClient; - this.threadPool = threadPool; + public TestGetExecutionContextRestAction(Client client) { + this.client = client; } @Override @@ -43,6 +42,6 @@ public String getName() { @Override public RestChannelConsumer prepareRequest(RestRequest request, NodeClient client) { final TestGetExecutionContextRequest getExecutionContextRequest = new TestGetExecutionContextRequest(); - return channel -> pluginNodeClient.executeLocally(TestGetExecutionContextAction.INSTANCE, getExecutionContextRequest, new RestToXContentListener<>(channel)); + return channel -> client.execute(TestGetExecutionContextAction.INSTANCE, getExecutionContextRequest, new RestToXContentListener<>(channel)); } } diff --git a/qa/smoke-test-http/src/test/java/org/opensearch/http/executioncontextplugin/TestGetExecutionContextTransportAction.java b/qa/smoke-test-http/src/test/java/org/opensearch/http/executioncontextplugin/TestGetExecutionContextTransportAction.java index 22c051e75ce33..5f4986aa65e2d 100644 --- a/qa/smoke-test-http/src/test/java/org/opensearch/http/executioncontextplugin/TestGetExecutionContextTransportAction.java +++ b/qa/smoke-test-http/src/test/java/org/opensearch/http/executioncontextplugin/TestGetExecutionContextTransportAction.java @@ -13,6 +13,8 @@ import org.opensearch.common.inject.Inject; import org.opensearch.common.util.concurrent.ThreadContext; import org.opensearch.core.action.ActionListener; +import org.opensearch.identity.Subject; +import org.opensearch.plugins.PluginSubject; import org.opensearch.tasks.Task; import org.opensearch.transport.TransportService; @@ -23,16 +25,21 @@ */ public class TestGetExecutionContextTransportAction extends HandledTransportAction { private final TransportService transportService; + private final PluginSubject pluginSubject; @Inject - public TestGetExecutionContextTransportAction(TransportService transportService, ActionFilters actionFilters) { + public TestGetExecutionContextTransportAction(TransportService transportService, ActionFilters actionFilters, PluginSubject pluginSubject) { super(TestGetExecutionContextAction.NAME, transportService, actionFilters, TestGetExecutionContextRequest::new); this.transportService = transportService; + this.pluginSubject = pluginSubject; } @Override protected void doExecute(Task task, TestGetExecutionContextRequest request, ActionListener listener) { - String pluginClassName = transportService.getThreadPool().getThreadContext().getHeader(ThreadContext.PLUGIN_EXECUTION_CONTEXT); + String pluginClassName; + try (Subject.Session session = pluginSubject.runAs()) { + pluginClassName = transportService.getThreadPool().getThreadContext().getHeader(PluginSubject.PLUGIN_EXECUTION_CONTEXT); + } listener.onResponse(new TestGetExecutionContextResponse(pluginClassName)); } } diff --git a/server/src/main/java/org/opensearch/client/node/PluginNodeClient.java b/server/src/main/java/org/opensearch/client/node/PluginNodeClient.java deleted file mode 100644 index 2da1375bfa0fb..0000000000000 --- a/server/src/main/java/org/opensearch/client/node/PluginNodeClient.java +++ /dev/null @@ -1,89 +0,0 @@ -/* - * SPDX-License-Identifier: Apache-2.0 - * - * The OpenSearch Contributors require contributions made to - * this file be licensed under the Apache-2.0 license or a - * compatible open source license. - */ - -package org.opensearch.client.node; - -import org.opensearch.action.ActionRequest; -import org.opensearch.action.ActionType; -import org.opensearch.client.Client; -import org.opensearch.common.settings.Settings; -import org.opensearch.common.util.concurrent.PluginContextSwitcher; -import org.opensearch.common.util.concurrent.ThreadContext; -import org.opensearch.core.action.ActionListener; -import org.opensearch.core.action.ActionResponse; -import org.opensearch.plugins.Plugin; -import org.opensearch.tasks.Task; -import org.opensearch.tasks.TaskListener; -import org.opensearch.threadpool.ThreadPool; - -/** - * Client that executes actions on the local node with contextual information about the plugin executing - * transport actions. - * - * @opensearch.api - */ -public class PluginNodeClient extends NodeClient { - private final PluginContextSwitcher contextSwitcher; - - public PluginNodeClient(Settings settings, ThreadPool threadPool, Plugin plugin) { - super(settings, threadPool); - contextSwitcher = new PluginContextSwitcher(threadPool, plugin); - } - - @Override - public void doExecute( - ActionType action, - Request request, - ActionListener listener - ) { - try (ThreadContext.StoredContext storedContext = contextSwitcher.switchContext()) { - // Discard the task because the Client interface doesn't use it. - executeLocally(action, request, listener); - } - } - - /** - * Execute an {@link ActionType} locally, returning that {@link Task} used to track it, and linking an {@link ActionListener}. - * Prefer this method if you don't need access to the task when listening for the response. This is the method used to implement - * the {@link Client} interface. - * - * This client will execute the transport action in the context of the plugin executing this action - */ - @Override - public Task executeLocally( - ActionType action, - Request request, - ActionListener listener - ) { - Task task; - try (ThreadContext.StoredContext storedContext = contextSwitcher.switchContext()) { - // Discard the task because the Client interface doesn't use it. - task = transportAction(action).execute(request, listener); - } - return task; - } - - /** - * Execute an {@link ActionType} locally, returning that {@link Task} used to track it, and linking an {@link TaskListener}. Prefer this - * method if you need access to the task when listening for the response. - * - * This client will execute the transport action in the context of the plugin executing this action - */ - @Override - public Task executeLocally( - ActionType action, - Request request, - TaskListener listener - ) { - Task task; - try (ThreadContext.StoredContext storedContext = contextSwitcher.switchContext()) { - task = transportAction(action).execute(request, listener); - } - return task; - } -} diff --git a/server/src/main/java/org/opensearch/common/util/concurrent/ContextSwitcher.java b/server/src/main/java/org/opensearch/common/util/concurrent/ContextSwitcher.java deleted file mode 100644 index d2e706e00845c..0000000000000 --- a/server/src/main/java/org/opensearch/common/util/concurrent/ContextSwitcher.java +++ /dev/null @@ -1,18 +0,0 @@ -/* - * SPDX-License-Identifier: Apache-2.0 - * - * The OpenSearch Contributors require contributions made to - * this file be licensed under the Apache-2.0 license or a - * compatible open source license. - */ - -package org.opensearch.common.util.concurrent; - -/** - * ContextSwitcher interface - * - * @opensearch.internal - */ -public interface ContextSwitcher { - ThreadContext.StoredContext switchContext(); -} diff --git a/server/src/main/java/org/opensearch/common/util/concurrent/PluginContextSwitcher.java b/server/src/main/java/org/opensearch/common/util/concurrent/PluginContextSwitcher.java deleted file mode 100644 index 2ca9b221d5a82..0000000000000 --- a/server/src/main/java/org/opensearch/common/util/concurrent/PluginContextSwitcher.java +++ /dev/null @@ -1,34 +0,0 @@ -/* - * SPDX-License-Identifier: Apache-2.0 - * - * The OpenSearch Contributors require contributions made to - * this file be licensed under the Apache-2.0 license or a - * compatible open source license. - */ - -package org.opensearch.common.util.concurrent; - -import org.opensearch.plugins.Plugin; -import org.opensearch.threadpool.ThreadPool; - -/** - * ContextSwitcher that is passed to plugins in order to switch to a fresh context - * from any existing context - * - * @opensearch.internal - */ -public class PluginContextSwitcher implements ContextSwitcher { - - private final ThreadPool threadPool; - private final Plugin plugin; - - public PluginContextSwitcher(ThreadPool threadPool, Plugin plugin) { - this.threadPool = threadPool; - this.plugin = plugin; - } - - @Override - public ThreadContext.StoredContext switchContext() { - return threadPool.getThreadContext().stashContext(plugin.getClass()); - } -} diff --git a/server/src/main/java/org/opensearch/common/util/concurrent/ThreadContext.java b/server/src/main/java/org/opensearch/common/util/concurrent/ThreadContext.java index 0a525b4cb427d..95d20d49a74ca 100644 --- a/server/src/main/java/org/opensearch/common/util/concurrent/ThreadContext.java +++ b/server/src/main/java/org/opensearch/common/util/concurrent/ThreadContext.java @@ -113,10 +113,6 @@ public final class ThreadContext implements Writeable { */ public static final String ACTION_ORIGIN_TRANSIENT_NAME = "action.origin"; - public static final String PLUGIN_EXECUTION_CONTEXT = "_plugin_execution_context"; - - private static final Set FORBIDDEN_HEADRES = Set.of(PLUGIN_EXECUTION_CONTEXT); - // thread context permissions private static final Permission ACCESS_SYSTEM_THREAD_CONTEXT_PERMISSION = new ThreadContextPermission("markAsSystemContext"); @@ -189,44 +185,6 @@ public StoredContext stashContext() { }; } - /** - * Removes the current context and resets a default context. Retains information about plugin stashing the context. - * The removed context can be restored by closing the returned {@link StoredContext}. - */ - StoredContext stashContext(Class pluginClass) { - final ThreadContextStruct context = threadLocal.get(); - /* - X-Opaque-ID should be preserved in a threadContext in order to propagate this across threads. - This is needed so the DeprecationLogger in another thread can see the value of X-Opaque-ID provided by a user. - Otherwise when context is stash, it should be empty. - */ - - ThreadContextStruct threadContextStruct = DEFAULT_CONTEXT.putPersistent(context.persistentHeaders); - - if (context.requestHeaders.containsKey(Task.X_OPAQUE_ID)) { - threadContextStruct = threadContextStruct.putHeaders( - MapBuilder.newMapBuilder() - .put(Task.X_OPAQUE_ID, context.requestHeaders.get(Task.X_OPAQUE_ID)) - .immutableMap() - ); - } - - final Map transientHeaders = propagateTransients(context.transientHeaders, context.isSystemContext); - if (!transientHeaders.isEmpty()) { - threadContextStruct = threadContextStruct.putTransient(transientHeaders); - } - - threadContextStruct = threadContextStruct.putPluginExecutionContext(pluginClass); - threadLocal.set(threadContextStruct); - - return () -> { - // If the node and thus the threadLocal get closed while this task - // is still executing, we don't want this runnable to fail with an - // uncaught exception - threadLocal.set(context); - }; - } - /** * Captures the current thread context as writeable, allowing it to be serialized out later */ @@ -507,9 +465,6 @@ public void copyHeaders(Iterable> headers) { * Puts a header into the context */ public void putHeader(String key, String value) { - if (FORBIDDEN_HEADRES.contains(key)) { - throw new IllegalArgumentException("Cannot set forbidden header: " + key); - } threadLocal.set(threadLocal.get().putRequest(key, value)); } @@ -759,14 +714,6 @@ private ThreadContextStruct() { this(Collections.emptyMap(), Collections.emptyMap(), Collections.emptyMap(), Collections.emptyMap(), false); } - private ThreadContextStruct putPluginExecutionContext(Class pluginClass) { - Map newRequestHeaders = new HashMap<>(this.requestHeaders); - if (newRequestHeaders.putIfAbsent(PLUGIN_EXECUTION_CONTEXT, pluginClass.getCanonicalName()) != null) { - throw new IllegalArgumentException("value for key [" + PLUGIN_EXECUTION_CONTEXT + "] already present"); - } - return new ThreadContextStruct(newRequestHeaders, responseHeaders, transientHeaders, persistentHeaders, isSystemContext); - } - private ThreadContextStruct putRequest(String key, String value) { Map newRequestHeaders = new HashMap<>(this.requestHeaders); putSingleHeader(key, value, newRequestHeaders); @@ -774,9 +721,6 @@ private ThreadContextStruct putRequest(String key, String value) { } private static void putSingleHeader(String key, T value, Map newHeaders) { - if (FORBIDDEN_HEADRES.contains(key)) { - throw new IllegalArgumentException("Cannot set forbidden header: " + key); - } if (newHeaders.putIfAbsent(key, value) != null) { throw new IllegalArgumentException("value for key [" + key + "] already present"); } diff --git a/server/src/main/java/org/opensearch/identity/Subject.java b/server/src/main/java/org/opensearch/identity/Subject.java index cbfdadb5cf6a7..fd74d5d93496c 100644 --- a/server/src/main/java/org/opensearch/identity/Subject.java +++ b/server/src/main/java/org/opensearch/identity/Subject.java @@ -5,6 +5,7 @@ package org.opensearch.identity; +import org.opensearch.common.annotation.PublicApi; import org.opensearch.identity.tokens.AuthToken; import java.security.Principal; @@ -29,4 +30,24 @@ public interface Subject { * throws SubjectDisabled */ void authenticate(final AuthToken token); + + /** + * runAs allows the caller to create a session as this subject + * + * @return A session to run transport actions in the context of this subject + */ + Session runAs(); + + /** + * This construct represents a session for this subject. A session is a short-lived block + * where transport actions are executed as this subject + * + * @opensearch.api + */ + @FunctionalInterface + @PublicApi(since = "2.17.0") + interface Session extends AutoCloseable { + @Override + void close(); + } } diff --git a/server/src/main/java/org/opensearch/identity/noop/NoopSubject.java b/server/src/main/java/org/opensearch/identity/noop/NoopSubject.java index 964a218db3cf5..3f48ad1b473d1 100644 --- a/server/src/main/java/org/opensearch/identity/noop/NoopSubject.java +++ b/server/src/main/java/org/opensearch/identity/noop/NoopSubject.java @@ -54,4 +54,9 @@ public String toString() { public void authenticate(AuthToken AuthToken) { // Do nothing as noop subject is always logged in } + + @Override + public Session runAs() { + return null; + } } diff --git a/server/src/main/java/org/opensearch/node/Node.java b/server/src/main/java/org/opensearch/node/Node.java index 37cb3bf08b63c..9b2f4add1fdd1 100644 --- a/server/src/main/java/org/opensearch/node/Node.java +++ b/server/src/main/java/org/opensearch/node/Node.java @@ -570,6 +570,7 @@ protected Node( runnableTaskListener = new AtomicReference<>(); final ThreadPool threadPool = new ThreadPool(settings, runnableTaskListener, executorBuilders.toArray(new ExecutorBuilder[0])); + pluginsService.initializePlugins(threadPool); final SetOnce repositoriesServiceReference = new SetOnce<>(); final RemoteStoreNodeService remoteStoreNodeService = new RemoteStoreNodeService(repositoriesServiceReference::get, threadPool); @@ -1452,14 +1453,6 @@ protected Node( transportService.getRemoteClusterService(), namedWriteableRegistry ); - pluginsService.initializePlugins( - settings, - threadPool, - dynamicActionRegistry, - () -> clusterService.localNode().getId(), - transportService.getRemoteClusterService(), - namedWriteableRegistry - ); this.namedWriteableRegistry = namedWriteableRegistry; logger.debug("initializing HTTP handlers ..."); diff --git a/server/src/main/java/org/opensearch/plugins/Plugin.java b/server/src/main/java/org/opensearch/plugins/Plugin.java index 300f3aba4aff1..9fabb8b93b367 100644 --- a/server/src/main/java/org/opensearch/plugins/Plugin.java +++ b/server/src/main/java/org/opensearch/plugins/Plugin.java @@ -34,7 +34,6 @@ import org.opensearch.bootstrap.BootstrapCheck; import org.opensearch.client.Client; -import org.opensearch.client.node.PluginNodeClient; import org.opensearch.cluster.ClusterState; import org.opensearch.cluster.metadata.IndexNameExpressionResolver; import org.opensearch.cluster.metadata.IndexTemplateMetadata; @@ -94,7 +93,7 @@ @PublicApi(since = "1.0.0") public abstract class Plugin implements Closeable { - protected PluginNodeClient pluginNodeClient; + protected PluginSubject pluginSubject; /** * A feature exposed by the plugin. This should be used if a plugin exposes {@link ClusterState.Custom} or {@link Metadata.Custom}; see @@ -123,15 +122,15 @@ public Collection> getGuiceServiceClasses() } /** - * Setter for PluginNodeClient. + * Setter for PluginSubject. * - * @param pluginNodeClient A client for executing transport actions as the plugin + * @param pluginSubject A subject for executing transport actions as the plugin */ - final void setPluginNodeClient(PluginNodeClient pluginNodeClient) { - if (this.pluginNodeClient != null) { - throw new IllegalStateException("pluginNodeClient can only be set once"); + final void setPluginSubject(PluginSubject pluginSubject) { + if (this.pluginSubject != null) { + throw new IllegalStateException("pluginSubject can only be set once"); } - this.pluginNodeClient = pluginNodeClient; + this.pluginSubject = pluginSubject; } /** diff --git a/server/src/main/java/org/opensearch/plugins/PluginSubject.java b/server/src/main/java/org/opensearch/plugins/PluginSubject.java new file mode 100644 index 0000000000000..a4940a25afc2e --- /dev/null +++ b/server/src/main/java/org/opensearch/plugins/PluginSubject.java @@ -0,0 +1,52 @@ +/* + * SPDX-License-Identifier: Apache-2.0 + * + * The OpenSearch Contributors require contributions made to + * this file be licensed under the Apache-2.0 license or a + * compatible open source license. + */ + +package org.opensearch.plugins; + +import org.opensearch.common.util.concurrent.ThreadContext; +import org.opensearch.identity.NamedPrincipal; +import org.opensearch.identity.Subject; +import org.opensearch.identity.tokens.AuthToken; +import org.opensearch.threadpool.ThreadPool; + +import java.security.Principal; + +/** + * PluginSubject is passed to plugins within createComponents and does not require + * an auth token to authenticate + * + * @opensearch.api + */ +public class PluginSubject implements Subject { + public static final String PLUGIN_EXECUTION_CONTEXT = "_plugin_execution_context"; + + private final NamedPrincipal pluginCanonicalName; + private final ThreadPool threadPool; + + PluginSubject(Class pluginClass, ThreadPool threadPool) { + this.pluginCanonicalName = new NamedPrincipal(pluginClass.getCanonicalName()); + this.threadPool = threadPool; + } + + @Override + public Principal getPrincipal() { + return pluginCanonicalName; + } + + @Override + public void authenticate(AuthToken token) { + // no-op + } + + @Override + public Session runAs() { + ThreadContext.StoredContext ctx = threadPool.getThreadContext().stashContext(); + threadPool.getThreadContext().putHeader(PLUGIN_EXECUTION_CONTEXT, pluginCanonicalName.getName()); + return ctx::restore; + } +} diff --git a/server/src/main/java/org/opensearch/plugins/PluginsService.java b/server/src/main/java/org/opensearch/plugins/PluginsService.java index 54bd9cc7a70d6..0960e1d564331 100644 --- a/server/src/main/java/org/opensearch/plugins/PluginsService.java +++ b/server/src/main/java/org/opensearch/plugins/PluginsService.java @@ -42,10 +42,8 @@ import org.opensearch.Build; import org.opensearch.OpenSearchException; import org.opensearch.Version; -import org.opensearch.action.ActionModule; import org.opensearch.action.admin.cluster.node.info.PluginsAndModules; import org.opensearch.bootstrap.JarHell; -import org.opensearch.client.node.PluginNodeClient; import org.opensearch.common.collect.Tuple; import org.opensearch.common.inject.Module; import org.opensearch.common.lifecycle.LifecycleComponent; @@ -53,13 +51,11 @@ import org.opensearch.common.settings.Setting.Property; import org.opensearch.common.settings.Settings; import org.opensearch.core.common.Strings; -import org.opensearch.core.common.io.stream.NamedWriteableRegistry; import org.opensearch.core.service.ReportingService; import org.opensearch.index.IndexModule; import org.opensearch.semver.SemverRange; import org.opensearch.threadpool.ExecutorBuilder; import org.opensearch.threadpool.ThreadPool; -import org.opensearch.transport.RemoteClusterService; import org.opensearch.transport.TransportSettings; import java.io.IOException; @@ -86,7 +82,6 @@ import java.util.Set; import java.util.TreeMap; import java.util.function.Function; -import java.util.function.Supplier; import java.util.stream.Collectors; import static org.opensearch.core.util.FileSystemUtils.isAccessibleDirectory; @@ -781,19 +776,11 @@ private Class loadPluginClass(String className, ClassLoader lo } } - public void initializePlugins( - Settings settings, - ThreadPool threadPool, - ActionModule.DynamicActionRegistry actionRegistry, - Supplier localNodeId, - RemoteClusterService remoteClusterService, - NamedWriteableRegistry namedWriteableRegistry - ) { + public void initializePlugins(ThreadPool threadPool) { List pluginList = filterPlugins(Plugin.class); for (Plugin p : pluginList) { - PluginNodeClient client = new PluginNodeClient(settings, threadPool, p); - client.initialize(actionRegistry, localNodeId, remoteClusterService, namedWriteableRegistry); - p.setPluginNodeClient(client); + PluginSubject pluginSubject = new PluginSubject(p.getClass(), threadPool); + p.setPluginSubject(pluginSubject); } } diff --git a/server/src/test/java/org/opensearch/common/util/concurrent/ThreadContextTests.java b/server/src/test/java/org/opensearch/common/util/concurrent/ThreadContextTests.java index 316b6be606cbe..5992ffa1465b4 100644 --- a/server/src/test/java/org/opensearch/common/util/concurrent/ThreadContextTests.java +++ b/server/src/test/java/org/opensearch/common/util/concurrent/ThreadContextTests.java @@ -34,7 +34,6 @@ import org.opensearch.common.io.stream.BytesStreamOutput; import org.opensearch.common.logging.HeaderWarning; import org.opensearch.common.settings.Settings; -import org.opensearch.plugins.Plugin; import org.opensearch.test.OpenSearchTestCase; import java.io.IOException; @@ -74,17 +73,6 @@ public void testStashContext() { assertEquals("1", threadContext.getHeader("default")); } - public void testStashContextWithPluginInfo() { - ThreadContext threadContext = new ThreadContext(Settings.EMPTY); - threadContext.putHeader("foo", "bar"); - try (ThreadContext.StoredContext ctx = threadContext.stashContext(Plugin.class)) { - assertNull(threadContext.getHeader("foo")); - assertEquals(Plugin.class.getCanonicalName(), threadContext.getHeader("_plugin_execution_context")); - } - - assertNull(threadContext.getHeader("_plugin_execution_context")); - } - public void testStashContextWithPersistentHeaders() { Settings build = Settings.builder().put("request.headers.default", "1").build(); ThreadContext threadContext = new ThreadContext(build); @@ -842,11 +830,6 @@ public void testPutHeaders() { () -> threadContext.putHeader(Collections.singletonMap("foo", "boom")) ); assertEquals("value for key [foo] already present", e.getMessage()); - IllegalArgumentException e2 = expectThrows( - IllegalArgumentException.class, - () -> threadContext.putHeader(Collections.singletonMap("_plugin_execution_context", "org.foo.bar.pluginA")) - ); - assertEquals("Cannot set forbidden header: _plugin_execution_context", e2.getMessage()); } /** diff --git a/server/src/test/java/org/opensearch/plugins/PluginsServiceTests.java b/server/src/test/java/org/opensearch/plugins/PluginsServiceTests.java index 148b2cc09783e..1a5e675a73239 100644 --- a/server/src/test/java/org/opensearch/plugins/PluginsServiceTests.java +++ b/server/src/test/java/org/opensearch/plugins/PluginsServiceTests.java @@ -38,13 +38,10 @@ import org.apache.lucene.util.Constants; import org.opensearch.LegacyESVersion; import org.opensearch.Version; -import org.opensearch.action.ActionModule; import org.opensearch.bootstrap.JarHell; -import org.opensearch.client.node.PluginNodeClient; import org.opensearch.common.collect.Tuple; import org.opensearch.common.io.PathUtils; import org.opensearch.common.settings.Settings; -import org.opensearch.core.common.io.stream.NamedWriteableRegistry; import org.opensearch.env.Environment; import org.opensearch.env.TestEnvironment; import org.opensearch.index.IndexModule; @@ -70,7 +67,6 @@ import java.util.Locale; import java.util.Map; import java.util.Set; -import java.util.function.Supplier; import java.util.zip.ZipEntry; import java.util.zip.ZipInputStream; import java.util.zip.ZipOutputStream; @@ -934,32 +930,25 @@ public void testPluginLoadFailure() throws IOException { assertThat(exception, hasToString(containsString("Unable to load plugin class [DummyClass]"))); } - public void testSetPluginNodeClient() { + public void testSetPluginSubject() { TestPlugin testPlugin = new TestPlugin(); - PluginNodeClient pluginNodeClient = new PluginNodeClient(Settings.EMPTY, null, testPlugin); - testPlugin.setPluginNodeClient(pluginNodeClient); // should succeed - IllegalStateException e = expectThrows(IllegalStateException.class, () -> testPlugin.setPluginNodeClient(pluginNodeClient)); - assertThat(e.getMessage(), containsString("pluginNodeClient can only be set once")); + PluginSubject testPluginSubject = new PluginSubject(testPlugin.getClass(), mock(ThreadPool.class)); + testPlugin.setPluginSubject(testPluginSubject); // should succeed + IllegalStateException e = expectThrows(IllegalStateException.class, () -> testPlugin.setPluginSubject(testPluginSubject)); + assertThat(e.getMessage(), containsString("pluginSubject can only be set once")); } public void testInitializePlugins() { Settings settings = Settings.builder().put(Environment.PATH_HOME_SETTING.getKey(), createTempDir()).build(); PluginsService service = newPluginsService(settings, TestPlugin.class); - service.initializePlugins( - Settings.EMPTY, - mock(ThreadPool.class), - mock(ActionModule.DynamicActionRegistry.class), - mock(Supplier.class), - null, - mock(NamedWriteableRegistry.class) - ); + service.initializePlugins(mock(ThreadPool.class)); Plugin testPlugin = service.filterPlugins(Plugin.class).get(0); - PluginNodeClient pluginNodeClient = new PluginNodeClient(Settings.EMPTY, null, testPlugin); - // pluginNodeClient should have previously been set in service.initializePlugins - IllegalStateException e = expectThrows(IllegalStateException.class, () -> testPlugin.setPluginNodeClient(pluginNodeClient)); - assertThat(e.getMessage(), containsString("pluginNodeClient can only be set once")); + PluginSubject testPluginSubject = new PluginSubject(testPlugin.getClass(), mock(ThreadPool.class)); + // pluginSubject should have previously been set in service.initializePlugins + IllegalStateException e = expectThrows(IllegalStateException.class, () -> testPlugin.setPluginSubject(testPluginSubject)); + assertThat(e.getMessage(), containsString("pluginSubject can only be set once")); } public void testExtensiblePlugin() { From f7f245da369f1085a75490eaf9d4236e6b61bfc9 Mon Sep 17 00:00:00 2001 From: Craig Perkins Date: Tue, 13 Aug 2024 14:57:01 -0400 Subject: [PATCH 34/65] Do nothing when runAs is called for ShiroSubject and NoopSubject Signed-off-by: Craig Perkins --- .../main/java/org/opensearch/identity/shiro/ShiroSubject.java | 2 +- .../src/main/java/org/opensearch/identity/noop/NoopSubject.java | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/plugins/identity-shiro/src/main/java/org/opensearch/identity/shiro/ShiroSubject.java b/plugins/identity-shiro/src/main/java/org/opensearch/identity/shiro/ShiroSubject.java index 76ee2808fdfd0..9968dd010f858 100644 --- a/plugins/identity-shiro/src/main/java/org/opensearch/identity/shiro/ShiroSubject.java +++ b/plugins/identity-shiro/src/main/java/org/opensearch/identity/shiro/ShiroSubject.java @@ -91,6 +91,6 @@ public void authenticate(AuthToken authenticationToken) { @Override public Session runAs() { - return null; + return () -> {}; } } diff --git a/server/src/main/java/org/opensearch/identity/noop/NoopSubject.java b/server/src/main/java/org/opensearch/identity/noop/NoopSubject.java index 3f48ad1b473d1..428cff31a41ed 100644 --- a/server/src/main/java/org/opensearch/identity/noop/NoopSubject.java +++ b/server/src/main/java/org/opensearch/identity/noop/NoopSubject.java @@ -57,6 +57,6 @@ public void authenticate(AuthToken AuthToken) { @Override public Session runAs() { - return null; + return () -> {}; } } From 6dd41532e593b86fa790dabdd858ca525b74b605 Mon Sep 17 00:00:00 2001 From: Craig Perkins Date: Tue, 13 Aug 2024 15:00:56 -0400 Subject: [PATCH 35/65] Remove extraneous changes Signed-off-by: Craig Perkins --- server/src/main/java/org/opensearch/client/node/NodeClient.java | 2 +- .../org/opensearch/common/util/concurrent/ThreadContext.java | 1 - 2 files changed, 1 insertion(+), 2 deletions(-) diff --git a/server/src/main/java/org/opensearch/client/node/NodeClient.java b/server/src/main/java/org/opensearch/client/node/NodeClient.java index e7f50e77cb8bb..5780e4c1e648a 100644 --- a/server/src/main/java/org/opensearch/client/node/NodeClient.java +++ b/server/src/main/java/org/opensearch/client/node/NodeClient.java @@ -136,7 +136,7 @@ public String getLocalNodeId() { * Get the {@link TransportAction} for an {@link ActionType}, throwing exceptions if the action isn't available. */ @SuppressWarnings("unchecked") - protected TransportAction transportAction( + private TransportAction transportAction( ActionType action ) { if (actionRegistry == null) { diff --git a/server/src/main/java/org/opensearch/common/util/concurrent/ThreadContext.java b/server/src/main/java/org/opensearch/common/util/concurrent/ThreadContext.java index 95d20d49a74ca..070e18481f2a3 100644 --- a/server/src/main/java/org/opensearch/common/util/concurrent/ThreadContext.java +++ b/server/src/main/java/org/opensearch/common/util/concurrent/ThreadContext.java @@ -160,7 +160,6 @@ public StoredContext stashContext() { */ ThreadContextStruct threadContextStruct = DEFAULT_CONTEXT.putPersistent(context.persistentHeaders); - threadContextStruct.setSystemContext(propagators); if (context.requestHeaders.containsKey(Task.X_OPAQUE_ID)) { threadContextStruct = threadContextStruct.putHeaders( From 38fe2e174d1264015c880c4d360e8f4d26fab13e Mon Sep 17 00:00:00 2001 From: Craig Perkins Date: Wed, 14 Aug 2024 10:08:28 -0400 Subject: [PATCH 36/65] Test all methods in PluginSubject Signed-off-by: Craig Perkins --- .../opensearch/plugins/PluginsServiceTests.java | 15 +++++++++++++-- 1 file changed, 13 insertions(+), 2 deletions(-) diff --git a/server/src/test/java/org/opensearch/plugins/PluginsServiceTests.java b/server/src/test/java/org/opensearch/plugins/PluginsServiceTests.java index 1a5e675a73239..d5d9c6e9786aa 100644 --- a/server/src/test/java/org/opensearch/plugins/PluginsServiceTests.java +++ b/server/src/test/java/org/opensearch/plugins/PluginsServiceTests.java @@ -44,11 +44,13 @@ import org.opensearch.common.settings.Settings; import org.opensearch.env.Environment; import org.opensearch.env.TestEnvironment; +import org.opensearch.identity.Subject; import org.opensearch.index.IndexModule; import org.opensearch.semver.SemverRange; import org.opensearch.test.MockLogAppender; import org.opensearch.test.OpenSearchTestCase; import org.opensearch.test.VersionUtils; +import org.opensearch.threadpool.TestThreadPool; import org.opensearch.threadpool.ThreadPool; import org.hamcrest.Matchers; @@ -71,8 +73,10 @@ import java.util.zip.ZipInputStream; import java.util.zip.ZipOutputStream; +import static org.opensearch.plugins.PluginSubject.PLUGIN_EXECUTION_CONTEXT; import static org.hamcrest.Matchers.containsInAnyOrder; import static org.hamcrest.Matchers.containsString; +import static org.hamcrest.Matchers.equalTo; import static org.hamcrest.Matchers.hasSize; import static org.hamcrest.Matchers.hasToString; import static org.hamcrest.Matchers.instanceOf; @@ -939,16 +943,23 @@ public void testSetPluginSubject() { } public void testInitializePlugins() { + ThreadPool threadPool = new TestThreadPool(getTestName()); Settings settings = Settings.builder().put(Environment.PATH_HOME_SETTING.getKey(), createTempDir()).build(); PluginsService service = newPluginsService(settings, TestPlugin.class); - service.initializePlugins(mock(ThreadPool.class)); + service.initializePlugins(threadPool); Plugin testPlugin = service.filterPlugins(Plugin.class).get(0); - PluginSubject testPluginSubject = new PluginSubject(testPlugin.getClass(), mock(ThreadPool.class)); + PluginSubject testPluginSubject = new PluginSubject(testPlugin.getClass(), threadPool); + assertThat(testPluginSubject.getPrincipal().getName(), equalTo(TestPlugin.class.getCanonicalName())); + try (Subject.Session session = testPluginSubject.runAs()) { + assertThat(TestPlugin.class.getCanonicalName(), equalTo(threadPool.getThreadContext().getHeader(PLUGIN_EXECUTION_CONTEXT))); + } + assertNull(threadPool.getThreadContext().getHeader(PLUGIN_EXECUTION_CONTEXT)); // pluginSubject should have previously been set in service.initializePlugins IllegalStateException e = expectThrows(IllegalStateException.class, () -> testPlugin.setPluginSubject(testPluginSubject)); assertThat(e.getMessage(), containsString("pluginSubject can only be set once")); + terminate(threadPool); } public void testExtensiblePlugin() { From 17b4444c77560d7fd30d3614636d1e4fb22335d5 Mon Sep 17 00:00:00 2001 From: Craig Perkins Date: Thu, 15 Aug 2024 11:37:38 -0400 Subject: [PATCH 37/65] Pass a Callable to runAs Signed-off-by: Craig Perkins --- .../identity/shiro/ShiroSubject.java | 8 +--- ...estGetExecutionContextTransportAction.java | 14 ++++-- .../opensearch/identity/AbstractSubject.java | 45 +++++++++++++++++++ .../java/org/opensearch/identity/Subject.java | 21 ++------- .../opensearch/identity/noop/NoopSubject.java | 12 ++--- .../org/opensearch/plugins/PluginSubject.java | 17 ++----- .../plugins/PluginsServiceTests.java | 8 ++-- 7 files changed, 73 insertions(+), 52 deletions(-) create mode 100644 server/src/main/java/org/opensearch/identity/AbstractSubject.java diff --git a/plugins/identity-shiro/src/main/java/org/opensearch/identity/shiro/ShiroSubject.java b/plugins/identity-shiro/src/main/java/org/opensearch/identity/shiro/ShiroSubject.java index 9968dd010f858..10d1d7990a7e3 100644 --- a/plugins/identity-shiro/src/main/java/org/opensearch/identity/shiro/ShiroSubject.java +++ b/plugins/identity-shiro/src/main/java/org/opensearch/identity/shiro/ShiroSubject.java @@ -8,6 +8,7 @@ package org.opensearch.identity.shiro; +import org.opensearch.identity.AbstractSubject; import org.opensearch.identity.Subject; import org.opensearch.identity.tokens.AuthToken; @@ -19,7 +20,7 @@ * * @opensearch.experimental */ -public class ShiroSubject implements Subject { +public class ShiroSubject extends AbstractSubject { private final ShiroTokenManager authTokenHandler; private final org.apache.shiro.subject.Subject shiroSubject; @@ -88,9 +89,4 @@ public void authenticate(AuthToken authenticationToken) { .orElseThrow(() -> new UnsupportedAuthenticationToken()); shiroSubject.login(authToken); } - - @Override - public Session runAs() { - return () -> {}; - } } diff --git a/qa/smoke-test-http/src/test/java/org/opensearch/http/executioncontextplugin/TestGetExecutionContextTransportAction.java b/qa/smoke-test-http/src/test/java/org/opensearch/http/executioncontextplugin/TestGetExecutionContextTransportAction.java index 5f4986aa65e2d..b8037e9ec3848 100644 --- a/qa/smoke-test-http/src/test/java/org/opensearch/http/executioncontextplugin/TestGetExecutionContextTransportAction.java +++ b/qa/smoke-test-http/src/test/java/org/opensearch/http/executioncontextplugin/TestGetExecutionContextTransportAction.java @@ -18,6 +18,8 @@ import org.opensearch.tasks.Task; import org.opensearch.transport.TransportService; +import static org.opensearch.identity.AbstractSubject.SUBJECT_HEADER; + /** * Transport action for GetExecutionContext. * @@ -36,10 +38,14 @@ public TestGetExecutionContextTransportAction(TransportService transportService, @Override protected void doExecute(Task task, TestGetExecutionContextRequest request, ActionListener listener) { - String pluginClassName; - try (Subject.Session session = pluginSubject.runAs()) { - pluginClassName = transportService.getThreadPool().getThreadContext().getHeader(PluginSubject.PLUGIN_EXECUTION_CONTEXT); + try { + pluginSubject.runAs(() -> { + String pluginClassName = transportService.getThreadPool().getThreadContext().getHeader(SUBJECT_HEADER); + listener.onResponse(new TestGetExecutionContextResponse(pluginClassName)); + return null; + }); + } catch (Exception e) { + throw new RuntimeException(e); } - listener.onResponse(new TestGetExecutionContextResponse(pluginClassName)); } } diff --git a/server/src/main/java/org/opensearch/identity/AbstractSubject.java b/server/src/main/java/org/opensearch/identity/AbstractSubject.java new file mode 100644 index 0000000000000..89cc31136dc2f --- /dev/null +++ b/server/src/main/java/org/opensearch/identity/AbstractSubject.java @@ -0,0 +1,45 @@ +/* + * SPDX-License-Identifier: Apache-2.0 + * + * The OpenSearch Contributors require contributions made to + * this file be licensed under the Apache-2.0 license or a + * compatible open source license. + */ + +package org.opensearch.identity; + +import org.opensearch.common.util.concurrent.ThreadContext; +import org.opensearch.threadpool.ThreadPool; + +import java.util.concurrent.Callable; + +/** + * An AbstractSubject provides a default implementation for runAs which populates the _subject header of the + * ThreadContext with the subject's principal name + */ +public abstract class AbstractSubject implements Subject { + + public static final String SUBJECT_HEADER = "_subject"; + + private final ThreadPool threadPool; + + public AbstractSubject(ThreadPool threadPool) { + this.threadPool = threadPool; + } + + public AbstractSubject() { + this.threadPool = null; + } + + @Override + public void runAs(Callable callable) throws Exception { + if (threadPool != null) { + try (ThreadContext.StoredContext ctx = threadPool.getThreadContext().stashContext()) { + threadPool.getThreadContext().putHeader(SUBJECT_HEADER, getPrincipal().getName()); + callable.call(); + } + } else { + callable.call(); + } + } +} diff --git a/server/src/main/java/org/opensearch/identity/Subject.java b/server/src/main/java/org/opensearch/identity/Subject.java index fd74d5d93496c..0beac722cbd64 100644 --- a/server/src/main/java/org/opensearch/identity/Subject.java +++ b/server/src/main/java/org/opensearch/identity/Subject.java @@ -5,10 +5,10 @@ package org.opensearch.identity; -import org.opensearch.common.annotation.PublicApi; import org.opensearch.identity.tokens.AuthToken; import java.security.Principal; +import java.util.concurrent.Callable; /** * An individual, process, or device that causes information to flow among objects or change to the system state. @@ -32,22 +32,7 @@ public interface Subject { void authenticate(final AuthToken token); /** - * runAs allows the caller to create a session as this subject - * - * @return A session to run transport actions in the context of this subject + * runAs allows the caller to run a callable function as this subject */ - Session runAs(); - - /** - * This construct represents a session for this subject. A session is a short-lived block - * where transport actions are executed as this subject - * - * @opensearch.api - */ - @FunctionalInterface - @PublicApi(since = "2.17.0") - interface Session extends AutoCloseable { - @Override - void close(); - } + void runAs(Callable callable) throws Exception; } diff --git a/server/src/main/java/org/opensearch/identity/noop/NoopSubject.java b/server/src/main/java/org/opensearch/identity/noop/NoopSubject.java index 428cff31a41ed..2cf63c6b230f8 100644 --- a/server/src/main/java/org/opensearch/identity/noop/NoopSubject.java +++ b/server/src/main/java/org/opensearch/identity/noop/NoopSubject.java @@ -8,6 +8,7 @@ package org.opensearch.identity.noop; +import org.opensearch.identity.AbstractSubject; import org.opensearch.identity.NamedPrincipal; import org.opensearch.identity.Subject; import org.opensearch.identity.tokens.AuthToken; @@ -22,7 +23,11 @@ * * @opensearch.internal */ -public class NoopSubject implements Subject { +public class NoopSubject extends AbstractSubject { + + public NoopSubject() { + super(); + } @Override public Principal getPrincipal() { @@ -54,9 +59,4 @@ public String toString() { public void authenticate(AuthToken AuthToken) { // Do nothing as noop subject is always logged in } - - @Override - public Session runAs() { - return () -> {}; - } } diff --git a/server/src/main/java/org/opensearch/plugins/PluginSubject.java b/server/src/main/java/org/opensearch/plugins/PluginSubject.java index a4940a25afc2e..c3b3058a30378 100644 --- a/server/src/main/java/org/opensearch/plugins/PluginSubject.java +++ b/server/src/main/java/org/opensearch/plugins/PluginSubject.java @@ -8,9 +8,8 @@ package org.opensearch.plugins; -import org.opensearch.common.util.concurrent.ThreadContext; +import org.opensearch.identity.AbstractSubject; import org.opensearch.identity.NamedPrincipal; -import org.opensearch.identity.Subject; import org.opensearch.identity.tokens.AuthToken; import org.opensearch.threadpool.ThreadPool; @@ -22,15 +21,12 @@ * * @opensearch.api */ -public class PluginSubject implements Subject { - public static final String PLUGIN_EXECUTION_CONTEXT = "_plugin_execution_context"; - +public class PluginSubject extends AbstractSubject { private final NamedPrincipal pluginCanonicalName; - private final ThreadPool threadPool; PluginSubject(Class pluginClass, ThreadPool threadPool) { + super(threadPool); this.pluginCanonicalName = new NamedPrincipal(pluginClass.getCanonicalName()); - this.threadPool = threadPool; } @Override @@ -42,11 +38,4 @@ public Principal getPrincipal() { public void authenticate(AuthToken token) { // no-op } - - @Override - public Session runAs() { - ThreadContext.StoredContext ctx = threadPool.getThreadContext().stashContext(); - threadPool.getThreadContext().putHeader(PLUGIN_EXECUTION_CONTEXT, pluginCanonicalName.getName()); - return ctx::restore; - } } diff --git a/server/src/test/java/org/opensearch/plugins/PluginsServiceTests.java b/server/src/test/java/org/opensearch/plugins/PluginsServiceTests.java index d5d9c6e9786aa..db5da89efa98f 100644 --- a/server/src/test/java/org/opensearch/plugins/PluginsServiceTests.java +++ b/server/src/test/java/org/opensearch/plugins/PluginsServiceTests.java @@ -44,7 +44,6 @@ import org.opensearch.common.settings.Settings; import org.opensearch.env.Environment; import org.opensearch.env.TestEnvironment; -import org.opensearch.identity.Subject; import org.opensearch.index.IndexModule; import org.opensearch.semver.SemverRange; import org.opensearch.test.MockLogAppender; @@ -942,7 +941,7 @@ public void testSetPluginSubject() { assertThat(e.getMessage(), containsString("pluginSubject can only be set once")); } - public void testInitializePlugins() { + public void testInitializePlugins() throws Exception { ThreadPool threadPool = new TestThreadPool(getTestName()); Settings settings = Settings.builder().put(Environment.PATH_HOME_SETTING.getKey(), createTempDir()).build(); PluginsService service = newPluginsService(settings, TestPlugin.class); @@ -952,9 +951,10 @@ public void testInitializePlugins() { Plugin testPlugin = service.filterPlugins(Plugin.class).get(0); PluginSubject testPluginSubject = new PluginSubject(testPlugin.getClass(), threadPool); assertThat(testPluginSubject.getPrincipal().getName(), equalTo(TestPlugin.class.getCanonicalName())); - try (Subject.Session session = testPluginSubject.runAs()) { + testPluginSubject.runAs(() -> { assertThat(TestPlugin.class.getCanonicalName(), equalTo(threadPool.getThreadContext().getHeader(PLUGIN_EXECUTION_CONTEXT))); - } + return null; + }); assertNull(threadPool.getThreadContext().getHeader(PLUGIN_EXECUTION_CONTEXT)); // pluginSubject should have previously been set in service.initializePlugins IllegalStateException e = expectThrows(IllegalStateException.class, () -> testPlugin.setPluginSubject(testPluginSubject)); From 247fd59e5b5cb9741ab676664833d7ed7be88726 Mon Sep 17 00:00:00 2001 From: Craig Perkins Date: Thu, 15 Aug 2024 12:14:22 -0400 Subject: [PATCH 38/65] Update import Signed-off-by: Craig Perkins --- .../java/org/opensearch/plugins/PluginsServiceTests.java | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/server/src/test/java/org/opensearch/plugins/PluginsServiceTests.java b/server/src/test/java/org/opensearch/plugins/PluginsServiceTests.java index db5da89efa98f..f42a1144cf9de 100644 --- a/server/src/test/java/org/opensearch/plugins/PluginsServiceTests.java +++ b/server/src/test/java/org/opensearch/plugins/PluginsServiceTests.java @@ -72,7 +72,7 @@ import java.util.zip.ZipInputStream; import java.util.zip.ZipOutputStream; -import static org.opensearch.plugins.PluginSubject.PLUGIN_EXECUTION_CONTEXT; +import static org.opensearch.identity.AbstractSubject.SUBJECT_HEADER; import static org.hamcrest.Matchers.containsInAnyOrder; import static org.hamcrest.Matchers.containsString; import static org.hamcrest.Matchers.equalTo; @@ -952,10 +952,10 @@ public void testInitializePlugins() throws Exception { PluginSubject testPluginSubject = new PluginSubject(testPlugin.getClass(), threadPool); assertThat(testPluginSubject.getPrincipal().getName(), equalTo(TestPlugin.class.getCanonicalName())); testPluginSubject.runAs(() -> { - assertThat(TestPlugin.class.getCanonicalName(), equalTo(threadPool.getThreadContext().getHeader(PLUGIN_EXECUTION_CONTEXT))); + assertThat(TestPlugin.class.getCanonicalName(), equalTo(threadPool.getThreadContext().getHeader(SUBJECT_HEADER))); return null; }); - assertNull(threadPool.getThreadContext().getHeader(PLUGIN_EXECUTION_CONTEXT)); + assertNull(threadPool.getThreadContext().getHeader(SUBJECT_HEADER)); // pluginSubject should have previously been set in service.initializePlugins IllegalStateException e = expectThrows(IllegalStateException.class, () -> testPlugin.setPluginSubject(testPluginSubject)); assertThat(e.getMessage(), containsString("pluginSubject can only be set once")); From 16f4251f709b4f5a8ffc5ff385fb88c2f18de410 Mon Sep 17 00:00:00 2001 From: Craig Perkins Date: Fri, 16 Aug 2024 10:34:28 -0400 Subject: [PATCH 39/65] Simplify PR, make NoopPluginSubject and introduce IdentityAwarePlugin Signed-off-by: Craig Perkins --- .../identity/shiro/ShiroIdentityPlugin.java | 15 ++++ .../http/ExecutionContextPluginGetIT.java | 51 ------------- .../TestExecutionContextPlugin.java | 72 ------------------- .../TestGetExecutionContextAction.java | 29 -------- .../TestGetExecutionContextRequest.java | 46 ------------ .../TestGetExecutionContextResponse.java | 55 -------------- .../TestGetExecutionContextRestAction.java | 47 ------------ ...estGetExecutionContextTransportAction.java | 51 ------------- .../opensearch/identity/AbstractSubject.java | 28 +------- .../opensearch/identity/IdentityService.java | 6 ++ .../identity/noop/NoopIdentityPlugin.java | 14 ++++ .../identity/noop/NoopPluginSubject.java | 44 ++++++++++++ .../main/java/org/opensearch/node/Node.java | 4 +- .../plugins/IdentityAwarePlugin.java | 31 ++++++++ .../opensearch/plugins/IdentityPlugin.java | 9 ++- .../java/org/opensearch/plugins/Plugin.java | 14 ---- .../org/opensearch/plugins/PluginSubject.java | 41 ----------- .../opensearch/plugins/PluginsService.java | 9 --- .../identity/PluginSubjectTests.java | 56 +++++++++++++++ .../plugins/PluginsServiceTests.java | 34 --------- 20 files changed, 179 insertions(+), 477 deletions(-) delete mode 100644 qa/smoke-test-http/src/test/java/org/opensearch/http/ExecutionContextPluginGetIT.java delete mode 100644 qa/smoke-test-http/src/test/java/org/opensearch/http/executioncontextplugin/TestExecutionContextPlugin.java delete mode 100644 qa/smoke-test-http/src/test/java/org/opensearch/http/executioncontextplugin/TestGetExecutionContextAction.java delete mode 100644 qa/smoke-test-http/src/test/java/org/opensearch/http/executioncontextplugin/TestGetExecutionContextRequest.java delete mode 100644 qa/smoke-test-http/src/test/java/org/opensearch/http/executioncontextplugin/TestGetExecutionContextResponse.java delete mode 100644 qa/smoke-test-http/src/test/java/org/opensearch/http/executioncontextplugin/TestGetExecutionContextRestAction.java delete mode 100644 qa/smoke-test-http/src/test/java/org/opensearch/http/executioncontextplugin/TestGetExecutionContextTransportAction.java create mode 100644 server/src/main/java/org/opensearch/identity/noop/NoopPluginSubject.java create mode 100644 server/src/main/java/org/opensearch/plugins/IdentityAwarePlugin.java delete mode 100644 server/src/main/java/org/opensearch/plugins/PluginSubject.java create mode 100644 server/src/test/java/org/opensearch/identity/PluginSubjectTests.java diff --git a/plugins/identity-shiro/src/main/java/org/opensearch/identity/shiro/ShiroIdentityPlugin.java b/plugins/identity-shiro/src/main/java/org/opensearch/identity/shiro/ShiroIdentityPlugin.java index 77cab13880c27..06172028578ae 100644 --- a/plugins/identity-shiro/src/main/java/org/opensearch/identity/shiro/ShiroIdentityPlugin.java +++ b/plugins/identity-shiro/src/main/java/org/opensearch/identity/shiro/ShiroIdentityPlugin.java @@ -14,9 +14,14 @@ import org.apache.shiro.mgt.SecurityManager; import org.opensearch.common.settings.Settings; import org.opensearch.identity.Subject; +import org.opensearch.identity.noop.NoopPluginSubject; import org.opensearch.identity.tokens.TokenManager; +import org.opensearch.plugins.IdentityAwarePlugin; import org.opensearch.plugins.IdentityPlugin; import org.opensearch.plugins.Plugin; +import org.opensearch.threadpool.ThreadPool; + +import java.util.List; /** * Identity implementation with Shiro @@ -61,4 +66,14 @@ public Subject getSubject() { public TokenManager getTokenManager() { return this.authTokenHandler; } + + @Override + public void initializeIdentityAwarePlugins(List identityAwarePlugins, ThreadPool threadPool) { + if (identityAwarePlugins != null) { + for (IdentityAwarePlugin plugin : identityAwarePlugins) { + Subject subject = new NoopPluginSubject(threadPool); + plugin.initializePlugin(subject); + } + } + } } diff --git a/qa/smoke-test-http/src/test/java/org/opensearch/http/ExecutionContextPluginGetIT.java b/qa/smoke-test-http/src/test/java/org/opensearch/http/ExecutionContextPluginGetIT.java deleted file mode 100644 index ea627196f1052..0000000000000 --- a/qa/smoke-test-http/src/test/java/org/opensearch/http/ExecutionContextPluginGetIT.java +++ /dev/null @@ -1,51 +0,0 @@ -/* - * SPDX-License-Identifier: Apache-2.0 - * - * The OpenSearch Contributors require contributions made to - * this file be licensed under the Apache-2.0 license or a - * compatible open source license. - */ - -package org.opensearch.http; - -import org.opensearch.client.Request; -import org.opensearch.client.Response; -import org.opensearch.http.executioncontextplugin.TestExecutionContextPlugin; -import org.opensearch.plugins.Plugin; -import org.opensearch.test.OpenSearchIntegTestCase.ClusterScope; -import org.opensearch.test.OpenSearchIntegTestCase.Scope; - -import java.io.IOException; -import java.nio.charset.StandardCharsets; -import java.util.ArrayList; -import java.util.Collection; - -import static org.hamcrest.Matchers.containsString; -import static org.hamcrest.Matchers.equalTo; - -/** - * Test to ensure that plugin execution context is set when plugin runs transport action with PluginSubject - */ -@ClusterScope(scope = Scope.SUITE, supportsDedicatedMasters = false, numDataNodes = 1) -public class ExecutionContextPluginGetIT extends HttpSmokeTestCase { - - @Override - protected boolean addMockHttpTransport() { - return false; // enable http - } - - @Override - protected Collection> nodePlugins() { - ArrayList> plugins = new ArrayList<>(super.nodePlugins()); - plugins.add(TestExecutionContextPlugin.class); - return plugins; - } - - public void testGetExecutionContext() throws IOException { - ensureGreen(); - Response response = getRestClient().performRequest(new Request("GET", "/_get_execution_context")); - String responseBody = new String(response.getEntity().getContent().readAllBytes(), StandardCharsets.UTF_8); - assertThat(response.getStatusLine().getStatusCode(), equalTo(200)); - assertThat(responseBody, containsString(TestExecutionContextPlugin.class.getName())); - } -} diff --git a/qa/smoke-test-http/src/test/java/org/opensearch/http/executioncontextplugin/TestExecutionContextPlugin.java b/qa/smoke-test-http/src/test/java/org/opensearch/http/executioncontextplugin/TestExecutionContextPlugin.java deleted file mode 100644 index bfd8dab1aca5f..0000000000000 --- a/qa/smoke-test-http/src/test/java/org/opensearch/http/executioncontextplugin/TestExecutionContextPlugin.java +++ /dev/null @@ -1,72 +0,0 @@ -/* - * SPDX-License-Identifier: Apache-2.0 - * - * The OpenSearch Contributors require contributions made to - * this file be licensed under the Apache-2.0 license or a - * compatible open source license. - */ - -package org.opensearch.http.executioncontextplugin; - -import org.opensearch.action.ActionRequest; -import org.opensearch.client.Client; -import org.opensearch.cluster.metadata.IndexNameExpressionResolver; -import org.opensearch.cluster.node.DiscoveryNodes; -import org.opensearch.cluster.service.ClusterService; -import org.opensearch.common.settings.ClusterSettings; -import org.opensearch.common.settings.IndexScopedSettings; -import org.opensearch.common.settings.Settings; -import org.opensearch.common.settings.SettingsFilter; -import org.opensearch.core.action.ActionResponse; -import org.opensearch.core.common.io.stream.NamedWriteableRegistry; -import org.opensearch.core.xcontent.NamedXContentRegistry; -import org.opensearch.env.Environment; -import org.opensearch.env.NodeEnvironment; -import org.opensearch.plugins.ActionPlugin; -import org.opensearch.plugins.Plugin; -import org.opensearch.repositories.RepositoriesService; -import org.opensearch.rest.RestController; -import org.opensearch.rest.RestHandler; -import org.opensearch.script.ScriptService; -import org.opensearch.threadpool.ThreadPool; -import org.opensearch.watcher.ResourceWatcherService; - -import java.util.Collection; -import java.util.Collections; -import java.util.List; -import java.util.function.Supplier; - -public class TestExecutionContextPlugin extends Plugin implements ActionPlugin { - private Client client; - private ThreadPool threadPool; - - @Override - public Collection createComponents( - Client client, - ClusterService clusterService, - ThreadPool threadPool, - ResourceWatcherService resourceWatcherService, - ScriptService scriptService, - NamedXContentRegistry xContentRegistry, - Environment environment, - NodeEnvironment nodeEnvironment, - NamedWriteableRegistry namedWriteableRegistry, - IndexNameExpressionResolver expressionResolver, - Supplier repositoriesServiceSupplier) { - this.client = client; - this.threadPool = threadPool; - return Collections.singletonList(pluginSubject); - } - - @Override - public List getRestHandlers(Settings settings, RestController restController, ClusterSettings clusterSettings, - IndexScopedSettings indexScopedSettings, SettingsFilter settingsFilter, IndexNameExpressionResolver indexNameExpressionResolver, - Supplier nodesInCluster) { - return List.of(new TestGetExecutionContextRestAction(client)); - } - - @Override - public List> getActions() { - return List.of(new ActionHandler<>(TestGetExecutionContextAction.INSTANCE, TestGetExecutionContextTransportAction.class)); - } -} diff --git a/qa/smoke-test-http/src/test/java/org/opensearch/http/executioncontextplugin/TestGetExecutionContextAction.java b/qa/smoke-test-http/src/test/java/org/opensearch/http/executioncontextplugin/TestGetExecutionContextAction.java deleted file mode 100644 index 83248bc672114..0000000000000 --- a/qa/smoke-test-http/src/test/java/org/opensearch/http/executioncontextplugin/TestGetExecutionContextAction.java +++ /dev/null @@ -1,29 +0,0 @@ -/* - * SPDX-License-Identifier: Apache-2.0 - * - * The OpenSearch Contributors require contributions made to - * this file be licensed under the Apache-2.0 license or a - * compatible open source license. - */ - -package org.opensearch.http.executioncontextplugin; - -import org.opensearch.action.ActionType; - -/** - * Test action to get the name of the plugin executing transport actions - */ -public class TestGetExecutionContextAction extends ActionType { - /** - * Get execution context action instance - */ - public static final TestGetExecutionContextAction INSTANCE = new TestGetExecutionContextAction(); - /** - * Get execution context action name - */ - public static final String NAME = "cluster:admin/executioncontext"; - - private TestGetExecutionContextAction() { - super(NAME, TestGetExecutionContextResponse::new); - } -} diff --git a/qa/smoke-test-http/src/test/java/org/opensearch/http/executioncontextplugin/TestGetExecutionContextRequest.java b/qa/smoke-test-http/src/test/java/org/opensearch/http/executioncontextplugin/TestGetExecutionContextRequest.java deleted file mode 100644 index da6deb384f38f..0000000000000 --- a/qa/smoke-test-http/src/test/java/org/opensearch/http/executioncontextplugin/TestGetExecutionContextRequest.java +++ /dev/null @@ -1,46 +0,0 @@ -/* - * SPDX-License-Identifier: Apache-2.0 - * - * The OpenSearch Contributors require contributions made to - * this file be licensed under the Apache-2.0 license or a - * compatible open source license. - */ - -package org.opensearch.http.executioncontextplugin; - -import org.opensearch.action.ActionRequest; -import org.opensearch.action.ActionRequestValidationException; -import org.opensearch.core.common.io.stream.StreamInput; -import org.opensearch.core.common.io.stream.StreamOutput; - -import java.io.IOException; - -/** - * Request object for GetExecutionContext transport action - */ -public class TestGetExecutionContextRequest extends ActionRequest { - - /** - * Default constructor - */ - public TestGetExecutionContextRequest() {} - - /** - * Constructor with stream input - * @param in the stream input - * @throws IOException IOException - */ - public TestGetExecutionContextRequest(final StreamInput in) throws IOException { - super(in); - } - - @Override - public void writeTo(final StreamOutput out) throws IOException { - super.writeTo(out); - } - - @Override - public ActionRequestValidationException validate() { - return null; - } -} diff --git a/qa/smoke-test-http/src/test/java/org/opensearch/http/executioncontextplugin/TestGetExecutionContextResponse.java b/qa/smoke-test-http/src/test/java/org/opensearch/http/executioncontextplugin/TestGetExecutionContextResponse.java deleted file mode 100644 index 335c29b673ee4..0000000000000 --- a/qa/smoke-test-http/src/test/java/org/opensearch/http/executioncontextplugin/TestGetExecutionContextResponse.java +++ /dev/null @@ -1,55 +0,0 @@ -/* - * SPDX-License-Identifier: Apache-2.0 - * - * The OpenSearch Contributors require contributions made to - * this file be licensed under the Apache-2.0 license or a - * compatible open source license. - */ - -package org.opensearch.http.executioncontextplugin; - -import org.opensearch.core.action.ActionResponse; -import org.opensearch.core.common.io.stream.StreamInput; -import org.opensearch.core.common.io.stream.StreamOutput; -import org.opensearch.core.xcontent.ToXContentObject; -import org.opensearch.core.xcontent.XContentBuilder; - -import java.io.IOException; - -/** - * Response object containing the name of the plugin executing the transport action - */ -public class TestGetExecutionContextResponse extends ActionResponse implements ToXContentObject { - private final String pluginClassName; - - /** - * Default constructor - * - * @param pluginClassName the canonical class name of the plugin executing the transport action - */ - public TestGetExecutionContextResponse(String pluginClassName) { - this.pluginClassName = pluginClassName; - } - - @Override - public void writeTo(StreamOutput out) throws IOException { - out.writeString(pluginClassName); - } - - /** - * Constructor with StreamInput - * - * @param in the stream input - */ - public TestGetExecutionContextResponse(final StreamInput in) throws IOException { - pluginClassName = in.readString(); - } - - @Override - public XContentBuilder toXContent(XContentBuilder builder, Params params) throws IOException { - builder.startObject(); - builder.field("plugin_execution_context", pluginClassName); - builder.endObject(); - return builder; - } -} diff --git a/qa/smoke-test-http/src/test/java/org/opensearch/http/executioncontextplugin/TestGetExecutionContextRestAction.java b/qa/smoke-test-http/src/test/java/org/opensearch/http/executioncontextplugin/TestGetExecutionContextRestAction.java deleted file mode 100644 index 03d2940f68602..0000000000000 --- a/qa/smoke-test-http/src/test/java/org/opensearch/http/executioncontextplugin/TestGetExecutionContextRestAction.java +++ /dev/null @@ -1,47 +0,0 @@ -/* - * SPDX-License-Identifier: Apache-2.0 - * - * The OpenSearch Contributors require contributions made to - * this file be licensed under the Apache-2.0 license or a - * compatible open source license. - */ - -package org.opensearch.http.executioncontextplugin; - -import org.opensearch.client.Client; -import org.opensearch.client.node.NodeClient; -import org.opensearch.plugins.PluginSubject; -import org.opensearch.rest.BaseRestHandler; -import org.opensearch.rest.RestRequest; -import org.opensearch.rest.action.RestToXContentListener; -import org.opensearch.threadpool.ThreadPool; - -import java.util.List; - -import static java.util.Collections.singletonList; -import static org.opensearch.rest.RestRequest.Method.GET; - -public class TestGetExecutionContextRestAction extends BaseRestHandler { - - private final Client client; - - public TestGetExecutionContextRestAction(Client client) { - this.client = client; - } - - @Override - public List routes() { - return singletonList(new Route(GET, "/_get_execution_context")); - } - - @Override - public String getName() { - return "test_get_execution_context_action"; - } - - @Override - public RestChannelConsumer prepareRequest(RestRequest request, NodeClient client) { - final TestGetExecutionContextRequest getExecutionContextRequest = new TestGetExecutionContextRequest(); - return channel -> client.execute(TestGetExecutionContextAction.INSTANCE, getExecutionContextRequest, new RestToXContentListener<>(channel)); - } -} diff --git a/qa/smoke-test-http/src/test/java/org/opensearch/http/executioncontextplugin/TestGetExecutionContextTransportAction.java b/qa/smoke-test-http/src/test/java/org/opensearch/http/executioncontextplugin/TestGetExecutionContextTransportAction.java deleted file mode 100644 index b8037e9ec3848..0000000000000 --- a/qa/smoke-test-http/src/test/java/org/opensearch/http/executioncontextplugin/TestGetExecutionContextTransportAction.java +++ /dev/null @@ -1,51 +0,0 @@ -/* - * SPDX-License-Identifier: Apache-2.0 - * - * The OpenSearch Contributors require contributions made to - * this file be licensed under the Apache-2.0 license or a - * compatible open source license. - */ - -package org.opensearch.http.executioncontextplugin; - -import org.opensearch.action.support.ActionFilters; -import org.opensearch.action.support.HandledTransportAction; -import org.opensearch.common.inject.Inject; -import org.opensearch.common.util.concurrent.ThreadContext; -import org.opensearch.core.action.ActionListener; -import org.opensearch.identity.Subject; -import org.opensearch.plugins.PluginSubject; -import org.opensearch.tasks.Task; -import org.opensearch.transport.TransportService; - -import static org.opensearch.identity.AbstractSubject.SUBJECT_HEADER; - -/** - * Transport action for GetExecutionContext. - * - * Returns the canonical class name of the plugin that is currently executing the transport action. - */ -public class TestGetExecutionContextTransportAction extends HandledTransportAction { - private final TransportService transportService; - private final PluginSubject pluginSubject; - - @Inject - public TestGetExecutionContextTransportAction(TransportService transportService, ActionFilters actionFilters, PluginSubject pluginSubject) { - super(TestGetExecutionContextAction.NAME, transportService, actionFilters, TestGetExecutionContextRequest::new); - this.transportService = transportService; - this.pluginSubject = pluginSubject; - } - - @Override - protected void doExecute(Task task, TestGetExecutionContextRequest request, ActionListener listener) { - try { - pluginSubject.runAs(() -> { - String pluginClassName = transportService.getThreadPool().getThreadContext().getHeader(SUBJECT_HEADER); - listener.onResponse(new TestGetExecutionContextResponse(pluginClassName)); - return null; - }); - } catch (Exception e) { - throw new RuntimeException(e); - } - } -} diff --git a/server/src/main/java/org/opensearch/identity/AbstractSubject.java b/server/src/main/java/org/opensearch/identity/AbstractSubject.java index 89cc31136dc2f..f841d4cb593b9 100644 --- a/server/src/main/java/org/opensearch/identity/AbstractSubject.java +++ b/server/src/main/java/org/opensearch/identity/AbstractSubject.java @@ -8,38 +8,16 @@ package org.opensearch.identity; -import org.opensearch.common.util.concurrent.ThreadContext; -import org.opensearch.threadpool.ThreadPool; - import java.util.concurrent.Callable; /** - * An AbstractSubject provides a default implementation for runAs which populates the _subject header of the - * ThreadContext with the subject's principal name + * An AbstractSubject provides a default implementation for runAs simply calls the Callable passed to it */ public abstract class AbstractSubject implements Subject { - - public static final String SUBJECT_HEADER = "_subject"; - - private final ThreadPool threadPool; - - public AbstractSubject(ThreadPool threadPool) { - this.threadPool = threadPool; - } - - public AbstractSubject() { - this.threadPool = null; - } + public AbstractSubject() {} @Override public void runAs(Callable callable) throws Exception { - if (threadPool != null) { - try (ThreadContext.StoredContext ctx = threadPool.getThreadContext().stashContext()) { - threadPool.getThreadContext().putHeader(SUBJECT_HEADER, getPrincipal().getName()); - callable.call(); - } - } else { - callable.call(); - } + callable.call(); } } diff --git a/server/src/main/java/org/opensearch/identity/IdentityService.java b/server/src/main/java/org/opensearch/identity/IdentityService.java index 3129c201b9a39..e81a6f970531a 100644 --- a/server/src/main/java/org/opensearch/identity/IdentityService.java +++ b/server/src/main/java/org/opensearch/identity/IdentityService.java @@ -11,7 +11,9 @@ import org.opensearch.common.settings.Settings; import org.opensearch.identity.noop.NoopIdentityPlugin; import org.opensearch.identity.tokens.TokenManager; +import org.opensearch.plugins.IdentityAwarePlugin; import org.opensearch.plugins.IdentityPlugin; +import org.opensearch.threadpool.ThreadPool; import java.util.List; import java.util.stream.Collectors; @@ -57,4 +59,8 @@ public Subject getSubject() { public TokenManager getTokenManager() { return identityPlugin.getTokenManager(); } + + public void initializeIdentityAwarePlugins(final List identityAwarePlugins, ThreadPool threadPool) { + identityPlugin.initializeIdentityAwarePlugins(identityAwarePlugins, threadPool); + } } diff --git a/server/src/main/java/org/opensearch/identity/noop/NoopIdentityPlugin.java b/server/src/main/java/org/opensearch/identity/noop/NoopIdentityPlugin.java index 090b1f1d025e0..1e37b47286cab 100644 --- a/server/src/main/java/org/opensearch/identity/noop/NoopIdentityPlugin.java +++ b/server/src/main/java/org/opensearch/identity/noop/NoopIdentityPlugin.java @@ -10,7 +10,11 @@ import org.opensearch.identity.Subject; import org.opensearch.identity.tokens.TokenManager; +import org.opensearch.plugins.IdentityAwarePlugin; import org.opensearch.plugins.IdentityPlugin; +import org.opensearch.threadpool.ThreadPool; + +import java.util.List; /** * Implementation of identity plugin that does not enforce authentication or authorization @@ -38,4 +42,14 @@ public Subject getSubject() { public TokenManager getTokenManager() { return new NoopTokenManager(); } + + @Override + public void initializeIdentityAwarePlugins(List identityAwarePlugins, ThreadPool threadPool) { + if (identityAwarePlugins != null) { + for (IdentityAwarePlugin plugin : identityAwarePlugins) { + Subject subject = new NoopPluginSubject(threadPool); + plugin.initializePlugin(subject); + } + } + } } diff --git a/server/src/main/java/org/opensearch/identity/noop/NoopPluginSubject.java b/server/src/main/java/org/opensearch/identity/noop/NoopPluginSubject.java new file mode 100644 index 0000000000000..b266bc9620def --- /dev/null +++ b/server/src/main/java/org/opensearch/identity/noop/NoopPluginSubject.java @@ -0,0 +1,44 @@ +/* + * SPDX-License-Identifier: Apache-2.0 + * + * The OpenSearch Contributors require contributions made to + * this file be licensed under the Apache-2.0 license or a + * compatible open source license. + */ + +package org.opensearch.identity.noop; + +import org.opensearch.common.util.concurrent.ThreadContext; +import org.opensearch.identity.AbstractSubject; +import org.opensearch.identity.NamedPrincipal; +import org.opensearch.identity.tokens.AuthToken; +import org.opensearch.threadpool.ThreadPool; + +import java.security.Principal; +import java.util.concurrent.Callable; + +public class NoopPluginSubject extends AbstractSubject { + private ThreadPool threadPool; + + public NoopPluginSubject(ThreadPool threadPool) { + super(); + this.threadPool = threadPool; + } + + @Override + public Principal getPrincipal() { + return NamedPrincipal.UNAUTHENTICATED; + } + + @Override + public void authenticate(AuthToken token) { + // Do nothing as noop subject is always logged in + } + + @Override + public void runAs(Callable callable) throws Exception { + try (ThreadContext.StoredContext ctx = threadPool.getThreadContext().stashContext()) { + callable.call(); + } + } +} diff --git a/server/src/main/java/org/opensearch/node/Node.java b/server/src/main/java/org/opensearch/node/Node.java index 5337fab74d9fa..74cd9e6467b95 100644 --- a/server/src/main/java/org/opensearch/node/Node.java +++ b/server/src/main/java/org/opensearch/node/Node.java @@ -201,6 +201,7 @@ import org.opensearch.plugins.DiscoveryPlugin; import org.opensearch.plugins.EnginePlugin; import org.opensearch.plugins.ExtensionAwarePlugin; +import org.opensearch.plugins.IdentityAwarePlugin; import org.opensearch.plugins.IdentityPlugin; import org.opensearch.plugins.IndexStorePlugin; import org.opensearch.plugins.IngestPlugin; @@ -574,7 +575,6 @@ protected Node( runnableTaskListener = new AtomicReference<>(); final ThreadPool threadPool = new ThreadPool(settings, runnableTaskListener, executorBuilders.toArray(new ExecutorBuilder[0])); - pluginsService.initializePlugins(threadPool); final SetOnce repositoriesServiceReference = new SetOnce<>(); final RemoteStoreNodeService remoteStoreNodeService = new RemoteStoreNodeService(repositoriesServiceReference::get, threadPool); @@ -713,6 +713,8 @@ protected Node( repositoriesServiceReference::get, rerouteServiceReference::get ); + List identityAwarePlugins = pluginsService.filterPlugins(IdentityAwarePlugin.class); + identityService.initializeIdentityAwarePlugins(identityAwarePlugins, threadPool); final Map> systemIndexDescriptorMap = Collections.unmodifiableMap( pluginsService.filterPlugins(SystemIndexPlugin.class) .stream() diff --git a/server/src/main/java/org/opensearch/plugins/IdentityAwarePlugin.java b/server/src/main/java/org/opensearch/plugins/IdentityAwarePlugin.java new file mode 100644 index 0000000000000..274934e8e322b --- /dev/null +++ b/server/src/main/java/org/opensearch/plugins/IdentityAwarePlugin.java @@ -0,0 +1,31 @@ +/* + * SPDX-License-Identifier: Apache-2.0 + * + * The OpenSearch Contributors require contributions made to + * this file be licensed under the Apache-2.0 license or a + * compatible open source license. + */ + +package org.opensearch.plugins; + +import org.opensearch.identity.Subject; + +/** + * Plugin that performs transport actions with a plugin system context. IdentityAwarePlugins are initialized + * with a {@link Subject} that they can utilize to perform transport actions outside the default subject. + * + * When the Security plugin is installed, the default subject is the authenticated user. In particular, + * SystemIndexPlugins utilize the {@link Subject} to perform transport actions that interact with system indices. + * + * @opensearch.api + */ +public interface IdentityAwarePlugin { + + /** + * Passes necessary classes for this plugin to operate as an IdentityAwarePlugin + * + * @param pluginSystemSubject A subject for running transport actions in the plugin system context for system index + * interaction + */ + default void initializePlugin(Subject pluginSystemSubject) {} +} diff --git a/server/src/main/java/org/opensearch/plugins/IdentityPlugin.java b/server/src/main/java/org/opensearch/plugins/IdentityPlugin.java index 410535504f0dd..c7d4e1c8c0c99 100644 --- a/server/src/main/java/org/opensearch/plugins/IdentityPlugin.java +++ b/server/src/main/java/org/opensearch/plugins/IdentityPlugin.java @@ -10,6 +10,9 @@ import org.opensearch.identity.Subject; import org.opensearch.identity.tokens.TokenManager; +import org.opensearch.threadpool.ThreadPool; + +import java.util.List; /** * Plugin that provides identity and access control for OpenSearch @@ -22,11 +25,13 @@ public interface IdentityPlugin { * Get the current subject. * @return Should never return null * */ - public Subject getSubject(); + Subject getSubject(); /** * Get the Identity Plugin's token manager implementation * @return Should never return null. */ - public TokenManager getTokenManager(); + TokenManager getTokenManager(); + + void initializeIdentityAwarePlugins(final List systemIndexPlugins, ThreadPool threadPool); } diff --git a/server/src/main/java/org/opensearch/plugins/Plugin.java b/server/src/main/java/org/opensearch/plugins/Plugin.java index 9fabb8b93b367..698502cf3b2b7 100644 --- a/server/src/main/java/org/opensearch/plugins/Plugin.java +++ b/server/src/main/java/org/opensearch/plugins/Plugin.java @@ -93,8 +93,6 @@ @PublicApi(since = "1.0.0") public abstract class Plugin implements Closeable { - protected PluginSubject pluginSubject; - /** * A feature exposed by the plugin. This should be used if a plugin exposes {@link ClusterState.Custom} or {@link Metadata.Custom}; see * also {@link ClusterState.FeatureAware}. @@ -121,18 +119,6 @@ public Collection> getGuiceServiceClasses() return Collections.emptyList(); } - /** - * Setter for PluginSubject. - * - * @param pluginSubject A subject for executing transport actions as the plugin - */ - final void setPluginSubject(PluginSubject pluginSubject) { - if (this.pluginSubject != null) { - throw new IllegalStateException("pluginSubject can only be set once"); - } - this.pluginSubject = pluginSubject; - } - /** * Returns components added by this plugin. *

diff --git a/server/src/main/java/org/opensearch/plugins/PluginSubject.java b/server/src/main/java/org/opensearch/plugins/PluginSubject.java deleted file mode 100644 index c3b3058a30378..0000000000000 --- a/server/src/main/java/org/opensearch/plugins/PluginSubject.java +++ /dev/null @@ -1,41 +0,0 @@ -/* - * SPDX-License-Identifier: Apache-2.0 - * - * The OpenSearch Contributors require contributions made to - * this file be licensed under the Apache-2.0 license or a - * compatible open source license. - */ - -package org.opensearch.plugins; - -import org.opensearch.identity.AbstractSubject; -import org.opensearch.identity.NamedPrincipal; -import org.opensearch.identity.tokens.AuthToken; -import org.opensearch.threadpool.ThreadPool; - -import java.security.Principal; - -/** - * PluginSubject is passed to plugins within createComponents and does not require - * an auth token to authenticate - * - * @opensearch.api - */ -public class PluginSubject extends AbstractSubject { - private final NamedPrincipal pluginCanonicalName; - - PluginSubject(Class pluginClass, ThreadPool threadPool) { - super(threadPool); - this.pluginCanonicalName = new NamedPrincipal(pluginClass.getCanonicalName()); - } - - @Override - public Principal getPrincipal() { - return pluginCanonicalName; - } - - @Override - public void authenticate(AuthToken token) { - // no-op - } -} diff --git a/server/src/main/java/org/opensearch/plugins/PluginsService.java b/server/src/main/java/org/opensearch/plugins/PluginsService.java index 0960e1d564331..f08c9c738f1b4 100644 --- a/server/src/main/java/org/opensearch/plugins/PluginsService.java +++ b/server/src/main/java/org/opensearch/plugins/PluginsService.java @@ -55,7 +55,6 @@ import org.opensearch.index.IndexModule; import org.opensearch.semver.SemverRange; import org.opensearch.threadpool.ExecutorBuilder; -import org.opensearch.threadpool.ThreadPool; import org.opensearch.transport.TransportSettings; import java.io.IOException; @@ -776,14 +775,6 @@ private Class loadPluginClass(String className, ClassLoader lo } } - public void initializePlugins(ThreadPool threadPool) { - List pluginList = filterPlugins(Plugin.class); - for (Plugin p : pluginList) { - PluginSubject pluginSubject = new PluginSubject(p.getClass(), threadPool); - p.setPluginSubject(pluginSubject); - } - } - private Plugin loadPlugin(Class pluginClass, Settings settings, Path configPath) { final Constructor[] constructors = pluginClass.getConstructors(); if (constructors.length == 0) { diff --git a/server/src/test/java/org/opensearch/identity/PluginSubjectTests.java b/server/src/test/java/org/opensearch/identity/PluginSubjectTests.java new file mode 100644 index 0000000000000..779b895b96a3c --- /dev/null +++ b/server/src/test/java/org/opensearch/identity/PluginSubjectTests.java @@ -0,0 +1,56 @@ +/* + * SPDX-License-Identifier: Apache-2.0 + * + * The OpenSearch Contributors require contributions made to + * this file be licensed under the Apache-2.0 license or a + * compatible open source license. + */ + +package org.opensearch.identity; + +import org.opensearch.common.settings.Settings; +import org.opensearch.identity.noop.NoopPluginSubject; +import org.opensearch.plugins.IdentityAwarePlugin; +import org.opensearch.plugins.Plugin; +import org.opensearch.test.OpenSearchTestCase; +import org.opensearch.threadpool.TestThreadPool; +import org.opensearch.threadpool.ThreadPool; + +import java.util.List; + +import static org.hamcrest.Matchers.equalTo; + +public class PluginSubjectTests extends OpenSearchTestCase { + public static class TestPlugin extends Plugin implements IdentityAwarePlugin { + private Subject subject; + + @Override + public void initializePlugin(Subject subject) { + this.subject = subject; + } + + public Subject getSubject() { + return subject; + } + } + + public void testInitializeIdentityAwarePlugin() throws Exception { + ThreadPool threadPool = new TestThreadPool(getTestName()); + IdentityService identityService = new IdentityService(Settings.EMPTY, List.of()); + + TestPlugin testPlugin = new TestPlugin(); + identityService.initializeIdentityAwarePlugins(List.of(testPlugin), threadPool); + + Subject testPluginSubject = new NoopPluginSubject(threadPool); + assertThat(testPlugin.getSubject().getPrincipal().getName(), equalTo(NamedPrincipal.UNAUTHENTICATED.getName())); + assertThat(testPluginSubject.getPrincipal().getName(), equalTo(NamedPrincipal.UNAUTHENTICATED.getName())); + threadPool.getThreadContext().putHeader("test_header", "foo"); + assertThat(threadPool.getThreadContext().getHeader("test_header"), equalTo("foo")); + testPluginSubject.runAs(() -> { + assertNull(threadPool.getThreadContext().getHeader("test_header")); + return null; + }); + assertThat(threadPool.getThreadContext().getHeader("test_header"), equalTo("foo")); + terminate(threadPool); + } +} diff --git a/server/src/test/java/org/opensearch/plugins/PluginsServiceTests.java b/server/src/test/java/org/opensearch/plugins/PluginsServiceTests.java index f42a1144cf9de..bd9ee33856f14 100644 --- a/server/src/test/java/org/opensearch/plugins/PluginsServiceTests.java +++ b/server/src/test/java/org/opensearch/plugins/PluginsServiceTests.java @@ -49,8 +49,6 @@ import org.opensearch.test.MockLogAppender; import org.opensearch.test.OpenSearchTestCase; import org.opensearch.test.VersionUtils; -import org.opensearch.threadpool.TestThreadPool; -import org.opensearch.threadpool.ThreadPool; import org.hamcrest.Matchers; import java.io.IOException; @@ -72,16 +70,13 @@ import java.util.zip.ZipInputStream; import java.util.zip.ZipOutputStream; -import static org.opensearch.identity.AbstractSubject.SUBJECT_HEADER; import static org.hamcrest.Matchers.containsInAnyOrder; import static org.hamcrest.Matchers.containsString; -import static org.hamcrest.Matchers.equalTo; import static org.hamcrest.Matchers.hasSize; import static org.hamcrest.Matchers.hasToString; import static org.hamcrest.Matchers.instanceOf; import static org.hamcrest.Matchers.notNullValue; import static org.hamcrest.Matchers.sameInstance; -import static org.mockito.Mockito.mock; @LuceneTestCase.SuppressFileSystems(value = "ExtrasFS") public class PluginsServiceTests extends OpenSearchTestCase { @@ -933,35 +928,6 @@ public void testPluginLoadFailure() throws IOException { assertThat(exception, hasToString(containsString("Unable to load plugin class [DummyClass]"))); } - public void testSetPluginSubject() { - TestPlugin testPlugin = new TestPlugin(); - PluginSubject testPluginSubject = new PluginSubject(testPlugin.getClass(), mock(ThreadPool.class)); - testPlugin.setPluginSubject(testPluginSubject); // should succeed - IllegalStateException e = expectThrows(IllegalStateException.class, () -> testPlugin.setPluginSubject(testPluginSubject)); - assertThat(e.getMessage(), containsString("pluginSubject can only be set once")); - } - - public void testInitializePlugins() throws Exception { - ThreadPool threadPool = new TestThreadPool(getTestName()); - Settings settings = Settings.builder().put(Environment.PATH_HOME_SETTING.getKey(), createTempDir()).build(); - PluginsService service = newPluginsService(settings, TestPlugin.class); - - service.initializePlugins(threadPool); - - Plugin testPlugin = service.filterPlugins(Plugin.class).get(0); - PluginSubject testPluginSubject = new PluginSubject(testPlugin.getClass(), threadPool); - assertThat(testPluginSubject.getPrincipal().getName(), equalTo(TestPlugin.class.getCanonicalName())); - testPluginSubject.runAs(() -> { - assertThat(TestPlugin.class.getCanonicalName(), equalTo(threadPool.getThreadContext().getHeader(SUBJECT_HEADER))); - return null; - }); - assertNull(threadPool.getThreadContext().getHeader(SUBJECT_HEADER)); - // pluginSubject should have previously been set in service.initializePlugins - IllegalStateException e = expectThrows(IllegalStateException.class, () -> testPlugin.setPluginSubject(testPluginSubject)); - assertThat(e.getMessage(), containsString("pluginSubject can only be set once")); - terminate(threadPool); - } - public void testExtensiblePlugin() { TestExtensiblePlugin extensiblePlugin = new TestExtensiblePlugin(); PluginsService.loadExtensions( From 7b3b5eccacccd6a83a05f5dd7d9fd5bdfb044693 Mon Sep 17 00:00:00 2001 From: Craig Perkins Date: Fri, 16 Aug 2024 10:39:33 -0400 Subject: [PATCH 40/65] Add final Signed-off-by: Craig Perkins --- .../java/org/opensearch/identity/noop/NoopPluginSubject.java | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/server/src/main/java/org/opensearch/identity/noop/NoopPluginSubject.java b/server/src/main/java/org/opensearch/identity/noop/NoopPluginSubject.java index b266bc9620def..e06711e8cec19 100644 --- a/server/src/main/java/org/opensearch/identity/noop/NoopPluginSubject.java +++ b/server/src/main/java/org/opensearch/identity/noop/NoopPluginSubject.java @@ -18,7 +18,7 @@ import java.util.concurrent.Callable; public class NoopPluginSubject extends AbstractSubject { - private ThreadPool threadPool; + private final ThreadPool threadPool; public NoopPluginSubject(ThreadPool threadPool) { super(); From 0a26f26e955b0485ed86cd79cd72478be1258db1 Mon Sep 17 00:00:00 2001 From: Craig Perkins Date: Fri, 16 Aug 2024 10:44:47 -0400 Subject: [PATCH 41/65] Remove server dependency Signed-off-by: Craig Perkins --- qa/smoke-test-http/build.gradle | 1 - 1 file changed, 1 deletion(-) diff --git a/qa/smoke-test-http/build.gradle b/qa/smoke-test-http/build.gradle index 709ed049e9d0f..496fda6bb717d 100644 --- a/qa/smoke-test-http/build.gradle +++ b/qa/smoke-test-http/build.gradle @@ -38,7 +38,6 @@ dependencies { testImplementation project(path: ':plugins:transport-reactor-netty4') // for http testImplementation project(path: ':plugins:transport-nio') testImplementation project(path: ':plugins:identity-shiro') // for http - testImplementation project(path: ':server') } integTest { From 94a5f2c3b582da291179b98f46bced53d037246f Mon Sep 17 00:00:00 2001 From: Craig Perkins Date: Fri, 16 Aug 2024 10:47:48 -0400 Subject: [PATCH 42/65] Remove AbstractSubject Signed-off-by: Craig Perkins --- .../identity/shiro/ShiroSubject.java | 3 +-- .../opensearch/identity/AbstractSubject.java | 23 ------------------- .../java/org/opensearch/identity/Subject.java | 4 +++- .../identity/noop/NoopPluginSubject.java | 4 ++-- .../opensearch/identity/noop/NoopSubject.java | 3 +-- 5 files changed, 7 insertions(+), 30 deletions(-) delete mode 100644 server/src/main/java/org/opensearch/identity/AbstractSubject.java diff --git a/plugins/identity-shiro/src/main/java/org/opensearch/identity/shiro/ShiroSubject.java b/plugins/identity-shiro/src/main/java/org/opensearch/identity/shiro/ShiroSubject.java index 10d1d7990a7e3..e55204593621c 100644 --- a/plugins/identity-shiro/src/main/java/org/opensearch/identity/shiro/ShiroSubject.java +++ b/plugins/identity-shiro/src/main/java/org/opensearch/identity/shiro/ShiroSubject.java @@ -8,7 +8,6 @@ package org.opensearch.identity.shiro; -import org.opensearch.identity.AbstractSubject; import org.opensearch.identity.Subject; import org.opensearch.identity.tokens.AuthToken; @@ -20,7 +19,7 @@ * * @opensearch.experimental */ -public class ShiroSubject extends AbstractSubject { +public class ShiroSubject implements Subject { private final ShiroTokenManager authTokenHandler; private final org.apache.shiro.subject.Subject shiroSubject; diff --git a/server/src/main/java/org/opensearch/identity/AbstractSubject.java b/server/src/main/java/org/opensearch/identity/AbstractSubject.java deleted file mode 100644 index f841d4cb593b9..0000000000000 --- a/server/src/main/java/org/opensearch/identity/AbstractSubject.java +++ /dev/null @@ -1,23 +0,0 @@ -/* - * SPDX-License-Identifier: Apache-2.0 - * - * The OpenSearch Contributors require contributions made to - * this file be licensed under the Apache-2.0 license or a - * compatible open source license. - */ - -package org.opensearch.identity; - -import java.util.concurrent.Callable; - -/** - * An AbstractSubject provides a default implementation for runAs simply calls the Callable passed to it - */ -public abstract class AbstractSubject implements Subject { - public AbstractSubject() {} - - @Override - public void runAs(Callable callable) throws Exception { - callable.call(); - } -} diff --git a/server/src/main/java/org/opensearch/identity/Subject.java b/server/src/main/java/org/opensearch/identity/Subject.java index 0beac722cbd64..84a221acaf2ce 100644 --- a/server/src/main/java/org/opensearch/identity/Subject.java +++ b/server/src/main/java/org/opensearch/identity/Subject.java @@ -34,5 +34,7 @@ public interface Subject { /** * runAs allows the caller to run a callable function as this subject */ - void runAs(Callable callable) throws Exception; + default void runAs(Callable callable) throws Exception { + callable.call(); + }; } diff --git a/server/src/main/java/org/opensearch/identity/noop/NoopPluginSubject.java b/server/src/main/java/org/opensearch/identity/noop/NoopPluginSubject.java index e06711e8cec19..0d6c0c38ec50f 100644 --- a/server/src/main/java/org/opensearch/identity/noop/NoopPluginSubject.java +++ b/server/src/main/java/org/opensearch/identity/noop/NoopPluginSubject.java @@ -9,15 +9,15 @@ package org.opensearch.identity.noop; import org.opensearch.common.util.concurrent.ThreadContext; -import org.opensearch.identity.AbstractSubject; import org.opensearch.identity.NamedPrincipal; +import org.opensearch.identity.Subject; import org.opensearch.identity.tokens.AuthToken; import org.opensearch.threadpool.ThreadPool; import java.security.Principal; import java.util.concurrent.Callable; -public class NoopPluginSubject extends AbstractSubject { +public class NoopPluginSubject implements Subject { private final ThreadPool threadPool; public NoopPluginSubject(ThreadPool threadPool) { diff --git a/server/src/main/java/org/opensearch/identity/noop/NoopSubject.java b/server/src/main/java/org/opensearch/identity/noop/NoopSubject.java index 2cf63c6b230f8..6c6e7077d5450 100644 --- a/server/src/main/java/org/opensearch/identity/noop/NoopSubject.java +++ b/server/src/main/java/org/opensearch/identity/noop/NoopSubject.java @@ -8,7 +8,6 @@ package org.opensearch.identity.noop; -import org.opensearch.identity.AbstractSubject; import org.opensearch.identity.NamedPrincipal; import org.opensearch.identity.Subject; import org.opensearch.identity.tokens.AuthToken; @@ -23,7 +22,7 @@ * * @opensearch.internal */ -public class NoopSubject extends AbstractSubject { +public class NoopSubject implements Subject { public NoopSubject() { super(); From 19dffb701bcff782cb12f7a83efa3482a2aa0959 Mon Sep 17 00:00:00 2001 From: Craig Perkins Date: Fri, 16 Aug 2024 10:50:22 -0400 Subject: [PATCH 43/65] Remove unnecessary changes Signed-off-by: Craig Perkins --- .../opensearch/identity/noop/NoopSubject.java | 4 ---- .../java/org/opensearch/plugins/Plugin.java | 20 +++++++++---------- 2 files changed, 10 insertions(+), 14 deletions(-) diff --git a/server/src/main/java/org/opensearch/identity/noop/NoopSubject.java b/server/src/main/java/org/opensearch/identity/noop/NoopSubject.java index 6c6e7077d5450..964a218db3cf5 100644 --- a/server/src/main/java/org/opensearch/identity/noop/NoopSubject.java +++ b/server/src/main/java/org/opensearch/identity/noop/NoopSubject.java @@ -24,10 +24,6 @@ */ public class NoopSubject implements Subject { - public NoopSubject() { - super(); - } - @Override public Principal getPrincipal() { return NamedPrincipal.UNAUTHENTICATED; diff --git a/server/src/main/java/org/opensearch/plugins/Plugin.java b/server/src/main/java/org/opensearch/plugins/Plugin.java index 698502cf3b2b7..33c4155d12c25 100644 --- a/server/src/main/java/org/opensearch/plugins/Plugin.java +++ b/server/src/main/java/org/opensearch/plugins/Plugin.java @@ -126,18 +126,18 @@ public Collection> getGuiceServiceClasses() * Note: To aid in the migration away from guice, all objects returned as components will be bound in guice * to themselves. * - * @param client A client to make requests to the system - * @param clusterService A service to allow watching and updating cluster state - * @param threadPool A service to allow retrieving an executor to run an async action - * @param resourceWatcherService A service to watch for changes to node local files - * @param scriptService A service to allow running scripts on the local node - * @param xContentRegistry the registry for extensible xContent parsing - * @param environment the environment for path and setting configurations - * @param nodeEnvironment the node environment used coordinate access to the data paths - * @param namedWriteableRegistry the registry for {@link NamedWriteable} object parsing + * @param client A client to make requests to the system + * @param clusterService A service to allow watching and updating cluster state + * @param threadPool A service to allow retrieving an executor to run an async action + * @param resourceWatcherService A service to watch for changes to node local files + * @param scriptService A service to allow running scripts on the local node + * @param xContentRegistry the registry for extensible xContent parsing + * @param environment the environment for path and setting configurations + * @param nodeEnvironment the node environment used coordinate access to the data paths + * @param namedWriteableRegistry the registry for {@link NamedWriteable} object parsing * @param indexNameExpressionResolver A service that resolves expression to index and alias names * @param repositoriesServiceSupplier A supplier for the service that manages snapshot repositories; will return null when this method - * is called, but will return the repositories service once the node is initialized. + * is called, but will return the repositories service once the node is initialized. */ public Collection createComponents( Client client, From 17abb6373f4ee20832e941c2eda1086a5424ee98 Mon Sep 17 00:00:00 2001 From: Craig Perkins Date: Fri, 16 Aug 2024 10:59:00 -0400 Subject: [PATCH 44/65] Add javadoc to NoopPluginSubject Signed-off-by: Craig Perkins --- .../org/opensearch/identity/noop/NoopPluginSubject.java | 9 +++++++++ 1 file changed, 9 insertions(+) diff --git a/server/src/main/java/org/opensearch/identity/noop/NoopPluginSubject.java b/server/src/main/java/org/opensearch/identity/noop/NoopPluginSubject.java index 0d6c0c38ec50f..f2d79d8a35d89 100644 --- a/server/src/main/java/org/opensearch/identity/noop/NoopPluginSubject.java +++ b/server/src/main/java/org/opensearch/identity/noop/NoopPluginSubject.java @@ -17,6 +17,15 @@ import java.security.Principal; import java.util.concurrent.Callable; +/** + * Implementation of subject that is always authenticated + *

+ * This class and related classes in this package will not return nulls or fail permissions checks + * + * This class is used by the NoopIdentityPlugin to initialize IdentityAwarePlugins + * + * @opensearch.internal + */ public class NoopPluginSubject implements Subject { private final ThreadPool threadPool; From 48bd43c1b2f13d7846fdf44f77c84dd6325a9da2 Mon Sep 17 00:00:00 2001 From: Craig Perkins Date: Fri, 16 Aug 2024 12:01:16 -0400 Subject: [PATCH 45/65] Rename to assignSubject Signed-off-by: Craig Perkins --- .../java/org/opensearch/identity/shiro/ShiroIdentityPlugin.java | 2 +- .../java/org/opensearch/identity/noop/NoopIdentityPlugin.java | 2 +- .../main/java/org/opensearch/plugins/IdentityAwarePlugin.java | 2 +- .../test/java/org/opensearch/identity/PluginSubjectTests.java | 2 +- 4 files changed, 4 insertions(+), 4 deletions(-) diff --git a/plugins/identity-shiro/src/main/java/org/opensearch/identity/shiro/ShiroIdentityPlugin.java b/plugins/identity-shiro/src/main/java/org/opensearch/identity/shiro/ShiroIdentityPlugin.java index 06172028578ae..8da38663ad974 100644 --- a/plugins/identity-shiro/src/main/java/org/opensearch/identity/shiro/ShiroIdentityPlugin.java +++ b/plugins/identity-shiro/src/main/java/org/opensearch/identity/shiro/ShiroIdentityPlugin.java @@ -72,7 +72,7 @@ public void initializeIdentityAwarePlugins(List identityAwa if (identityAwarePlugins != null) { for (IdentityAwarePlugin plugin : identityAwarePlugins) { Subject subject = new NoopPluginSubject(threadPool); - plugin.initializePlugin(subject); + plugin.assignSubject(subject); } } } diff --git a/server/src/main/java/org/opensearch/identity/noop/NoopIdentityPlugin.java b/server/src/main/java/org/opensearch/identity/noop/NoopIdentityPlugin.java index 1e37b47286cab..2eab42c2513de 100644 --- a/server/src/main/java/org/opensearch/identity/noop/NoopIdentityPlugin.java +++ b/server/src/main/java/org/opensearch/identity/noop/NoopIdentityPlugin.java @@ -48,7 +48,7 @@ public void initializeIdentityAwarePlugins(List identityAwa if (identityAwarePlugins != null) { for (IdentityAwarePlugin plugin : identityAwarePlugins) { Subject subject = new NoopPluginSubject(threadPool); - plugin.initializePlugin(subject); + plugin.assignSubject(subject); } } } diff --git a/server/src/main/java/org/opensearch/plugins/IdentityAwarePlugin.java b/server/src/main/java/org/opensearch/plugins/IdentityAwarePlugin.java index 274934e8e322b..45712d98eac75 100644 --- a/server/src/main/java/org/opensearch/plugins/IdentityAwarePlugin.java +++ b/server/src/main/java/org/opensearch/plugins/IdentityAwarePlugin.java @@ -27,5 +27,5 @@ public interface IdentityAwarePlugin { * @param pluginSystemSubject A subject for running transport actions in the plugin system context for system index * interaction */ - default void initializePlugin(Subject pluginSystemSubject) {} + default void assignSubject(Subject pluginSystemSubject) {} } diff --git a/server/src/test/java/org/opensearch/identity/PluginSubjectTests.java b/server/src/test/java/org/opensearch/identity/PluginSubjectTests.java index 779b895b96a3c..0d2d5d1d75f71 100644 --- a/server/src/test/java/org/opensearch/identity/PluginSubjectTests.java +++ b/server/src/test/java/org/opensearch/identity/PluginSubjectTests.java @@ -25,7 +25,7 @@ public static class TestPlugin extends Plugin implements IdentityAwarePlugin { private Subject subject; @Override - public void initializePlugin(Subject subject) { + public void assignSubject(Subject subject) { this.subject = subject; } From be9a89a50cbf2224199c97632ac7487616bba529 Mon Sep 17 00:00:00 2001 From: Craig Perkins Date: Fri, 16 Aug 2024 12:29:19 -0400 Subject: [PATCH 46/65] Add experimental label Signed-off-by: Craig Perkins --- .../main/java/org/opensearch/plugins/IdentityAwarePlugin.java | 4 +++- 1 file changed, 3 insertions(+), 1 deletion(-) diff --git a/server/src/main/java/org/opensearch/plugins/IdentityAwarePlugin.java b/server/src/main/java/org/opensearch/plugins/IdentityAwarePlugin.java index 45712d98eac75..a0a3b336e16ae 100644 --- a/server/src/main/java/org/opensearch/plugins/IdentityAwarePlugin.java +++ b/server/src/main/java/org/opensearch/plugins/IdentityAwarePlugin.java @@ -8,6 +8,7 @@ package org.opensearch.plugins; +import org.opensearch.common.annotation.ExperimentalApi; import org.opensearch.identity.Subject; /** @@ -17,8 +18,9 @@ * When the Security plugin is installed, the default subject is the authenticated user. In particular, * SystemIndexPlugins utilize the {@link Subject} to perform transport actions that interact with system indices. * - * @opensearch.api + * @opensearch.experimental */ +@ExperimentalApi public interface IdentityAwarePlugin { /** From ca1f2974110777e86d3da2273d0afaaa7c75b25e Mon Sep 17 00:00:00 2001 From: Craig Perkins Date: Fri, 16 Aug 2024 14:26:44 -0400 Subject: [PATCH 47/65] Add getPluginSubject(plugin) to IdentityPlugin Signed-off-by: Craig Perkins --- .../identity/shiro/ShiroIdentityPlugin.java | 44 +++++++++++++++---- .../shiro/ShiroIdentityPluginTests.java | 7 ++- .../extensions/NoopExtensionsManager.java | 5 +-- .../opensearch/identity/IdentityService.java | 14 ++++-- .../java/org/opensearch/identity/Subject.java | 2 + .../identity/noop/NoopIdentityPlugin.java | 19 ++++---- .../opensearch/identity/tokens/AuthToken.java | 3 ++ .../identity/tokens/OnBehalfOfClaims.java | 5 +++ .../identity/tokens/TokenManager.java | 4 ++ .../main/java/org/opensearch/node/Node.java | 28 ++++++------ .../opensearch/plugins/IdentityPlugin.java | 14 ++++-- .../opensearch/action/ActionModuleTests.java | 5 ++- .../bootstrap/IdentityPluginTests.java | 15 ++++--- .../extensions/ExtensionsManagerTests.java | 4 +- .../rest/ExtensionRestRequestTests.java | 4 +- .../RestInitializeExtensionActionTests.java | 6 +-- .../rest/RestSendToExtensionActionTests.java | 7 +-- .../identity/PluginSubjectTests.java | 4 +- .../opensearch/rest/RestControllerTests.java | 3 +- .../rest/RestHttpResponseHeadersTests.java | 4 +- .../indices/RestValidateQueryActionTests.java | 2 +- .../test/rest/RestActionTestCase.java | 5 ++- 22 files changed, 135 insertions(+), 69 deletions(-) diff --git a/plugins/identity-shiro/src/main/java/org/opensearch/identity/shiro/ShiroIdentityPlugin.java b/plugins/identity-shiro/src/main/java/org/opensearch/identity/shiro/ShiroIdentityPlugin.java index 8da38663ad974..34d1746be72f1 100644 --- a/plugins/identity-shiro/src/main/java/org/opensearch/identity/shiro/ShiroIdentityPlugin.java +++ b/plugins/identity-shiro/src/main/java/org/opensearch/identity/shiro/ShiroIdentityPlugin.java @@ -12,16 +12,27 @@ import org.apache.logging.log4j.Logger; import org.apache.shiro.SecurityUtils; import org.apache.shiro.mgt.SecurityManager; +import org.opensearch.client.Client; +import org.opensearch.cluster.metadata.IndexNameExpressionResolver; +import org.opensearch.cluster.service.ClusterService; import org.opensearch.common.settings.Settings; +import org.opensearch.core.common.io.stream.NamedWriteableRegistry; +import org.opensearch.core.xcontent.NamedXContentRegistry; +import org.opensearch.env.Environment; +import org.opensearch.env.NodeEnvironment; import org.opensearch.identity.Subject; import org.opensearch.identity.noop.NoopPluginSubject; import org.opensearch.identity.tokens.TokenManager; -import org.opensearch.plugins.IdentityAwarePlugin; import org.opensearch.plugins.IdentityPlugin; import org.opensearch.plugins.Plugin; +import org.opensearch.repositories.RepositoriesService; +import org.opensearch.script.ScriptService; import org.opensearch.threadpool.ThreadPool; +import org.opensearch.watcher.ResourceWatcherService; -import java.util.List; +import java.util.Collection; +import java.util.Collections; +import java.util.function.Supplier; /** * Identity implementation with Shiro @@ -34,6 +45,8 @@ public final class ShiroIdentityPlugin extends Plugin implements IdentityPlugin private final Settings settings; private final ShiroTokenManager authTokenHandler; + private ThreadPool threadPool; + /** * Create a new instance of the Shiro Identity Plugin * @@ -47,6 +60,24 @@ public ShiroIdentityPlugin(final Settings settings) { SecurityUtils.setSecurityManager(securityManager); } + @Override + public Collection createComponents( + Client client, + ClusterService clusterService, + ThreadPool threadPool, + ResourceWatcherService resourceWatcherService, + ScriptService scriptService, + NamedXContentRegistry xContentRegistry, + Environment environment, + NodeEnvironment nodeEnvironment, + NamedWriteableRegistry namedWriteableRegistry, + IndexNameExpressionResolver expressionResolver, + Supplier repositoriesServiceSupplier + ) { + this.threadPool = threadPool; + return Collections.emptyList(); + } + /** * Return a Shiro Subject based on the provided authTokenHandler and current subject * @@ -68,12 +99,7 @@ public TokenManager getTokenManager() { } @Override - public void initializeIdentityAwarePlugins(List identityAwarePlugins, ThreadPool threadPool) { - if (identityAwarePlugins != null) { - for (IdentityAwarePlugin plugin : identityAwarePlugins) { - Subject subject = new NoopPluginSubject(threadPool); - plugin.assignSubject(subject); - } - } + public Subject getPluginSubject(Plugin plugin) { + return new NoopPluginSubject(threadPool); } } diff --git a/plugins/identity-shiro/src/test/java/org/opensearch/identity/shiro/ShiroIdentityPluginTests.java b/plugins/identity-shiro/src/test/java/org/opensearch/identity/shiro/ShiroIdentityPluginTests.java index 626cd44d13ec8..cb09590918278 100644 --- a/plugins/identity-shiro/src/test/java/org/opensearch/identity/shiro/ShiroIdentityPluginTests.java +++ b/plugins/identity-shiro/src/test/java/org/opensearch/identity/shiro/ShiroIdentityPluginTests.java @@ -13,6 +13,7 @@ import org.opensearch.identity.IdentityService; import org.opensearch.plugins.IdentityPlugin; import org.opensearch.test.OpenSearchTestCase; +import org.opensearch.threadpool.TestThreadPool; import java.util.List; @@ -24,18 +25,20 @@ public class ShiroIdentityPluginTests extends OpenSearchTestCase { public void testSingleIdentityPluginSucceeds() { + TestThreadPool threadPool = new TestThreadPool(getTestName()); IdentityPlugin identityPlugin1 = new ShiroIdentityPlugin(Settings.EMPTY); List pluginList1 = List.of(identityPlugin1); - IdentityService identityService1 = new IdentityService(Settings.EMPTY, pluginList1); + IdentityService identityService1 = new IdentityService(Settings.EMPTY, threadPool, pluginList1); assertThat(identityService1.getTokenManager(), is(instanceOf(ShiroTokenManager.class))); } public void testMultipleIdentityPluginsFail() { + TestThreadPool threadPool = new TestThreadPool(getTestName()); IdentityPlugin identityPlugin1 = new ShiroIdentityPlugin(Settings.EMPTY); IdentityPlugin identityPlugin2 = new ShiroIdentityPlugin(Settings.EMPTY); IdentityPlugin identityPlugin3 = new ShiroIdentityPlugin(Settings.EMPTY); List pluginList = List.of(identityPlugin1, identityPlugin2, identityPlugin3); - Exception ex = assertThrows(OpenSearchException.class, () -> new IdentityService(Settings.EMPTY, pluginList)); + Exception ex = assertThrows(OpenSearchException.class, () -> new IdentityService(Settings.EMPTY, threadPool, pluginList)); assert (ex.getMessage().contains("Multiple identity plugins are not supported,")); } diff --git a/server/src/main/java/org/opensearch/extensions/NoopExtensionsManager.java b/server/src/main/java/org/opensearch/extensions/NoopExtensionsManager.java index 81b1b91b11481..5bc655af4df7b 100644 --- a/server/src/main/java/org/opensearch/extensions/NoopExtensionsManager.java +++ b/server/src/main/java/org/opensearch/extensions/NoopExtensionsManager.java @@ -20,7 +20,6 @@ import org.opensearch.transport.TransportService; import java.io.IOException; -import java.util.List; import java.util.Optional; import java.util.Set; @@ -31,8 +30,8 @@ */ public class NoopExtensionsManager extends ExtensionsManager { - public NoopExtensionsManager() throws IOException { - super(Set.of(), new IdentityService(Settings.EMPTY, List.of())); + public NoopExtensionsManager(IdentityService identityService) throws IOException { + super(Set.of(), identityService); } @Override diff --git a/server/src/main/java/org/opensearch/identity/IdentityService.java b/server/src/main/java/org/opensearch/identity/IdentityService.java index e81a6f970531a..ed9b14c7d0368 100644 --- a/server/src/main/java/org/opensearch/identity/IdentityService.java +++ b/server/src/main/java/org/opensearch/identity/IdentityService.java @@ -13,6 +13,7 @@ import org.opensearch.identity.tokens.TokenManager; import org.opensearch.plugins.IdentityAwarePlugin; import org.opensearch.plugins.IdentityPlugin; +import org.opensearch.plugins.Plugin; import org.opensearch.threadpool.ThreadPool; import java.util.List; @@ -29,12 +30,12 @@ public class IdentityService { private final Settings settings; private final IdentityPlugin identityPlugin; - public IdentityService(final Settings settings, final List identityPlugins) { + public IdentityService(final Settings settings, final ThreadPool threadPool, final List identityPlugins) { this.settings = settings; if (identityPlugins.size() == 0) { log.debug("Identity plugins size is 0"); - identityPlugin = new NoopIdentityPlugin(); + identityPlugin = new NoopIdentityPlugin(threadPool); } else if (identityPlugins.size() == 1) { log.debug("Identity plugins size is 1"); identityPlugin = identityPlugins.get(0); @@ -60,7 +61,12 @@ public TokenManager getTokenManager() { return identityPlugin.getTokenManager(); } - public void initializeIdentityAwarePlugins(final List identityAwarePlugins, ThreadPool threadPool) { - identityPlugin.initializeIdentityAwarePlugins(identityAwarePlugins, threadPool); + public void initializeIdentityAwarePlugins(final List identityAwarePlugins) { + if (identityAwarePlugins != null) { + for (IdentityAwarePlugin plugin : identityAwarePlugins) { + Subject subject = identityPlugin.getPluginSubject((Plugin) plugin); + plugin.assignSubject(subject); + } + } } } diff --git a/server/src/main/java/org/opensearch/identity/Subject.java b/server/src/main/java/org/opensearch/identity/Subject.java index 84a221acaf2ce..a6bd7f9777481 100644 --- a/server/src/main/java/org/opensearch/identity/Subject.java +++ b/server/src/main/java/org/opensearch/identity/Subject.java @@ -5,6 +5,7 @@ package org.opensearch.identity; +import org.opensearch.common.annotation.ExperimentalApi; import org.opensearch.identity.tokens.AuthToken; import java.security.Principal; @@ -15,6 +16,7 @@ * * @opensearch.experimental */ +@ExperimentalApi public interface Subject { /** diff --git a/server/src/main/java/org/opensearch/identity/noop/NoopIdentityPlugin.java b/server/src/main/java/org/opensearch/identity/noop/NoopIdentityPlugin.java index 2eab42c2513de..a66e5a6a12781 100644 --- a/server/src/main/java/org/opensearch/identity/noop/NoopIdentityPlugin.java +++ b/server/src/main/java/org/opensearch/identity/noop/NoopIdentityPlugin.java @@ -10,12 +10,10 @@ import org.opensearch.identity.Subject; import org.opensearch.identity.tokens.TokenManager; -import org.opensearch.plugins.IdentityAwarePlugin; import org.opensearch.plugins.IdentityPlugin; +import org.opensearch.plugins.Plugin; import org.opensearch.threadpool.ThreadPool; -import java.util.List; - /** * Implementation of identity plugin that does not enforce authentication or authorization *

@@ -25,6 +23,12 @@ */ public class NoopIdentityPlugin implements IdentityPlugin { + private final ThreadPool threadPool; + + public NoopIdentityPlugin(ThreadPool threadPool) { + this.threadPool = threadPool; + } + /** * Get the current subject * @return Must never return null @@ -44,12 +48,7 @@ public TokenManager getTokenManager() { } @Override - public void initializeIdentityAwarePlugins(List identityAwarePlugins, ThreadPool threadPool) { - if (identityAwarePlugins != null) { - for (IdentityAwarePlugin plugin : identityAwarePlugins) { - Subject subject = new NoopPluginSubject(threadPool); - plugin.assignSubject(subject); - } - } + public Subject getPluginSubject(Plugin plugin) { + return new NoopPluginSubject(threadPool); } } diff --git a/server/src/main/java/org/opensearch/identity/tokens/AuthToken.java b/server/src/main/java/org/opensearch/identity/tokens/AuthToken.java index 88bb855a6e70d..57e4ac4a82ae3 100644 --- a/server/src/main/java/org/opensearch/identity/tokens/AuthToken.java +++ b/server/src/main/java/org/opensearch/identity/tokens/AuthToken.java @@ -8,11 +8,14 @@ package org.opensearch.identity.tokens; +import org.opensearch.common.annotation.ExperimentalApi; + /** * Interface for all token formats to support to authenticate user such as UserName/Password tokens, Access tokens, and more. * * @opensearch.experimental */ +@ExperimentalApi public interface AuthToken { String asAuthHeaderValue(); diff --git a/server/src/main/java/org/opensearch/identity/tokens/OnBehalfOfClaims.java b/server/src/main/java/org/opensearch/identity/tokens/OnBehalfOfClaims.java index 00e50a59e9486..2b37ed954e7d4 100644 --- a/server/src/main/java/org/opensearch/identity/tokens/OnBehalfOfClaims.java +++ b/server/src/main/java/org/opensearch/identity/tokens/OnBehalfOfClaims.java @@ -8,9 +8,14 @@ package org.opensearch.identity.tokens; +import org.opensearch.common.annotation.ExperimentalApi; + /** * This class represents the claims of an OnBehalfOf token. + * + * @opensearch.experimental */ +@ExperimentalApi public class OnBehalfOfClaims { private final String audience; diff --git a/server/src/main/java/org/opensearch/identity/tokens/TokenManager.java b/server/src/main/java/org/opensearch/identity/tokens/TokenManager.java index 972a9a1080955..b9340e618245a 100644 --- a/server/src/main/java/org/opensearch/identity/tokens/TokenManager.java +++ b/server/src/main/java/org/opensearch/identity/tokens/TokenManager.java @@ -8,11 +8,15 @@ package org.opensearch.identity.tokens; +import org.opensearch.common.annotation.ExperimentalApi; import org.opensearch.identity.Subject; /** * This interface defines the expected methods of a token manager + * + * @opensearch.experimental */ +@ExperimentalApi public interface TokenManager { /** diff --git a/server/src/main/java/org/opensearch/node/Node.java b/server/src/main/java/org/opensearch/node/Node.java index 74cd9e6467b95..132a46b9b87e4 100644 --- a/server/src/main/java/org/opensearch/node/Node.java +++ b/server/src/main/java/org/opensearch/node/Node.java @@ -526,19 +526,6 @@ protected Node( identityPlugins.addAll(pluginsService.filterPlugins(IdentityPlugin.class)); } - final IdentityService identityService = new IdentityService(settings, identityPlugins); - - if (FeatureFlags.isEnabled(FeatureFlags.EXTENSIONS)) { - final List extensionAwarePlugins = pluginsService.filterPlugins(ExtensionAwarePlugin.class); - Set> additionalSettings = new HashSet<>(); - for (ExtensionAwarePlugin extAwarePlugin : extensionAwarePlugins) { - additionalSettings.addAll(extAwarePlugin.getExtensionSettings()); - } - this.extensionsManager = new ExtensionsManager(additionalSettings, identityService); - } else { - this.extensionsManager = new NoopExtensionsManager(); - } - final Set additionalRoles = pluginsService.filterPlugins(Plugin.class) .stream() .map(Plugin::getRoles) @@ -576,6 +563,19 @@ protected Node( runnableTaskListener = new AtomicReference<>(); final ThreadPool threadPool = new ThreadPool(settings, runnableTaskListener, executorBuilders.toArray(new ExecutorBuilder[0])); + final IdentityService identityService = new IdentityService(settings, threadPool, identityPlugins); + + if (FeatureFlags.isEnabled(FeatureFlags.EXTENSIONS)) { + final List extensionAwarePlugins = pluginsService.filterPlugins(ExtensionAwarePlugin.class); + Set> additionalSettings = new HashSet<>(); + for (ExtensionAwarePlugin extAwarePlugin : extensionAwarePlugins) { + additionalSettings.addAll(extAwarePlugin.getExtensionSettings()); + } + this.extensionsManager = new ExtensionsManager(additionalSettings, identityService); + } else { + this.extensionsManager = new NoopExtensionsManager(identityService); + } + final SetOnce repositoriesServiceReference = new SetOnce<>(); final RemoteStoreNodeService remoteStoreNodeService = new RemoteStoreNodeService(repositoriesServiceReference::get, threadPool); localNodeFactory = new LocalNodeFactory(settings, nodeEnvironment.nodeId(), remoteStoreNodeService); @@ -714,7 +714,7 @@ protected Node( rerouteServiceReference::get ); List identityAwarePlugins = pluginsService.filterPlugins(IdentityAwarePlugin.class); - identityService.initializeIdentityAwarePlugins(identityAwarePlugins, threadPool); + identityService.initializeIdentityAwarePlugins(identityAwarePlugins); final Map> systemIndexDescriptorMap = Collections.unmodifiableMap( pluginsService.filterPlugins(SystemIndexPlugin.class) .stream() diff --git a/server/src/main/java/org/opensearch/plugins/IdentityPlugin.java b/server/src/main/java/org/opensearch/plugins/IdentityPlugin.java index c7d4e1c8c0c99..6dd6c97bbbf33 100644 --- a/server/src/main/java/org/opensearch/plugins/IdentityPlugin.java +++ b/server/src/main/java/org/opensearch/plugins/IdentityPlugin.java @@ -8,17 +8,16 @@ package org.opensearch.plugins; +import org.opensearch.common.annotation.ExperimentalApi; import org.opensearch.identity.Subject; import org.opensearch.identity.tokens.TokenManager; -import org.opensearch.threadpool.ThreadPool; - -import java.util.List; /** * Plugin that provides identity and access control for OpenSearch * * @opensearch.experimental */ +@ExperimentalApi public interface IdentityPlugin { /** @@ -33,5 +32,12 @@ public interface IdentityPlugin { */ TokenManager getTokenManager(); - void initializeIdentityAwarePlugins(final List systemIndexPlugins, ThreadPool threadPool); + /** + * Gets a subject corresponding to the passed plugin that can be utilized to perform transport actions + * in the plugin system context + * + * @param plugin The corresponding plugin + * @return Subject corresponding to the plugin + */ + Subject getPluginSubject(Plugin plugin); } diff --git a/server/src/test/java/org/opensearch/action/ActionModuleTests.java b/server/src/test/java/org/opensearch/action/ActionModuleTests.java index 8479f011adf48..13c408d36a923 100644 --- a/server/src/test/java/org/opensearch/action/ActionModuleTests.java +++ b/server/src/test/java/org/opensearch/action/ActionModuleTests.java @@ -130,6 +130,7 @@ protected FakeAction() { public void testSetupRestHandlerContainsKnownBuiltin() throws IOException { SettingsModule settings = new SettingsModule(Settings.EMPTY); UsageService usageService = new UsageService(); + ThreadPool threadPool = new TestThreadPool(getTestName()); ActionModule actionModule = new ActionModule( settings.getSettings(), new IndexNameExpressionResolver(new ThreadContext(Settings.EMPTY)), @@ -142,8 +143,8 @@ public void testSetupRestHandlerContainsKnownBuiltin() throws IOException { null, usageService, null, - new IdentityService(Settings.EMPTY, new ArrayList<>()), - new ExtensionsManager(Set.of(), new IdentityService(Settings.EMPTY, List.of())) + new IdentityService(Settings.EMPTY, threadPool, new ArrayList<>()), + new ExtensionsManager(Set.of(), new IdentityService(Settings.EMPTY, threadPool, List.of())) ); actionModule.initRestHandlers(null); // At this point the easiest way to confirm that a handler is loaded is to try to register another one on top of it and to fail diff --git a/server/src/test/java/org/opensearch/bootstrap/IdentityPluginTests.java b/server/src/test/java/org/opensearch/bootstrap/IdentityPluginTests.java index 2129810a99879..e08f8e71d42a7 100644 --- a/server/src/test/java/org/opensearch/bootstrap/IdentityPluginTests.java +++ b/server/src/test/java/org/opensearch/bootstrap/IdentityPluginTests.java @@ -15,6 +15,7 @@ import org.opensearch.identity.noop.NoopTokenManager; import org.opensearch.plugins.IdentityPlugin; import org.opensearch.test.OpenSearchTestCase; +import org.opensearch.threadpool.TestThreadPool; import java.util.List; @@ -24,19 +25,21 @@ public class IdentityPluginTests extends OpenSearchTestCase { public void testSingleIdentityPluginSucceeds() { - IdentityPlugin identityPlugin1 = new NoopIdentityPlugin(); + TestThreadPool threadPool = new TestThreadPool(getTestName()); + IdentityPlugin identityPlugin1 = new NoopIdentityPlugin(threadPool); List pluginList1 = List.of(identityPlugin1); - IdentityService identityService1 = new IdentityService(Settings.EMPTY, pluginList1); + IdentityService identityService1 = new IdentityService(Settings.EMPTY, threadPool, pluginList1); assertTrue(identityService1.getSubject().getPrincipal().getName().equalsIgnoreCase("Unauthenticated")); assertThat(identityService1.getTokenManager(), is(instanceOf(NoopTokenManager.class))); } public void testMultipleIdentityPluginsFail() { - IdentityPlugin identityPlugin1 = new NoopIdentityPlugin(); - IdentityPlugin identityPlugin2 = new NoopIdentityPlugin(); - IdentityPlugin identityPlugin3 = new NoopIdentityPlugin(); + TestThreadPool threadPool = new TestThreadPool(getTestName()); + IdentityPlugin identityPlugin1 = new NoopIdentityPlugin(threadPool); + IdentityPlugin identityPlugin2 = new NoopIdentityPlugin(threadPool); + IdentityPlugin identityPlugin3 = new NoopIdentityPlugin(threadPool); List pluginList = List.of(identityPlugin1, identityPlugin2, identityPlugin3); - Exception ex = assertThrows(OpenSearchException.class, () -> new IdentityService(Settings.EMPTY, pluginList)); + Exception ex = assertThrows(OpenSearchException.class, () -> new IdentityService(Settings.EMPTY, threadPool, pluginList)); assert (ex.getMessage().contains("Multiple identity plugins are not supported,")); } } diff --git a/server/src/test/java/org/opensearch/extensions/ExtensionsManagerTests.java b/server/src/test/java/org/opensearch/extensions/ExtensionsManagerTests.java index 3c25dbdff3342..5ae1bdce48cd5 100644 --- a/server/src/test/java/org/opensearch/extensions/ExtensionsManagerTests.java +++ b/server/src/test/java/org/opensearch/extensions/ExtensionsManagerTests.java @@ -154,7 +154,7 @@ public List> getExtensionSettings() { new NodeClient(Settings.EMPTY, threadPool), new NoneCircuitBreakerService(), new UsageService(), - new IdentityService(Settings.EMPTY, List.of()) + new IdentityService(Settings.EMPTY, threadPool, List.of()) ); when(actionModule.getDynamicActionRegistry()).thenReturn(mock(DynamicActionRegistry.class)); when(actionModule.getRestController()).thenReturn(restController); @@ -171,7 +171,7 @@ public List> getExtensionSettings() { Collections.emptyList() ); client = new NoOpNodeClient(this.getTestName()); - identityService = new IdentityService(Settings.EMPTY, List.of()); + identityService = new IdentityService(Settings.EMPTY, threadPool, List.of()); } @Override diff --git a/server/src/test/java/org/opensearch/extensions/rest/ExtensionRestRequestTests.java b/server/src/test/java/org/opensearch/extensions/rest/ExtensionRestRequestTests.java index 8b73f2e81972f..c0158a347a7c2 100644 --- a/server/src/test/java/org/opensearch/extensions/rest/ExtensionRestRequestTests.java +++ b/server/src/test/java/org/opensearch/extensions/rest/ExtensionRestRequestTests.java @@ -29,6 +29,7 @@ import org.opensearch.rest.BytesRestResponse; import org.opensearch.rest.RestRequest.Method; import org.opensearch.test.OpenSearchTestCase; +import org.opensearch.threadpool.ThreadPool; import java.nio.charset.StandardCharsets; import java.security.Principal; @@ -38,6 +39,7 @@ import java.util.Map; import static java.util.Map.entry; +import static org.mockito.Mockito.mock; public class ExtensionRestRequestTests extends OpenSearchTestCase { @@ -72,7 +74,7 @@ public void setUp() throws Exception { userPrincipal = () -> "user1"; expectedHttpVersion = HttpRequest.HttpVersion.HTTP_1_1; extensionTokenProcessor = "placeholder_extension_token_processor"; - identityService = new IdentityService(Settings.EMPTY, List.of()); + identityService = new IdentityService(Settings.EMPTY, mock(ThreadPool.class), List.of()); TokenManager tokenManager = identityService.getTokenManager(); Subject subject = this.identityService.getSubject(); OnBehalfOfClaims claims = new OnBehalfOfClaims("testID", subject.getPrincipal().getName()); diff --git a/server/src/test/java/org/opensearch/extensions/rest/RestInitializeExtensionActionTests.java b/server/src/test/java/org/opensearch/extensions/rest/RestInitializeExtensionActionTests.java index 0dae0ae1b4e0b..ac818c3bb4a7b 100644 --- a/server/src/test/java/org/opensearch/extensions/rest/RestInitializeExtensionActionTests.java +++ b/server/src/test/java/org/opensearch/extensions/rest/RestInitializeExtensionActionTests.java @@ -121,7 +121,7 @@ public void testRestInitializeExtensionActionResponse() throws Exception { } public void testRestInitializeExtensionActionFailure() throws Exception { - ExtensionsManager extensionsManager = new ExtensionsManager(Set.of(), new IdentityService(Settings.EMPTY, List.of())); + ExtensionsManager extensionsManager = new ExtensionsManager(Set.of(), new IdentityService(Settings.EMPTY, threadPool, List.of())); RestInitializeExtensionAction restInitializeExtensionAction = new RestInitializeExtensionAction(extensionsManager); final String content = "{\"name\":\"ad-extension\",\"uniqueId\":\"\",\"hostAddress\":\"127.0.0.1\"," @@ -156,7 +156,7 @@ public void testRestInitializeExtensionActionResponseWithAdditionalSettings() th ); ExtensionsManager extensionsManager = new ExtensionsManager( Set.of(boolSetting, stringSetting, intSetting, listSetting), - new IdentityService(Settings.EMPTY, List.of()) + new IdentityService(Settings.EMPTY, threadPool, List.of()) ); ExtensionsManager spy = spy(extensionsManager); @@ -206,7 +206,7 @@ public void testRestInitializeExtensionActionResponseWithAdditionalSettingsUsing ); ExtensionsManager extensionsManager = new ExtensionsManager( Set.of(boolSetting, stringSetting, intSetting, listSetting), - new IdentityService(Settings.EMPTY, List.of()) + new IdentityService(Settings.EMPTY, threadPool, List.of()) ); ExtensionsManager spy = spy(extensionsManager); diff --git a/server/src/test/java/org/opensearch/extensions/rest/RestSendToExtensionActionTests.java b/server/src/test/java/org/opensearch/extensions/rest/RestSendToExtensionActionTests.java index 9da976de7d7f6..6f74bdc487ef6 100644 --- a/server/src/test/java/org/opensearch/extensions/rest/RestSendToExtensionActionTests.java +++ b/server/src/test/java/org/opensearch/extensions/rest/RestSendToExtensionActionTests.java @@ -110,6 +110,7 @@ public void setup() throws Exception { ); SettingsModule settingsModule = new SettingsModule(settings); UsageService usageService = new UsageService(); + TestThreadPool threadPool = new TestThreadPool(getTestName()); actionModule = new ActionModule( settingsModule.getSettings(), new IndexNameExpressionResolver(new ThreadContext(Settings.EMPTY)), @@ -122,10 +123,10 @@ public void setup() throws Exception { null, usageService, null, - new IdentityService(Settings.EMPTY, new ArrayList<>()), - new ExtensionsManager(Set.of(), new IdentityService(Settings.EMPTY, List.of())) + new IdentityService(Settings.EMPTY, threadPool, new ArrayList<>()), + new ExtensionsManager(Set.of(), new IdentityService(Settings.EMPTY, threadPool, List.of())) ); - identityService = new IdentityService(Settings.EMPTY, new ArrayList<>()); + identityService = new IdentityService(Settings.EMPTY, threadPool, new ArrayList<>()); dynamicActionRegistry = actionModule.getDynamicActionRegistry(); } diff --git a/server/src/test/java/org/opensearch/identity/PluginSubjectTests.java b/server/src/test/java/org/opensearch/identity/PluginSubjectTests.java index 0d2d5d1d75f71..8cb57b7277fb5 100644 --- a/server/src/test/java/org/opensearch/identity/PluginSubjectTests.java +++ b/server/src/test/java/org/opensearch/identity/PluginSubjectTests.java @@ -36,10 +36,10 @@ public Subject getSubject() { public void testInitializeIdentityAwarePlugin() throws Exception { ThreadPool threadPool = new TestThreadPool(getTestName()); - IdentityService identityService = new IdentityService(Settings.EMPTY, List.of()); + IdentityService identityService = new IdentityService(Settings.EMPTY, threadPool, List.of()); TestPlugin testPlugin = new TestPlugin(); - identityService.initializeIdentityAwarePlugins(List.of(testPlugin), threadPool); + identityService.initializeIdentityAwarePlugins(List.of(testPlugin)); Subject testPluginSubject = new NoopPluginSubject(threadPool); assertThat(testPlugin.getSubject().getPrincipal().getName(), equalTo(NamedPrincipal.UNAUTHENTICATED.getName())); diff --git a/server/src/test/java/org/opensearch/rest/RestControllerTests.java b/server/src/test/java/org/opensearch/rest/RestControllerTests.java index b7239e7b59742..ef9257d746573 100644 --- a/server/src/test/java/org/opensearch/rest/RestControllerTests.java +++ b/server/src/test/java/org/opensearch/rest/RestControllerTests.java @@ -61,6 +61,7 @@ import org.opensearch.test.OpenSearchTestCase; import org.opensearch.test.client.NoOpNodeClient; import org.opensearch.test.rest.FakeRestRequest; +import org.opensearch.threadpool.ThreadPool; import org.opensearch.usage.UsageService; import org.junit.After; import org.junit.Before; @@ -114,7 +115,7 @@ public void setup() { // we can do this here only because we know that we don't adjust breaker settings dynamically in the test inFlightRequestsBreaker = circuitBreakerService.getBreaker(CircuitBreaker.IN_FLIGHT_REQUESTS); - identityService = new IdentityService(Settings.EMPTY, List.of()); + identityService = new IdentityService(Settings.EMPTY, mock(ThreadPool.class), List.of()); HttpServerTransport httpServerTransport = new TestHttpServerTransport(); client = new NoOpNodeClient(this.getTestName()); diff --git a/server/src/test/java/org/opensearch/rest/RestHttpResponseHeadersTests.java b/server/src/test/java/org/opensearch/rest/RestHttpResponseHeadersTests.java index 5d677247b8b6d..983121a4f481d 100644 --- a/server/src/test/java/org/opensearch/rest/RestHttpResponseHeadersTests.java +++ b/server/src/test/java/org/opensearch/rest/RestHttpResponseHeadersTests.java @@ -44,6 +44,7 @@ import org.opensearch.test.OpenSearchTestCase; import org.opensearch.test.rest.FakeRestChannel; import org.opensearch.test.rest.FakeRestRequest; +import org.opensearch.threadpool.ThreadPool; import org.opensearch.usage.UsageService; import java.util.ArrayList; @@ -55,6 +56,7 @@ import static org.hamcrest.CoreMatchers.notNullValue; import static org.hamcrest.Matchers.containsInAnyOrder; import static org.hamcrest.Matchers.is; +import static org.mockito.Mockito.mock; public class RestHttpResponseHeadersTests extends OpenSearchTestCase { @@ -106,7 +108,7 @@ public void testUnsupportedMethodResponseHttpHeader() throws Exception { final Settings settings = Settings.EMPTY; UsageService usageService = new UsageService(); - final IdentityService identityService = new IdentityService(settings, List.of()); + final IdentityService identityService = new IdentityService(settings, mock(ThreadPool.class), List.of()); RestController restController = new RestController( Collections.emptySet(), null, diff --git a/server/src/test/java/org/opensearch/rest/action/admin/indices/RestValidateQueryActionTests.java b/server/src/test/java/org/opensearch/rest/action/admin/indices/RestValidateQueryActionTests.java index 3fb6764846da6..c3cf33f4e9034 100644 --- a/server/src/test/java/org/opensearch/rest/action/admin/indices/RestValidateQueryActionTests.java +++ b/server/src/test/java/org/opensearch/rest/action/admin/indices/RestValidateQueryActionTests.java @@ -75,7 +75,7 @@ public class RestValidateQueryActionTests extends AbstractSearchTestCase { private static NodeClient client = new NodeClient(Settings.EMPTY, threadPool); private static UsageService usageService = new UsageService(); - private static IdentityService identityService = new IdentityService(Settings.EMPTY, List.of()); + private static IdentityService identityService = new IdentityService(Settings.EMPTY, threadPool, List.of()); private static RestController controller = new RestController( emptySet(), null, diff --git a/test/framework/src/main/java/org/opensearch/test/rest/RestActionTestCase.java b/test/framework/src/main/java/org/opensearch/test/rest/RestActionTestCase.java index a77865579f3b3..c7a0fe35b0237 100644 --- a/test/framework/src/main/java/org/opensearch/test/rest/RestActionTestCase.java +++ b/test/framework/src/main/java/org/opensearch/test/rest/RestActionTestCase.java @@ -47,6 +47,7 @@ import org.opensearch.tasks.TaskListener; import org.opensearch.test.OpenSearchTestCase; import org.opensearch.test.client.NoOpNodeClient; +import org.opensearch.threadpool.ThreadPool; import org.opensearch.usage.UsageService; import org.junit.After; import org.junit.Before; @@ -56,6 +57,8 @@ import java.util.concurrent.atomic.AtomicReference; import java.util.function.BiFunction; +import static org.mockito.Mockito.mock; + /** * A common base class for Rest*ActionTests. Provides access to a {@link RestController} * that can be used to register individual REST actions, and test request handling. @@ -67,7 +70,7 @@ public abstract class RestActionTestCase extends OpenSearchTestCase { @Before public void setUpController() { verifyingClient = new VerifyingClient(this.getTestName()); - final IdentityService identityService = new IdentityService(Settings.EMPTY, List.of()); + final IdentityService identityService = new IdentityService(Settings.EMPTY, mock(ThreadPool.class), List.of()); controller = new RestController( Collections.emptySet(), null, From 84c0cc3324dfc66bc12a5c6e9f8eb5594eda8b68 Mon Sep 17 00:00:00 2001 From: Craig Perkins Date: Fri, 16 Aug 2024 14:29:48 -0400 Subject: [PATCH 48/65] Make runAs generic Signed-off-by: Craig Perkins --- server/src/main/java/org/opensearch/identity/Subject.java | 3 ++- .../java/org/opensearch/identity/noop/NoopPluginSubject.java | 3 ++- 2 files changed, 4 insertions(+), 2 deletions(-) diff --git a/server/src/main/java/org/opensearch/identity/Subject.java b/server/src/main/java/org/opensearch/identity/Subject.java index a6bd7f9777481..349ce120244e4 100644 --- a/server/src/main/java/org/opensearch/identity/Subject.java +++ b/server/src/main/java/org/opensearch/identity/Subject.java @@ -36,7 +36,8 @@ public interface Subject { /** * runAs allows the caller to run a callable function as this subject */ - default void runAs(Callable callable) throws Exception { + default T runAs(Callable callable) throws Exception { callable.call(); + return null; }; } diff --git a/server/src/main/java/org/opensearch/identity/noop/NoopPluginSubject.java b/server/src/main/java/org/opensearch/identity/noop/NoopPluginSubject.java index f2d79d8a35d89..b8e25a1107afb 100644 --- a/server/src/main/java/org/opensearch/identity/noop/NoopPluginSubject.java +++ b/server/src/main/java/org/opensearch/identity/noop/NoopPluginSubject.java @@ -45,9 +45,10 @@ public void authenticate(AuthToken token) { } @Override - public void runAs(Callable callable) throws Exception { + public T runAs(Callable callable) throws Exception { try (ThreadContext.StoredContext ctx = threadPool.getThreadContext().stashContext()) { callable.call(); } + return null; } } From c200272cefeb70fc30239decd5966a41cab9fb79 Mon Sep 17 00:00:00 2001 From: Craig Perkins Date: Fri, 16 Aug 2024 15:08:05 -0400 Subject: [PATCH 49/65] package-private constructor Signed-off-by: Craig Perkins --- .../identity/shiro/ShiroIdentityPlugin.java | 5 +- .../identity/shiro/ShiroPluginSubject.java | 56 +++++++++++++++++++ .../identity/noop/NoopPluginSubject.java | 4 +- .../NoopPluginSubjectTests.java} | 8 ++- 4 files changed, 67 insertions(+), 6 deletions(-) create mode 100644 plugins/identity-shiro/src/main/java/org/opensearch/identity/shiro/ShiroPluginSubject.java rename server/src/test/java/org/opensearch/identity/{PluginSubjectTests.java => noop/NoopPluginSubjectTests.java} (89%) diff --git a/plugins/identity-shiro/src/main/java/org/opensearch/identity/shiro/ShiroIdentityPlugin.java b/plugins/identity-shiro/src/main/java/org/opensearch/identity/shiro/ShiroIdentityPlugin.java index 34d1746be72f1..06cfb360c4423 100644 --- a/plugins/identity-shiro/src/main/java/org/opensearch/identity/shiro/ShiroIdentityPlugin.java +++ b/plugins/identity-shiro/src/main/java/org/opensearch/identity/shiro/ShiroIdentityPlugin.java @@ -15,13 +15,13 @@ import org.opensearch.client.Client; import org.opensearch.cluster.metadata.IndexNameExpressionResolver; import org.opensearch.cluster.service.ClusterService; +import org.opensearch.common.annotation.ExperimentalApi; import org.opensearch.common.settings.Settings; import org.opensearch.core.common.io.stream.NamedWriteableRegistry; import org.opensearch.core.xcontent.NamedXContentRegistry; import org.opensearch.env.Environment; import org.opensearch.env.NodeEnvironment; import org.opensearch.identity.Subject; -import org.opensearch.identity.noop.NoopPluginSubject; import org.opensearch.identity.tokens.TokenManager; import org.opensearch.plugins.IdentityPlugin; import org.opensearch.plugins.Plugin; @@ -39,6 +39,7 @@ * * @opensearch.experimental */ +@ExperimentalApi public final class ShiroIdentityPlugin extends Plugin implements IdentityPlugin { private Logger log = LogManager.getLogger(this.getClass()); @@ -100,6 +101,6 @@ public TokenManager getTokenManager() { @Override public Subject getPluginSubject(Plugin plugin) { - return new NoopPluginSubject(threadPool); + return new ShiroPluginSubject(threadPool); } } diff --git a/plugins/identity-shiro/src/main/java/org/opensearch/identity/shiro/ShiroPluginSubject.java b/plugins/identity-shiro/src/main/java/org/opensearch/identity/shiro/ShiroPluginSubject.java new file mode 100644 index 0000000000000..64e5da4c7048e --- /dev/null +++ b/plugins/identity-shiro/src/main/java/org/opensearch/identity/shiro/ShiroPluginSubject.java @@ -0,0 +1,56 @@ +/* + * SPDX-License-Identifier: Apache-2.0 + * + * The OpenSearch Contributors require contributions made to + * this file be licensed under the Apache-2.0 license or a + * compatible open source license. + */ + +package org.opensearch.identity.shiro; + +import org.opensearch.common.annotation.ExperimentalApi; +import org.opensearch.common.util.concurrent.ThreadContext; +import org.opensearch.identity.NamedPrincipal; +import org.opensearch.identity.Subject; +import org.opensearch.identity.tokens.AuthToken; +import org.opensearch.threadpool.ThreadPool; + +import java.security.Principal; +import java.util.concurrent.Callable; + +/** + * Implementation of subject that is always authenticated + *

+ * This class and related classes in this package will not return nulls or fail permissions checks + * + * This class is used by the ShiroIdentityPlugin to initialize IdentityAwarePlugins + * + * @opensearch.experimental + */ +@ExperimentalApi +public class ShiroPluginSubject implements Subject { + private final ThreadPool threadPool; + + ShiroPluginSubject(ThreadPool threadPool) { + super(); + this.threadPool = threadPool; + } + + @Override + public Principal getPrincipal() { + return NamedPrincipal.UNAUTHENTICATED; + } + + @Override + public void authenticate(AuthToken token) { + // Do nothing as noop subject is always logged in + } + + @Override + public T runAs(Callable callable) throws Exception { + try (ThreadContext.StoredContext ctx = threadPool.getThreadContext().stashContext()) { + callable.call(); + } + return null; + } +} diff --git a/server/src/main/java/org/opensearch/identity/noop/NoopPluginSubject.java b/server/src/main/java/org/opensearch/identity/noop/NoopPluginSubject.java index b8e25a1107afb..50d2f84497e66 100644 --- a/server/src/main/java/org/opensearch/identity/noop/NoopPluginSubject.java +++ b/server/src/main/java/org/opensearch/identity/noop/NoopPluginSubject.java @@ -8,6 +8,7 @@ package org.opensearch.identity.noop; +import org.opensearch.common.annotation.InternalApi; import org.opensearch.common.util.concurrent.ThreadContext; import org.opensearch.identity.NamedPrincipal; import org.opensearch.identity.Subject; @@ -26,10 +27,11 @@ * * @opensearch.internal */ +@InternalApi public class NoopPluginSubject implements Subject { private final ThreadPool threadPool; - public NoopPluginSubject(ThreadPool threadPool) { + NoopPluginSubject(ThreadPool threadPool) { super(); this.threadPool = threadPool; } diff --git a/server/src/test/java/org/opensearch/identity/PluginSubjectTests.java b/server/src/test/java/org/opensearch/identity/noop/NoopPluginSubjectTests.java similarity index 89% rename from server/src/test/java/org/opensearch/identity/PluginSubjectTests.java rename to server/src/test/java/org/opensearch/identity/noop/NoopPluginSubjectTests.java index 8cb57b7277fb5..3756d94195687 100644 --- a/server/src/test/java/org/opensearch/identity/PluginSubjectTests.java +++ b/server/src/test/java/org/opensearch/identity/noop/NoopPluginSubjectTests.java @@ -6,10 +6,12 @@ * compatible open source license. */ -package org.opensearch.identity; +package org.opensearch.identity.noop; import org.opensearch.common.settings.Settings; -import org.opensearch.identity.noop.NoopPluginSubject; +import org.opensearch.identity.IdentityService; +import org.opensearch.identity.NamedPrincipal; +import org.opensearch.identity.Subject; import org.opensearch.plugins.IdentityAwarePlugin; import org.opensearch.plugins.Plugin; import org.opensearch.test.OpenSearchTestCase; @@ -20,7 +22,7 @@ import static org.hamcrest.Matchers.equalTo; -public class PluginSubjectTests extends OpenSearchTestCase { +public class NoopPluginSubjectTests extends OpenSearchTestCase { public static class TestPlugin extends Plugin implements IdentityAwarePlugin { private Subject subject; From be9b3cc69215624fa2f051af34083c9171fff592 Mon Sep 17 00:00:00 2001 From: Craig Perkins Date: Fri, 16 Aug 2024 15:18:06 -0400 Subject: [PATCH 50/65] Move IdentityAwarePlugin initialization Signed-off-by: Craig Perkins --- server/src/main/java/org/opensearch/node/Node.java | 5 +++-- 1 file changed, 3 insertions(+), 2 deletions(-) diff --git a/server/src/main/java/org/opensearch/node/Node.java b/server/src/main/java/org/opensearch/node/Node.java index 132a46b9b87e4..1dfe77093f051 100644 --- a/server/src/main/java/org/opensearch/node/Node.java +++ b/server/src/main/java/org/opensearch/node/Node.java @@ -713,8 +713,6 @@ protected Node( repositoriesServiceReference::get, rerouteServiceReference::get ); - List identityAwarePlugins = pluginsService.filterPlugins(IdentityAwarePlugin.class); - identityService.initializeIdentityAwarePlugins(identityAwarePlugins); final Map> systemIndexDescriptorMap = Collections.unmodifiableMap( pluginsService.filterPlugins(SystemIndexPlugin.class) .stream() @@ -1014,6 +1012,9 @@ protected Node( // Add the telemetryAwarePlugin components to the existing pluginComponents collection. pluginComponents.addAll(telemetryAwarePluginComponents); + List identityAwarePlugins = pluginsService.filterPlugins(IdentityAwarePlugin.class); + identityService.initializeIdentityAwarePlugins(identityAwarePlugins); + // register all standard SearchRequestOperationsCompositeListenerFactory to the SearchRequestOperationsCompositeListenerFactory final SearchRequestOperationsCompositeListenerFactory searchRequestOperationsCompositeListenerFactory = new SearchRequestOperationsCompositeListenerFactory( From 9c07676e43d6161120f56557eaa5d15b3fe9da7e Mon Sep 17 00:00:00 2001 From: Craig Perkins Date: Fri, 16 Aug 2024 15:36:01 -0400 Subject: [PATCH 51/65] Create separate PluginSubject interface Signed-off-by: Craig Perkins --- .../identity/shiro/ShiroIdentityPlugin.java | 3 +- .../identity/shiro/ShiroPluginSubject.java | 4 +-- .../opensearch/identity/IdentityService.java | 4 +-- .../opensearch/identity/PluginSubject.java | 36 +++++++++++++++++++ .../identity/noop/NoopIdentityPlugin.java | 3 +- .../identity/noop/NoopPluginSubject.java | 10 ++---- .../plugins/IdentityAwarePlugin.java | 3 +- .../opensearch/plugins/IdentityPlugin.java | 3 +- .../identity/noop/NoopPluginSubjectTests.java | 10 +++--- 9 files changed, 55 insertions(+), 21 deletions(-) create mode 100644 server/src/main/java/org/opensearch/identity/PluginSubject.java diff --git a/plugins/identity-shiro/src/main/java/org/opensearch/identity/shiro/ShiroIdentityPlugin.java b/plugins/identity-shiro/src/main/java/org/opensearch/identity/shiro/ShiroIdentityPlugin.java index 06cfb360c4423..658040ef7206a 100644 --- a/plugins/identity-shiro/src/main/java/org/opensearch/identity/shiro/ShiroIdentityPlugin.java +++ b/plugins/identity-shiro/src/main/java/org/opensearch/identity/shiro/ShiroIdentityPlugin.java @@ -21,6 +21,7 @@ import org.opensearch.core.xcontent.NamedXContentRegistry; import org.opensearch.env.Environment; import org.opensearch.env.NodeEnvironment; +import org.opensearch.identity.PluginSubject; import org.opensearch.identity.Subject; import org.opensearch.identity.tokens.TokenManager; import org.opensearch.plugins.IdentityPlugin; @@ -100,7 +101,7 @@ public TokenManager getTokenManager() { } @Override - public Subject getPluginSubject(Plugin plugin) { + public PluginSubject getPluginSubject(Plugin plugin) { return new ShiroPluginSubject(threadPool); } } diff --git a/plugins/identity-shiro/src/main/java/org/opensearch/identity/shiro/ShiroPluginSubject.java b/plugins/identity-shiro/src/main/java/org/opensearch/identity/shiro/ShiroPluginSubject.java index 64e5da4c7048e..81eaaa642d058 100644 --- a/plugins/identity-shiro/src/main/java/org/opensearch/identity/shiro/ShiroPluginSubject.java +++ b/plugins/identity-shiro/src/main/java/org/opensearch/identity/shiro/ShiroPluginSubject.java @@ -11,7 +11,7 @@ import org.opensearch.common.annotation.ExperimentalApi; import org.opensearch.common.util.concurrent.ThreadContext; import org.opensearch.identity.NamedPrincipal; -import org.opensearch.identity.Subject; +import org.opensearch.identity.PluginSubject; import org.opensearch.identity.tokens.AuthToken; import org.opensearch.threadpool.ThreadPool; @@ -28,7 +28,7 @@ * @opensearch.experimental */ @ExperimentalApi -public class ShiroPluginSubject implements Subject { +public class ShiroPluginSubject implements PluginSubject { private final ThreadPool threadPool; ShiroPluginSubject(ThreadPool threadPool) { diff --git a/server/src/main/java/org/opensearch/identity/IdentityService.java b/server/src/main/java/org/opensearch/identity/IdentityService.java index ed9b14c7d0368..5e9c146fbd2f5 100644 --- a/server/src/main/java/org/opensearch/identity/IdentityService.java +++ b/server/src/main/java/org/opensearch/identity/IdentityService.java @@ -64,8 +64,8 @@ public TokenManager getTokenManager() { public void initializeIdentityAwarePlugins(final List identityAwarePlugins) { if (identityAwarePlugins != null) { for (IdentityAwarePlugin plugin : identityAwarePlugins) { - Subject subject = identityPlugin.getPluginSubject((Plugin) plugin); - plugin.assignSubject(subject); + PluginSubject pluginSubject = identityPlugin.getPluginSubject((Plugin) plugin); + plugin.assignSubject(pluginSubject); } } } diff --git a/server/src/main/java/org/opensearch/identity/PluginSubject.java b/server/src/main/java/org/opensearch/identity/PluginSubject.java new file mode 100644 index 0000000000000..290c27b23468b --- /dev/null +++ b/server/src/main/java/org/opensearch/identity/PluginSubject.java @@ -0,0 +1,36 @@ +/* + * SPDX-License-Identifier: Apache-2.0 + * + * The OpenSearch Contributors require contributions made to + * this file be licensed under the Apache-2.0 license or a + * compatible open source license. + */ + +package org.opensearch.identity; + +import org.opensearch.common.annotation.ExperimentalApi; + +import java.security.Principal; +import java.util.concurrent.Callable; + +/** + * Similar to {@link Subject}, but represents a plugin executing actions + * + * @opensearch.experimental + */ +@ExperimentalApi +public interface PluginSubject { + + /** + * Get the application-wide uniquely identifying principal + * */ + Principal getPrincipal(); + + /** + * runAs allows the caller to run a callable function as this subject + */ + default T runAs(Callable callable) throws Exception { + callable.call(); + return null; + }; +} diff --git a/server/src/main/java/org/opensearch/identity/noop/NoopIdentityPlugin.java b/server/src/main/java/org/opensearch/identity/noop/NoopIdentityPlugin.java index a66e5a6a12781..15ee4af9cefbd 100644 --- a/server/src/main/java/org/opensearch/identity/noop/NoopIdentityPlugin.java +++ b/server/src/main/java/org/opensearch/identity/noop/NoopIdentityPlugin.java @@ -8,6 +8,7 @@ package org.opensearch.identity.noop; +import org.opensearch.identity.PluginSubject; import org.opensearch.identity.Subject; import org.opensearch.identity.tokens.TokenManager; import org.opensearch.plugins.IdentityPlugin; @@ -48,7 +49,7 @@ public TokenManager getTokenManager() { } @Override - public Subject getPluginSubject(Plugin plugin) { + public PluginSubject getPluginSubject(Plugin plugin) { return new NoopPluginSubject(threadPool); } } diff --git a/server/src/main/java/org/opensearch/identity/noop/NoopPluginSubject.java b/server/src/main/java/org/opensearch/identity/noop/NoopPluginSubject.java index 50d2f84497e66..fdfab255a8c43 100644 --- a/server/src/main/java/org/opensearch/identity/noop/NoopPluginSubject.java +++ b/server/src/main/java/org/opensearch/identity/noop/NoopPluginSubject.java @@ -11,8 +11,7 @@ import org.opensearch.common.annotation.InternalApi; import org.opensearch.common.util.concurrent.ThreadContext; import org.opensearch.identity.NamedPrincipal; -import org.opensearch.identity.Subject; -import org.opensearch.identity.tokens.AuthToken; +import org.opensearch.identity.PluginSubject; import org.opensearch.threadpool.ThreadPool; import java.security.Principal; @@ -28,7 +27,7 @@ * @opensearch.internal */ @InternalApi -public class NoopPluginSubject implements Subject { +public class NoopPluginSubject implements PluginSubject { private final ThreadPool threadPool; NoopPluginSubject(ThreadPool threadPool) { @@ -41,11 +40,6 @@ public Principal getPrincipal() { return NamedPrincipal.UNAUTHENTICATED; } - @Override - public void authenticate(AuthToken token) { - // Do nothing as noop subject is always logged in - } - @Override public T runAs(Callable callable) throws Exception { try (ThreadContext.StoredContext ctx = threadPool.getThreadContext().stashContext()) { diff --git a/server/src/main/java/org/opensearch/plugins/IdentityAwarePlugin.java b/server/src/main/java/org/opensearch/plugins/IdentityAwarePlugin.java index a0a3b336e16ae..9000392d44a37 100644 --- a/server/src/main/java/org/opensearch/plugins/IdentityAwarePlugin.java +++ b/server/src/main/java/org/opensearch/plugins/IdentityAwarePlugin.java @@ -9,6 +9,7 @@ package org.opensearch.plugins; import org.opensearch.common.annotation.ExperimentalApi; +import org.opensearch.identity.PluginSubject; import org.opensearch.identity.Subject; /** @@ -29,5 +30,5 @@ public interface IdentityAwarePlugin { * @param pluginSystemSubject A subject for running transport actions in the plugin system context for system index * interaction */ - default void assignSubject(Subject pluginSystemSubject) {} + default void assignSubject(PluginSubject pluginSystemSubject) {} } diff --git a/server/src/main/java/org/opensearch/plugins/IdentityPlugin.java b/server/src/main/java/org/opensearch/plugins/IdentityPlugin.java index 6dd6c97bbbf33..74d079e358a92 100644 --- a/server/src/main/java/org/opensearch/plugins/IdentityPlugin.java +++ b/server/src/main/java/org/opensearch/plugins/IdentityPlugin.java @@ -9,6 +9,7 @@ package org.opensearch.plugins; import org.opensearch.common.annotation.ExperimentalApi; +import org.opensearch.identity.PluginSubject; import org.opensearch.identity.Subject; import org.opensearch.identity.tokens.TokenManager; @@ -39,5 +40,5 @@ public interface IdentityPlugin { * @param plugin The corresponding plugin * @return Subject corresponding to the plugin */ - Subject getPluginSubject(Plugin plugin); + PluginSubject getPluginSubject(Plugin plugin); } diff --git a/server/src/test/java/org/opensearch/identity/noop/NoopPluginSubjectTests.java b/server/src/test/java/org/opensearch/identity/noop/NoopPluginSubjectTests.java index 3756d94195687..79c26a7eb790d 100644 --- a/server/src/test/java/org/opensearch/identity/noop/NoopPluginSubjectTests.java +++ b/server/src/test/java/org/opensearch/identity/noop/NoopPluginSubjectTests.java @@ -11,7 +11,7 @@ import org.opensearch.common.settings.Settings; import org.opensearch.identity.IdentityService; import org.opensearch.identity.NamedPrincipal; -import org.opensearch.identity.Subject; +import org.opensearch.identity.PluginSubject; import org.opensearch.plugins.IdentityAwarePlugin; import org.opensearch.plugins.Plugin; import org.opensearch.test.OpenSearchTestCase; @@ -24,14 +24,14 @@ public class NoopPluginSubjectTests extends OpenSearchTestCase { public static class TestPlugin extends Plugin implements IdentityAwarePlugin { - private Subject subject; + private PluginSubject subject; @Override - public void assignSubject(Subject subject) { + public void assignSubject(PluginSubject subject) { this.subject = subject; } - public Subject getSubject() { + public PluginSubject getSubject() { return subject; } } @@ -43,7 +43,7 @@ public void testInitializeIdentityAwarePlugin() throws Exception { TestPlugin testPlugin = new TestPlugin(); identityService.initializeIdentityAwarePlugins(List.of(testPlugin)); - Subject testPluginSubject = new NoopPluginSubject(threadPool); + PluginSubject testPluginSubject = new NoopPluginSubject(threadPool); assertThat(testPlugin.getSubject().getPrincipal().getName(), equalTo(NamedPrincipal.UNAUTHENTICATED.getName())); assertThat(testPluginSubject.getPrincipal().getName(), equalTo(NamedPrincipal.UNAUTHENTICATED.getName())); threadPool.getThreadContext().putHeader("test_header", "foo"); From 901d53dca54df9a5ae2d0ffe159de40f430bcf38 Mon Sep 17 00:00:00 2001 From: Craig Perkins Date: Fri, 16 Aug 2024 15:47:27 -0400 Subject: [PATCH 52/65] Remove authenticate method Signed-off-by: Craig Perkins --- .../org/opensearch/identity/shiro/ShiroPluginSubject.java | 5 ----- 1 file changed, 5 deletions(-) diff --git a/plugins/identity-shiro/src/main/java/org/opensearch/identity/shiro/ShiroPluginSubject.java b/plugins/identity-shiro/src/main/java/org/opensearch/identity/shiro/ShiroPluginSubject.java index 81eaaa642d058..c81453401d9e4 100644 --- a/plugins/identity-shiro/src/main/java/org/opensearch/identity/shiro/ShiroPluginSubject.java +++ b/plugins/identity-shiro/src/main/java/org/opensearch/identity/shiro/ShiroPluginSubject.java @@ -41,11 +41,6 @@ public Principal getPrincipal() { return NamedPrincipal.UNAUTHENTICATED; } - @Override - public void authenticate(AuthToken token) { - // Do nothing as noop subject is always logged in - } - @Override public T runAs(Callable callable) throws Exception { try (ThreadContext.StoredContext ctx = threadPool.getThreadContext().stashContext()) { From 55834df8dad468f7f2f23343838adea56d052b73 Mon Sep 17 00:00:00 2001 From: Craig Perkins Date: Fri, 16 Aug 2024 15:48:43 -0400 Subject: [PATCH 53/65] Remove import Signed-off-by: Craig Perkins --- .../java/org/opensearch/identity/shiro/ShiroPluginSubject.java | 1 - 1 file changed, 1 deletion(-) diff --git a/plugins/identity-shiro/src/main/java/org/opensearch/identity/shiro/ShiroPluginSubject.java b/plugins/identity-shiro/src/main/java/org/opensearch/identity/shiro/ShiroPluginSubject.java index c81453401d9e4..595ee188f7424 100644 --- a/plugins/identity-shiro/src/main/java/org/opensearch/identity/shiro/ShiroPluginSubject.java +++ b/plugins/identity-shiro/src/main/java/org/opensearch/identity/shiro/ShiroPluginSubject.java @@ -12,7 +12,6 @@ import org.opensearch.common.util.concurrent.ThreadContext; import org.opensearch.identity.NamedPrincipal; import org.opensearch.identity.PluginSubject; -import org.opensearch.identity.tokens.AuthToken; import org.opensearch.threadpool.ThreadPool; import java.security.Principal; From 7374479938f892fc2ab9af9cd27d967b4086f9d1 Mon Sep 17 00:00:00 2001 From: Craig Perkins Date: Fri, 16 Aug 2024 16:02:44 -0400 Subject: [PATCH 54/65] Separate UserSubject and PluginSubject Signed-off-by: Craig Perkins --- .../identity/shiro/ShiroIdentityPlugin.java | 4 +-- .../identity/shiro/ShiroSubject.java | 3 +- .../rest/RestSendToExtensionAction.java | 2 +- .../opensearch/identity/IdentityService.java | 6 ++-- .../opensearch/identity/PluginSubject.java | 19 +----------- .../java/org/opensearch/identity/Subject.java | 10 ------- .../org/opensearch/identity/UserSubject.java | 29 +++++++++++++++++++ .../identity/noop/NoopIdentityPlugin.java | 4 +-- .../opensearch/identity/noop/NoopSubject.java | 3 +- .../opensearch/plugins/IdentityPlugin.java | 7 +++-- .../org/opensearch/rest/RestController.java | 4 +-- .../bootstrap/IdentityPluginTests.java | 2 +- .../rest/ExtensionRestRequestTests.java | 4 +-- 13 files changed, 51 insertions(+), 46 deletions(-) create mode 100644 server/src/main/java/org/opensearch/identity/UserSubject.java diff --git a/plugins/identity-shiro/src/main/java/org/opensearch/identity/shiro/ShiroIdentityPlugin.java b/plugins/identity-shiro/src/main/java/org/opensearch/identity/shiro/ShiroIdentityPlugin.java index 658040ef7206a..435b0acdb06af 100644 --- a/plugins/identity-shiro/src/main/java/org/opensearch/identity/shiro/ShiroIdentityPlugin.java +++ b/plugins/identity-shiro/src/main/java/org/opensearch/identity/shiro/ShiroIdentityPlugin.java @@ -22,7 +22,7 @@ import org.opensearch.env.Environment; import org.opensearch.env.NodeEnvironment; import org.opensearch.identity.PluginSubject; -import org.opensearch.identity.Subject; +import org.opensearch.identity.UserSubject; import org.opensearch.identity.tokens.TokenManager; import org.opensearch.plugins.IdentityPlugin; import org.opensearch.plugins.Plugin; @@ -86,7 +86,7 @@ public Collection createComponents( * @return The current subject */ @Override - public Subject getSubject() { + public UserSubject getUserSubject() { return new ShiroSubject(authTokenHandler, SecurityUtils.getSubject()); } diff --git a/plugins/identity-shiro/src/main/java/org/opensearch/identity/shiro/ShiroSubject.java b/plugins/identity-shiro/src/main/java/org/opensearch/identity/shiro/ShiroSubject.java index e55204593621c..72a168f23c5cd 100644 --- a/plugins/identity-shiro/src/main/java/org/opensearch/identity/shiro/ShiroSubject.java +++ b/plugins/identity-shiro/src/main/java/org/opensearch/identity/shiro/ShiroSubject.java @@ -9,6 +9,7 @@ package org.opensearch.identity.shiro; import org.opensearch.identity.Subject; +import org.opensearch.identity.UserSubject; import org.opensearch.identity.tokens.AuthToken; import java.security.Principal; @@ -19,7 +20,7 @@ * * @opensearch.experimental */ -public class ShiroSubject implements Subject { +public class ShiroSubject implements UserSubject { private final ShiroTokenManager authTokenHandler; private final org.apache.shiro.subject.Subject shiroSubject; diff --git a/server/src/main/java/org/opensearch/extensions/rest/RestSendToExtensionAction.java b/server/src/main/java/org/opensearch/extensions/rest/RestSendToExtensionAction.java index f4503ce55e6bc..2e64ded6c5158 100644 --- a/server/src/main/java/org/opensearch/extensions/rest/RestSendToExtensionAction.java +++ b/server/src/main/java/org/opensearch/extensions/rest/RestSendToExtensionAction.java @@ -249,7 +249,7 @@ public String executor() { Map> filteredHeaders = filterHeaders(headers, allowList, denyList); TokenManager tokenManager = identityService.getTokenManager(); - Subject subject = this.identityService.getSubject(); + Subject subject = this.identityService.getUserSubject(); OnBehalfOfClaims claims = new OnBehalfOfClaims(discoveryExtensionNode.getId(), subject.getPrincipal().getName()); transportService.sendRequest( diff --git a/server/src/main/java/org/opensearch/identity/IdentityService.java b/server/src/main/java/org/opensearch/identity/IdentityService.java index 5e9c146fbd2f5..186b30020c676 100644 --- a/server/src/main/java/org/opensearch/identity/IdentityService.java +++ b/server/src/main/java/org/opensearch/identity/IdentityService.java @@ -48,10 +48,10 @@ public IdentityService(final Settings settings, final ThreadPool threadPool, fin } /** - * Gets the current Subject + * Gets the current UserSubject */ - public Subject getSubject() { - return identityPlugin.getSubject(); + public UserSubject getUserSubject() { + return identityPlugin.getUserSubject(); } /** diff --git a/server/src/main/java/org/opensearch/identity/PluginSubject.java b/server/src/main/java/org/opensearch/identity/PluginSubject.java index 290c27b23468b..3ea42182d3fc3 100644 --- a/server/src/main/java/org/opensearch/identity/PluginSubject.java +++ b/server/src/main/java/org/opensearch/identity/PluginSubject.java @@ -10,27 +10,10 @@ import org.opensearch.common.annotation.ExperimentalApi; -import java.security.Principal; -import java.util.concurrent.Callable; - /** * Similar to {@link Subject}, but represents a plugin executing actions * * @opensearch.experimental */ @ExperimentalApi -public interface PluginSubject { - - /** - * Get the application-wide uniquely identifying principal - * */ - Principal getPrincipal(); - - /** - * runAs allows the caller to run a callable function as this subject - */ - default T runAs(Callable callable) throws Exception { - callable.call(); - return null; - }; -} +public interface PluginSubject extends Subject {} diff --git a/server/src/main/java/org/opensearch/identity/Subject.java b/server/src/main/java/org/opensearch/identity/Subject.java index 349ce120244e4..e138ab7a957ca 100644 --- a/server/src/main/java/org/opensearch/identity/Subject.java +++ b/server/src/main/java/org/opensearch/identity/Subject.java @@ -6,7 +6,6 @@ package org.opensearch.identity; import org.opensearch.common.annotation.ExperimentalApi; -import org.opensearch.identity.tokens.AuthToken; import java.security.Principal; import java.util.concurrent.Callable; @@ -24,15 +23,6 @@ public interface Subject { * */ Principal getPrincipal(); - /** - * Authenticate via an auth token - * throws UnsupportedAuthenticationMethod - * throws InvalidAuthenticationToken - * throws SubjectNotFound - * throws SubjectDisabled - */ - void authenticate(final AuthToken token); - /** * runAs allows the caller to run a callable function as this subject */ diff --git a/server/src/main/java/org/opensearch/identity/UserSubject.java b/server/src/main/java/org/opensearch/identity/UserSubject.java new file mode 100644 index 0000000000000..50f8ac6b37be3 --- /dev/null +++ b/server/src/main/java/org/opensearch/identity/UserSubject.java @@ -0,0 +1,29 @@ +/* + * SPDX-License-Identifier: Apache-2.0 + * + * The OpenSearch Contributors require contributions made to + * this file be licensed under the Apache-2.0 license or a + * compatible open source license. + */ + +package org.opensearch.identity; + +import org.opensearch.common.annotation.ExperimentalApi; +import org.opensearch.identity.tokens.AuthToken; + +/** + * An instance of a subject representing a User. UserSubjects must pass credentials for authentication. + * + * @opensearch.experimental + */ +@ExperimentalApi +public interface UserSubject extends Subject { + /** + * Authenticate via an auth token + * throws UnsupportedAuthenticationMethod + * throws InvalidAuthenticationToken + * throws SubjectNotFound + * throws SubjectDisabled + */ + void authenticate(final AuthToken token); +} diff --git a/server/src/main/java/org/opensearch/identity/noop/NoopIdentityPlugin.java b/server/src/main/java/org/opensearch/identity/noop/NoopIdentityPlugin.java index 15ee4af9cefbd..80f8c06728067 100644 --- a/server/src/main/java/org/opensearch/identity/noop/NoopIdentityPlugin.java +++ b/server/src/main/java/org/opensearch/identity/noop/NoopIdentityPlugin.java @@ -9,7 +9,7 @@ package org.opensearch.identity.noop; import org.opensearch.identity.PluginSubject; -import org.opensearch.identity.Subject; +import org.opensearch.identity.UserSubject; import org.opensearch.identity.tokens.TokenManager; import org.opensearch.plugins.IdentityPlugin; import org.opensearch.plugins.Plugin; @@ -35,7 +35,7 @@ public NoopIdentityPlugin(ThreadPool threadPool) { * @return Must never return null */ @Override - public Subject getSubject() { + public UserSubject getUserSubject() { return new NoopSubject(); } diff --git a/server/src/main/java/org/opensearch/identity/noop/NoopSubject.java b/server/src/main/java/org/opensearch/identity/noop/NoopSubject.java index 964a218db3cf5..fda88a8b7e8af 100644 --- a/server/src/main/java/org/opensearch/identity/noop/NoopSubject.java +++ b/server/src/main/java/org/opensearch/identity/noop/NoopSubject.java @@ -10,6 +10,7 @@ import org.opensearch.identity.NamedPrincipal; import org.opensearch.identity.Subject; +import org.opensearch.identity.UserSubject; import org.opensearch.identity.tokens.AuthToken; import java.security.Principal; @@ -22,7 +23,7 @@ * * @opensearch.internal */ -public class NoopSubject implements Subject { +public class NoopSubject implements UserSubject { @Override public Principal getPrincipal() { diff --git a/server/src/main/java/org/opensearch/plugins/IdentityPlugin.java b/server/src/main/java/org/opensearch/plugins/IdentityPlugin.java index 74d079e358a92..1e5584051cdc7 100644 --- a/server/src/main/java/org/opensearch/plugins/IdentityPlugin.java +++ b/server/src/main/java/org/opensearch/plugins/IdentityPlugin.java @@ -10,7 +10,7 @@ import org.opensearch.common.annotation.ExperimentalApi; import org.opensearch.identity.PluginSubject; -import org.opensearch.identity.Subject; +import org.opensearch.identity.UserSubject; import org.opensearch.identity.tokens.TokenManager; /** @@ -22,10 +22,11 @@ public interface IdentityPlugin { /** - * Get the current subject. + * Get the current user subject. + * * @return Should never return null * */ - Subject getSubject(); + UserSubject getUserSubject(); /** * Get the Identity Plugin's token manager implementation diff --git a/server/src/main/java/org/opensearch/rest/RestController.java b/server/src/main/java/org/opensearch/rest/RestController.java index 7d0c1e2260de1..197c998a9b714 100644 --- a/server/src/main/java/org/opensearch/rest/RestController.java +++ b/server/src/main/java/org/opensearch/rest/RestController.java @@ -57,7 +57,7 @@ import org.opensearch.http.HttpChunk; import org.opensearch.http.HttpServerTransport; import org.opensearch.identity.IdentityService; -import org.opensearch.identity.Subject; +import org.opensearch.identity.UserSubject; import org.opensearch.identity.tokens.AuthToken; import org.opensearch.identity.tokens.RestTokenExtractor; import org.opensearch.usage.UsageService; @@ -593,7 +593,7 @@ private boolean handleAuthenticateUser(final RestRequest request, final RestChan // Authentication did not fail so return true. Authorization is handled at the action level. return true; } - final Subject currentSubject = identityService.getSubject(); + final UserSubject currentSubject = identityService.getUserSubject(); currentSubject.authenticate(token); logger.debug("Logged in as user " + currentSubject); } catch (final Exception e) { diff --git a/server/src/test/java/org/opensearch/bootstrap/IdentityPluginTests.java b/server/src/test/java/org/opensearch/bootstrap/IdentityPluginTests.java index e08f8e71d42a7..ae17a90cacc77 100644 --- a/server/src/test/java/org/opensearch/bootstrap/IdentityPluginTests.java +++ b/server/src/test/java/org/opensearch/bootstrap/IdentityPluginTests.java @@ -29,7 +29,7 @@ public void testSingleIdentityPluginSucceeds() { IdentityPlugin identityPlugin1 = new NoopIdentityPlugin(threadPool); List pluginList1 = List.of(identityPlugin1); IdentityService identityService1 = new IdentityService(Settings.EMPTY, threadPool, pluginList1); - assertTrue(identityService1.getSubject().getPrincipal().getName().equalsIgnoreCase("Unauthenticated")); + assertTrue(identityService1.getUserSubject().getPrincipal().getName().equalsIgnoreCase("Unauthenticated")); assertThat(identityService1.getTokenManager(), is(instanceOf(NoopTokenManager.class))); } diff --git a/server/src/test/java/org/opensearch/extensions/rest/ExtensionRestRequestTests.java b/server/src/test/java/org/opensearch/extensions/rest/ExtensionRestRequestTests.java index c0158a347a7c2..e9fc561632a8f 100644 --- a/server/src/test/java/org/opensearch/extensions/rest/ExtensionRestRequestTests.java +++ b/server/src/test/java/org/opensearch/extensions/rest/ExtensionRestRequestTests.java @@ -76,10 +76,10 @@ public void setUp() throws Exception { extensionTokenProcessor = "placeholder_extension_token_processor"; identityService = new IdentityService(Settings.EMPTY, mock(ThreadPool.class), List.of()); TokenManager tokenManager = identityService.getTokenManager(); - Subject subject = this.identityService.getSubject(); + Subject subject = this.identityService.getUserSubject(); OnBehalfOfClaims claims = new OnBehalfOfClaims("testID", subject.getPrincipal().getName()); expectedRequestIssuerIdentity = identityService.getTokenManager() - .issueOnBehalfOfToken(identityService.getSubject(), claims) + .issueOnBehalfOfToken(identityService.getUserSubject(), claims) .asAuthHeaderValue(); } From efac9192ed3bcdcdfd7a0e0496dbc142d032c0e7 Mon Sep 17 00:00:00 2001 From: Craig Perkins Date: Fri, 16 Aug 2024 16:28:08 -0400 Subject: [PATCH 55/65] Terminate TestThreadPool Signed-off-by: Craig Perkins --- .../org/opensearch/identity/shiro/ShiroIdentityPluginTests.java | 2 ++ .../test/java/org/opensearch/bootstrap/IdentityPluginTests.java | 2 ++ 2 files changed, 4 insertions(+) diff --git a/plugins/identity-shiro/src/test/java/org/opensearch/identity/shiro/ShiroIdentityPluginTests.java b/plugins/identity-shiro/src/test/java/org/opensearch/identity/shiro/ShiroIdentityPluginTests.java index cb09590918278..bc14410d81de0 100644 --- a/plugins/identity-shiro/src/test/java/org/opensearch/identity/shiro/ShiroIdentityPluginTests.java +++ b/plugins/identity-shiro/src/test/java/org/opensearch/identity/shiro/ShiroIdentityPluginTests.java @@ -30,6 +30,7 @@ public void testSingleIdentityPluginSucceeds() { List pluginList1 = List.of(identityPlugin1); IdentityService identityService1 = new IdentityService(Settings.EMPTY, threadPool, pluginList1); assertThat(identityService1.getTokenManager(), is(instanceOf(ShiroTokenManager.class))); + terminate(threadPool); } public void testMultipleIdentityPluginsFail() { @@ -40,6 +41,7 @@ public void testMultipleIdentityPluginsFail() { List pluginList = List.of(identityPlugin1, identityPlugin2, identityPlugin3); Exception ex = assertThrows(OpenSearchException.class, () -> new IdentityService(Settings.EMPTY, threadPool, pluginList)); assert (ex.getMessage().contains("Multiple identity plugins are not supported,")); + terminate(threadPool); } } diff --git a/server/src/test/java/org/opensearch/bootstrap/IdentityPluginTests.java b/server/src/test/java/org/opensearch/bootstrap/IdentityPluginTests.java index ae17a90cacc77..d4064dd7d3c1a 100644 --- a/server/src/test/java/org/opensearch/bootstrap/IdentityPluginTests.java +++ b/server/src/test/java/org/opensearch/bootstrap/IdentityPluginTests.java @@ -31,6 +31,7 @@ public void testSingleIdentityPluginSucceeds() { IdentityService identityService1 = new IdentityService(Settings.EMPTY, threadPool, pluginList1); assertTrue(identityService1.getUserSubject().getPrincipal().getName().equalsIgnoreCase("Unauthenticated")); assertThat(identityService1.getTokenManager(), is(instanceOf(NoopTokenManager.class))); + terminate(threadPool); } public void testMultipleIdentityPluginsFail() { @@ -41,5 +42,6 @@ public void testMultipleIdentityPluginsFail() { List pluginList = List.of(identityPlugin1, identityPlugin2, identityPlugin3); Exception ex = assertThrows(OpenSearchException.class, () -> new IdentityService(Settings.EMPTY, threadPool, pluginList)); assert (ex.getMessage().contains("Multiple identity plugins are not supported,")); + terminate(threadPool); } } From 1536380c5ce6f84f86207a6191bf7655eba9bf60 Mon Sep 17 00:00:00 2001 From: Craig Perkins Date: Fri, 16 Aug 2024 16:44:38 -0400 Subject: [PATCH 56/65] mock ThreadPool in RestSendToExtensionActionTests Signed-off-by: Craig Perkins --- .../extensions/rest/RestSendToExtensionActionTests.java | 7 +++---- 1 file changed, 3 insertions(+), 4 deletions(-) diff --git a/server/src/test/java/org/opensearch/extensions/rest/RestSendToExtensionActionTests.java b/server/src/test/java/org/opensearch/extensions/rest/RestSendToExtensionActionTests.java index 6f74bdc487ef6..e9c910ea361fb 100644 --- a/server/src/test/java/org/opensearch/extensions/rest/RestSendToExtensionActionTests.java +++ b/server/src/test/java/org/opensearch/extensions/rest/RestSendToExtensionActionTests.java @@ -110,7 +110,6 @@ public void setup() throws Exception { ); SettingsModule settingsModule = new SettingsModule(settings); UsageService usageService = new UsageService(); - TestThreadPool threadPool = new TestThreadPool(getTestName()); actionModule = new ActionModule( settingsModule.getSettings(), new IndexNameExpressionResolver(new ThreadContext(Settings.EMPTY)), @@ -123,10 +122,10 @@ public void setup() throws Exception { null, usageService, null, - new IdentityService(Settings.EMPTY, threadPool, new ArrayList<>()), - new ExtensionsManager(Set.of(), new IdentityService(Settings.EMPTY, threadPool, List.of())) + new IdentityService(Settings.EMPTY, mock(ThreadPool.class), new ArrayList<>()), + new ExtensionsManager(Set.of(), new IdentityService(Settings.EMPTY, mock(ThreadPool.class), List.of())) ); - identityService = new IdentityService(Settings.EMPTY, threadPool, new ArrayList<>()); + identityService = new IdentityService(Settings.EMPTY, mock(ThreadPool.class), new ArrayList<>()); dynamicActionRegistry = actionModule.getDynamicActionRegistry(); } From e6eb37e9bfdbaf327f4b1866d0feb866bb90c814 Mon Sep 17 00:00:00 2001 From: Craig Perkins Date: Fri, 16 Aug 2024 21:42:03 -0400 Subject: [PATCH 57/65] Fix Thread leak Signed-off-by: Craig Perkins --- .../test/java/org/opensearch/action/ActionModuleTests.java | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/server/src/test/java/org/opensearch/action/ActionModuleTests.java b/server/src/test/java/org/opensearch/action/ActionModuleTests.java index 13c408d36a923..6b8951dd43d11 100644 --- a/server/src/test/java/org/opensearch/action/ActionModuleTests.java +++ b/server/src/test/java/org/opensearch/action/ActionModuleTests.java @@ -74,6 +74,7 @@ import static java.util.Collections.singletonList; import static org.hamcrest.Matchers.hasEntry; import static org.hamcrest.Matchers.startsWith; +import static org.mockito.Mockito.mock; public class ActionModuleTests extends OpenSearchTestCase { public void testSetupActionsContainsKnownBuiltin() { @@ -130,7 +131,6 @@ protected FakeAction() { public void testSetupRestHandlerContainsKnownBuiltin() throws IOException { SettingsModule settings = new SettingsModule(Settings.EMPTY); UsageService usageService = new UsageService(); - ThreadPool threadPool = new TestThreadPool(getTestName()); ActionModule actionModule = new ActionModule( settings.getSettings(), new IndexNameExpressionResolver(new ThreadContext(Settings.EMPTY)), @@ -143,8 +143,8 @@ public void testSetupRestHandlerContainsKnownBuiltin() throws IOException { null, usageService, null, - new IdentityService(Settings.EMPTY, threadPool, new ArrayList<>()), - new ExtensionsManager(Set.of(), new IdentityService(Settings.EMPTY, threadPool, List.of())) + new IdentityService(Settings.EMPTY, mock(ThreadPool.class), new ArrayList<>()), + new ExtensionsManager(Set.of(), new IdentityService(Settings.EMPTY, mock(ThreadPool.class), List.of())) ); actionModule.initRestHandlers(null); // At this point the easiest way to confirm that a handler is loaded is to try to register another one on top of it and to fail From 2c9ba5623a02ae0265fe339c8b4383dd0aacd0ae Mon Sep 17 00:00:00 2001 From: Craig Perkins Date: Mon, 19 Aug 2024 11:38:27 -0400 Subject: [PATCH 58/65] Add to CHANGELOG Signed-off-by: Craig Perkins --- CHANGELOG.md | 1 + 1 file changed, 1 insertion(+) diff --git a/CHANGELOG.md b/CHANGELOG.md index 511dd77c24e22..7d342a6aa76f7 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -19,6 +19,7 @@ The format is based on [Keep a Changelog](https://keepachangelog.com/en/1.0.0/), - Add took time to request nodes stats ([#15054](https://github.com/opensearch-project/OpenSearch/pull/15054)) - [Workload Management] QueryGroup resource tracking framework changes ([#13897](https://github.com/opensearch-project/OpenSearch/pull/13897)) - Add slice execution listeners to SearchOperationListener interface ([#15153](https://github.com/opensearch-project/OpenSearch/pull/15153)) +- Add runAs to Subject interface and introduce IdentityAwarePlugin extension point ([#14630](https://github.com/opensearch-project/OpenSearch/pull/14630)) ### Dependencies - Bump `netty` from 4.1.111.Final to 4.1.112.Final ([#15081](https://github.com/opensearch-project/OpenSearch/pull/15081)) From 9c5b2c43bf9729c26fc1ad1e681121a91316f1b2 Mon Sep 17 00:00:00 2001 From: Craig Perkins Date: Mon, 19 Aug 2024 12:51:10 -0400 Subject: [PATCH 59/65] Rename to getCurrentSubject Signed-off-by: Craig Perkins --- .../org/opensearch/identity/shiro/ShiroIdentityPlugin.java | 4 ++-- .../org/opensearch/identity/shiro/ShiroPluginSubject.java | 3 +-- .../extensions/rest/RestSendToExtensionAction.java | 2 +- .../main/java/org/opensearch/identity/IdentityService.java | 6 +++--- server/src/main/java/org/opensearch/identity/Subject.java | 3 +-- .../org/opensearch/identity/noop/NoopIdentityPlugin.java | 4 ++-- .../org/opensearch/identity/noop/NoopPluginSubject.java | 3 +-- .../main/java/org/opensearch/plugins/IdentityPlugin.java | 6 +++--- .../src/main/java/org/opensearch/rest/RestController.java | 2 +- .../java/org/opensearch/bootstrap/IdentityPluginTests.java | 2 +- .../extensions/rest/ExtensionRestRequestTests.java | 4 ++-- 11 files changed, 18 insertions(+), 21 deletions(-) diff --git a/plugins/identity-shiro/src/main/java/org/opensearch/identity/shiro/ShiroIdentityPlugin.java b/plugins/identity-shiro/src/main/java/org/opensearch/identity/shiro/ShiroIdentityPlugin.java index 435b0acdb06af..af802596ebaa7 100644 --- a/plugins/identity-shiro/src/main/java/org/opensearch/identity/shiro/ShiroIdentityPlugin.java +++ b/plugins/identity-shiro/src/main/java/org/opensearch/identity/shiro/ShiroIdentityPlugin.java @@ -22,7 +22,7 @@ import org.opensearch.env.Environment; import org.opensearch.env.NodeEnvironment; import org.opensearch.identity.PluginSubject; -import org.opensearch.identity.UserSubject; +import org.opensearch.identity.Subject; import org.opensearch.identity.tokens.TokenManager; import org.opensearch.plugins.IdentityPlugin; import org.opensearch.plugins.Plugin; @@ -86,7 +86,7 @@ public Collection createComponents( * @return The current subject */ @Override - public UserSubject getUserSubject() { + public Subject getCurrentSubject() { return new ShiroSubject(authTokenHandler, SecurityUtils.getSubject()); } diff --git a/plugins/identity-shiro/src/main/java/org/opensearch/identity/shiro/ShiroPluginSubject.java b/plugins/identity-shiro/src/main/java/org/opensearch/identity/shiro/ShiroPluginSubject.java index 595ee188f7424..31dde34f447d4 100644 --- a/plugins/identity-shiro/src/main/java/org/opensearch/identity/shiro/ShiroPluginSubject.java +++ b/plugins/identity-shiro/src/main/java/org/opensearch/identity/shiro/ShiroPluginSubject.java @@ -43,8 +43,7 @@ public Principal getPrincipal() { @Override public T runAs(Callable callable) throws Exception { try (ThreadContext.StoredContext ctx = threadPool.getThreadContext().stashContext()) { - callable.call(); + return callable.call(); } - return null; } } diff --git a/server/src/main/java/org/opensearch/extensions/rest/RestSendToExtensionAction.java b/server/src/main/java/org/opensearch/extensions/rest/RestSendToExtensionAction.java index 2e64ded6c5158..dc508e30b1895 100644 --- a/server/src/main/java/org/opensearch/extensions/rest/RestSendToExtensionAction.java +++ b/server/src/main/java/org/opensearch/extensions/rest/RestSendToExtensionAction.java @@ -249,7 +249,7 @@ public String executor() { Map> filteredHeaders = filterHeaders(headers, allowList, denyList); TokenManager tokenManager = identityService.getTokenManager(); - Subject subject = this.identityService.getUserSubject(); + Subject subject = this.identityService.getCurrentSubject(); OnBehalfOfClaims claims = new OnBehalfOfClaims(discoveryExtensionNode.getId(), subject.getPrincipal().getName()); transportService.sendRequest( diff --git a/server/src/main/java/org/opensearch/identity/IdentityService.java b/server/src/main/java/org/opensearch/identity/IdentityService.java index 186b30020c676..03f937180f4ba 100644 --- a/server/src/main/java/org/opensearch/identity/IdentityService.java +++ b/server/src/main/java/org/opensearch/identity/IdentityService.java @@ -48,10 +48,10 @@ public IdentityService(final Settings settings, final ThreadPool threadPool, fin } /** - * Gets the current UserSubject + * Gets the current Subject */ - public UserSubject getUserSubject() { - return identityPlugin.getUserSubject(); + public Subject getCurrentSubject() { + return identityPlugin.getCurrentSubject(); } /** diff --git a/server/src/main/java/org/opensearch/identity/Subject.java b/server/src/main/java/org/opensearch/identity/Subject.java index e138ab7a957ca..0fb0e53848d80 100644 --- a/server/src/main/java/org/opensearch/identity/Subject.java +++ b/server/src/main/java/org/opensearch/identity/Subject.java @@ -27,7 +27,6 @@ public interface Subject { * runAs allows the caller to run a callable function as this subject */ default T runAs(Callable callable) throws Exception { - callable.call(); - return null; + return callable.call(); }; } diff --git a/server/src/main/java/org/opensearch/identity/noop/NoopIdentityPlugin.java b/server/src/main/java/org/opensearch/identity/noop/NoopIdentityPlugin.java index 80f8c06728067..6279388c76f96 100644 --- a/server/src/main/java/org/opensearch/identity/noop/NoopIdentityPlugin.java +++ b/server/src/main/java/org/opensearch/identity/noop/NoopIdentityPlugin.java @@ -9,7 +9,7 @@ package org.opensearch.identity.noop; import org.opensearch.identity.PluginSubject; -import org.opensearch.identity.UserSubject; +import org.opensearch.identity.Subject; import org.opensearch.identity.tokens.TokenManager; import org.opensearch.plugins.IdentityPlugin; import org.opensearch.plugins.Plugin; @@ -35,7 +35,7 @@ public NoopIdentityPlugin(ThreadPool threadPool) { * @return Must never return null */ @Override - public UserSubject getUserSubject() { + public Subject getCurrentSubject() { return new NoopSubject(); } diff --git a/server/src/main/java/org/opensearch/identity/noop/NoopPluginSubject.java b/server/src/main/java/org/opensearch/identity/noop/NoopPluginSubject.java index fdfab255a8c43..20e075276f317 100644 --- a/server/src/main/java/org/opensearch/identity/noop/NoopPluginSubject.java +++ b/server/src/main/java/org/opensearch/identity/noop/NoopPluginSubject.java @@ -43,8 +43,7 @@ public Principal getPrincipal() { @Override public T runAs(Callable callable) throws Exception { try (ThreadContext.StoredContext ctx = threadPool.getThreadContext().stashContext()) { - callable.call(); + return callable.call(); } - return null; } } diff --git a/server/src/main/java/org/opensearch/plugins/IdentityPlugin.java b/server/src/main/java/org/opensearch/plugins/IdentityPlugin.java index 1e5584051cdc7..b40af14231fb9 100644 --- a/server/src/main/java/org/opensearch/plugins/IdentityPlugin.java +++ b/server/src/main/java/org/opensearch/plugins/IdentityPlugin.java @@ -10,7 +10,7 @@ import org.opensearch.common.annotation.ExperimentalApi; import org.opensearch.identity.PluginSubject; -import org.opensearch.identity.UserSubject; +import org.opensearch.identity.Subject; import org.opensearch.identity.tokens.TokenManager; /** @@ -22,11 +22,11 @@ public interface IdentityPlugin { /** - * Get the current user subject. + * Get the current subject. * * @return Should never return null * */ - UserSubject getUserSubject(); + Subject getCurrentSubject(); /** * Get the Identity Plugin's token manager implementation diff --git a/server/src/main/java/org/opensearch/rest/RestController.java b/server/src/main/java/org/opensearch/rest/RestController.java index 197c998a9b714..8b435191846e9 100644 --- a/server/src/main/java/org/opensearch/rest/RestController.java +++ b/server/src/main/java/org/opensearch/rest/RestController.java @@ -593,7 +593,7 @@ private boolean handleAuthenticateUser(final RestRequest request, final RestChan // Authentication did not fail so return true. Authorization is handled at the action level. return true; } - final UserSubject currentSubject = identityService.getUserSubject(); + final UserSubject currentSubject = (UserSubject) identityService.getCurrentSubject(); currentSubject.authenticate(token); logger.debug("Logged in as user " + currentSubject); } catch (final Exception e) { diff --git a/server/src/test/java/org/opensearch/bootstrap/IdentityPluginTests.java b/server/src/test/java/org/opensearch/bootstrap/IdentityPluginTests.java index d4064dd7d3c1a..d7b9f5917c366 100644 --- a/server/src/test/java/org/opensearch/bootstrap/IdentityPluginTests.java +++ b/server/src/test/java/org/opensearch/bootstrap/IdentityPluginTests.java @@ -29,7 +29,7 @@ public void testSingleIdentityPluginSucceeds() { IdentityPlugin identityPlugin1 = new NoopIdentityPlugin(threadPool); List pluginList1 = List.of(identityPlugin1); IdentityService identityService1 = new IdentityService(Settings.EMPTY, threadPool, pluginList1); - assertTrue(identityService1.getUserSubject().getPrincipal().getName().equalsIgnoreCase("Unauthenticated")); + assertTrue(identityService1.getCurrentSubject().getPrincipal().getName().equalsIgnoreCase("Unauthenticated")); assertThat(identityService1.getTokenManager(), is(instanceOf(NoopTokenManager.class))); terminate(threadPool); } diff --git a/server/src/test/java/org/opensearch/extensions/rest/ExtensionRestRequestTests.java b/server/src/test/java/org/opensearch/extensions/rest/ExtensionRestRequestTests.java index e9fc561632a8f..7d9ebe1d1e26a 100644 --- a/server/src/test/java/org/opensearch/extensions/rest/ExtensionRestRequestTests.java +++ b/server/src/test/java/org/opensearch/extensions/rest/ExtensionRestRequestTests.java @@ -76,10 +76,10 @@ public void setUp() throws Exception { extensionTokenProcessor = "placeholder_extension_token_processor"; identityService = new IdentityService(Settings.EMPTY, mock(ThreadPool.class), List.of()); TokenManager tokenManager = identityService.getTokenManager(); - Subject subject = this.identityService.getUserSubject(); + Subject subject = this.identityService.getCurrentSubject(); OnBehalfOfClaims claims = new OnBehalfOfClaims("testID", subject.getPrincipal().getName()); expectedRequestIssuerIdentity = identityService.getTokenManager() - .issueOnBehalfOfToken(identityService.getUserSubject(), claims) + .issueOnBehalfOfToken(identityService.getCurrentSubject(), claims) .asAuthHeaderValue(); } From 4b8c7bd706c37f6c874d5512882779fcc49ed2e3 Mon Sep 17 00:00:00 2001 From: Craig Perkins Date: Mon, 19 Aug 2024 13:49:09 -0400 Subject: [PATCH 60/65] Add type check Signed-off-by: Craig Perkins --- .../main/java/org/opensearch/rest/RestController.java | 9 ++++++--- 1 file changed, 6 insertions(+), 3 deletions(-) diff --git a/server/src/main/java/org/opensearch/rest/RestController.java b/server/src/main/java/org/opensearch/rest/RestController.java index 8b435191846e9..9889f5d67e966 100644 --- a/server/src/main/java/org/opensearch/rest/RestController.java +++ b/server/src/main/java/org/opensearch/rest/RestController.java @@ -57,6 +57,7 @@ import org.opensearch.http.HttpChunk; import org.opensearch.http.HttpServerTransport; import org.opensearch.identity.IdentityService; +import org.opensearch.identity.Subject; import org.opensearch.identity.UserSubject; import org.opensearch.identity.tokens.AuthToken; import org.opensearch.identity.tokens.RestTokenExtractor; @@ -593,9 +594,11 @@ private boolean handleAuthenticateUser(final RestRequest request, final RestChan // Authentication did not fail so return true. Authorization is handled at the action level. return true; } - final UserSubject currentSubject = (UserSubject) identityService.getCurrentSubject(); - currentSubject.authenticate(token); - logger.debug("Logged in as user " + currentSubject); + final Subject currentSubject = identityService.getCurrentSubject(); + if (currentSubject instanceof UserSubject) { + ((UserSubject) currentSubject).authenticate(token); + logger.debug("Logged in as user " + currentSubject); + } } catch (final Exception e) { try { final BytesRestResponse bytesRestResponse = BytesRestResponse.createSimpleErrorResponse( From 1a468e793a06db2d7250245f1af89b557c1f1d37 Mon Sep 17 00:00:00 2001 From: Craig Perkins Date: Wed, 21 Aug 2024 16:33:27 -0400 Subject: [PATCH 61/65] Rename to pluginSubject Signed-off-by: Craig Perkins --- .../main/java/org/opensearch/plugins/IdentityAwarePlugin.java | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/server/src/main/java/org/opensearch/plugins/IdentityAwarePlugin.java b/server/src/main/java/org/opensearch/plugins/IdentityAwarePlugin.java index 9000392d44a37..b19dcfe5544ec 100644 --- a/server/src/main/java/org/opensearch/plugins/IdentityAwarePlugin.java +++ b/server/src/main/java/org/opensearch/plugins/IdentityAwarePlugin.java @@ -27,8 +27,8 @@ public interface IdentityAwarePlugin { /** * Passes necessary classes for this plugin to operate as an IdentityAwarePlugin * - * @param pluginSystemSubject A subject for running transport actions in the plugin system context for system index + * @param pluginSubject A subject for running transport actions in the plugin context for system index * interaction */ - default void assignSubject(PluginSubject pluginSystemSubject) {} + default void assignSubject(PluginSubject pluginSubject) {} } From c74c67773ee7a99debfccc3710eb5d8b6732d8e7 Mon Sep 17 00:00:00 2001 From: Craig Perkins Date: Wed, 28 Aug 2024 10:53:07 -0400 Subject: [PATCH 62/65] Add runAs to ActionRequest and surround doExecute in AbstractClient Signed-off-by: Craig Perkins --- .../org/opensearch/action/ActionRequest.java | 11 +++++++++++ .../client/support/AbstractClient.java | 16 +++++++++++++++- 2 files changed, 26 insertions(+), 1 deletion(-) diff --git a/server/src/main/java/org/opensearch/action/ActionRequest.java b/server/src/main/java/org/opensearch/action/ActionRequest.java index 7ab87065bef7e..2254472dd6801 100644 --- a/server/src/main/java/org/opensearch/action/ActionRequest.java +++ b/server/src/main/java/org/opensearch/action/ActionRequest.java @@ -35,6 +35,7 @@ import org.opensearch.common.annotation.PublicApi; import org.opensearch.core.common.io.stream.StreamInput; import org.opensearch.core.common.io.stream.StreamOutput; +import org.opensearch.identity.Subject; import org.opensearch.transport.TransportRequest; import java.io.IOException; @@ -47,6 +48,8 @@ @PublicApi(since = "1.0.0") public abstract class ActionRequest extends TransportRequest { + private Subject runAs; + public ActionRequest() { super(); // this does not set the listenerThreaded API, if needed, its up to the caller to set it @@ -67,6 +70,14 @@ public boolean getShouldStoreResult() { return false; } + public void runAs(Subject runAs) { + this.runAs = runAs; + } + + public Subject getRunAs() { + return this.runAs; + } + @Override public void writeTo(StreamOutput out) throws IOException { super.writeTo(out); diff --git a/server/src/main/java/org/opensearch/client/support/AbstractClient.java b/server/src/main/java/org/opensearch/client/support/AbstractClient.java index 509cd732357d6..f94e93e30fc46 100644 --- a/server/src/main/java/org/opensearch/client/support/AbstractClient.java +++ b/server/src/main/java/org/opensearch/client/support/AbstractClient.java @@ -422,6 +422,7 @@ import org.opensearch.core.common.bytes.BytesReference; import org.opensearch.core.tasks.TaskId; import org.opensearch.core.xcontent.MediaType; +import org.opensearch.identity.Subject; import org.opensearch.threadpool.ThreadPool; import java.util.Map; @@ -480,7 +481,20 @@ public final vo Request request, ActionListener listener ) { - doExecute(action, request, listener); + Subject runAs = request.getRunAs(); + if (runAs != null) { + try { + runAs.runAs(() -> { + doExecute(action, request, listener); + return null; + }); + } catch (Exception e) { + throw new RuntimeException(e); + } + } else { + // run with default subject. If security is installed, default subject is the authenticated user + doExecute(action, request, listener); + } } protected abstract void doExecute( From 06259f7f74e38b40040252c12d8eb8801924ab5e Mon Sep 17 00:00:00 2001 From: Craig Perkins Date: Wed, 28 Aug 2024 10:56:22 -0400 Subject: [PATCH 63/65] Return this Signed-off-by: Craig Perkins --- server/src/main/java/org/opensearch/action/ActionRequest.java | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/server/src/main/java/org/opensearch/action/ActionRequest.java b/server/src/main/java/org/opensearch/action/ActionRequest.java index 2254472dd6801..1459619e08db5 100644 --- a/server/src/main/java/org/opensearch/action/ActionRequest.java +++ b/server/src/main/java/org/opensearch/action/ActionRequest.java @@ -70,8 +70,9 @@ public boolean getShouldStoreResult() { return false; } - public void runAs(Subject runAs) { + public ActionRequest runAs(Subject runAs) { this.runAs = runAs; + return this; } public Subject getRunAs() { From fc5459d4c538c33d3f6ac28253dc352302bac9ab Mon Sep 17 00:00:00 2001 From: Craig Perkins Date: Wed, 28 Aug 2024 11:06:12 -0400 Subject: [PATCH 64/65] Switch back to void Signed-off-by: Craig Perkins --- server/src/main/java/org/opensearch/action/ActionRequest.java | 3 +-- 1 file changed, 1 insertion(+), 2 deletions(-) diff --git a/server/src/main/java/org/opensearch/action/ActionRequest.java b/server/src/main/java/org/opensearch/action/ActionRequest.java index 1459619e08db5..2254472dd6801 100644 --- a/server/src/main/java/org/opensearch/action/ActionRequest.java +++ b/server/src/main/java/org/opensearch/action/ActionRequest.java @@ -70,9 +70,8 @@ public boolean getShouldStoreResult() { return false; } - public ActionRequest runAs(Subject runAs) { + public void runAs(Subject runAs) { this.runAs = runAs; - return this; } public Subject getRunAs() { From 653beb4d405288635ffd388b770c45bcc34f9b17 Mon Sep 17 00:00:00 2001 From: Craig Perkins Date: Wed, 28 Aug 2024 11:58:00 -0400 Subject: [PATCH 65/65] Revert change to ActionRequest Signed-off-by: Craig Perkins --- .../org/opensearch/action/ActionRequest.java | 11 ----------- .../client/support/AbstractClient.java | 16 +--------------- 2 files changed, 1 insertion(+), 26 deletions(-) diff --git a/server/src/main/java/org/opensearch/action/ActionRequest.java b/server/src/main/java/org/opensearch/action/ActionRequest.java index 2254472dd6801..7ab87065bef7e 100644 --- a/server/src/main/java/org/opensearch/action/ActionRequest.java +++ b/server/src/main/java/org/opensearch/action/ActionRequest.java @@ -35,7 +35,6 @@ import org.opensearch.common.annotation.PublicApi; import org.opensearch.core.common.io.stream.StreamInput; import org.opensearch.core.common.io.stream.StreamOutput; -import org.opensearch.identity.Subject; import org.opensearch.transport.TransportRequest; import java.io.IOException; @@ -48,8 +47,6 @@ @PublicApi(since = "1.0.0") public abstract class ActionRequest extends TransportRequest { - private Subject runAs; - public ActionRequest() { super(); // this does not set the listenerThreaded API, if needed, its up to the caller to set it @@ -70,14 +67,6 @@ public boolean getShouldStoreResult() { return false; } - public void runAs(Subject runAs) { - this.runAs = runAs; - } - - public Subject getRunAs() { - return this.runAs; - } - @Override public void writeTo(StreamOutput out) throws IOException { super.writeTo(out); diff --git a/server/src/main/java/org/opensearch/client/support/AbstractClient.java b/server/src/main/java/org/opensearch/client/support/AbstractClient.java index f94e93e30fc46..509cd732357d6 100644 --- a/server/src/main/java/org/opensearch/client/support/AbstractClient.java +++ b/server/src/main/java/org/opensearch/client/support/AbstractClient.java @@ -422,7 +422,6 @@ import org.opensearch.core.common.bytes.BytesReference; import org.opensearch.core.tasks.TaskId; import org.opensearch.core.xcontent.MediaType; -import org.opensearch.identity.Subject; import org.opensearch.threadpool.ThreadPool; import java.util.Map; @@ -481,20 +480,7 @@ public final vo Request request, ActionListener listener ) { - Subject runAs = request.getRunAs(); - if (runAs != null) { - try { - runAs.runAs(() -> { - doExecute(action, request, listener); - return null; - }); - } catch (Exception e) { - throw new RuntimeException(e); - } - } else { - // run with default subject. If security is installed, default subject is the authenticated user - doExecute(action, request, listener); - } + doExecute(action, request, listener); } protected abstract void doExecute(