Skip to content

Commit d6e59ad

Browse files
authored
Allow storing scripts in multiple projects (#130578)
This commit makes the `ScriptService`, the `ScriptCache`, and the stored script APIs project-aware. By adding the project ID to the cache key in the `ScriptCache`, we avoid data leakage between projects. We resolve the project ID from the thread context inside `ScriptService#compile` instead of passing the project ID explicitly, to avoid making a large number of changes. Since scripts should always be compiled in a user context, resolving the project ID this way should be fine.
1 parent 6ca5a18 commit d6e59ad

File tree

65 files changed

+496
-165
lines changed

Some content is hidden

Large Commits have some content hidden by default. Use the searchbox below for content that may be hidden.

65 files changed

+496
-165
lines changed

libs/logstash-bridge/src/main/java/org/elasticsearch/logstashbridge/script/ScriptServiceBridge.java

Lines changed: 5 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -8,7 +8,9 @@
88
*/
99
package org.elasticsearch.logstashbridge.script;
1010

11+
import org.elasticsearch.cluster.project.ProjectResolver;
1112
import org.elasticsearch.common.settings.Settings;
13+
import org.elasticsearch.core.FixForMultiProject;
1214
import org.elasticsearch.ingest.common.ProcessorsWhitelistExtension;
1315
import org.elasticsearch.logstashbridge.StableBridgeAPI;
1416
import org.elasticsearch.logstashbridge.common.SettingsBridge;
@@ -66,7 +68,9 @@ private static ScriptService getScriptService(final Settings settings, final Lon
6668
MustacheScriptEngine.NAME,
6769
new MustacheScriptEngine(settings)
6870
);
69-
return new ScriptService(settings, scriptEngines, ScriptModule.CORE_CONTEXTS, timeProvider);
71+
@FixForMultiProject // Should this be non-null?
72+
final ProjectResolver projectResolver = null;
73+
return new ScriptService(settings, scriptEngines, ScriptModule.CORE_CONTEXTS, timeProvider, projectResolver);
7074
}
7175

7276
private static List<Whitelist> getPainlessBaseWhiteList() {

modules/aggregations/src/test/java/org/elasticsearch/aggregations/pipeline/MovFnAggregatorTests.java

Lines changed: 3 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -18,6 +18,7 @@
1818
import org.apache.lucene.search.Query;
1919
import org.apache.lucene.store.Directory;
2020
import org.apache.lucene.tests.index.RandomIndexWriter;
21+
import org.elasticsearch.cluster.project.TestProjectResolvers;
2122
import org.elasticsearch.common.settings.Settings;
2223
import org.elasticsearch.common.time.DateFormatters;
2324
import org.elasticsearch.index.mapper.DateFieldMapper;
@@ -106,7 +107,8 @@ public Set<ScriptContext<?>> getSupportedContexts() {
106107
Settings.EMPTY,
107108
engines,
108109
Map.of(MovingFunctionScript.CONTEXT.name, MovingFunctionScript.CONTEXT),
109-
() -> 1L
110+
() -> 1L,
111+
TestProjectResolvers.singleProject(randomProjectIdOrDefault())
110112
);
111113
}
112114

modules/analysis-common/src/test/java/org/elasticsearch/analysis/common/PredicateTokenScriptFilterTests.java

Lines changed: 7 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -63,7 +63,13 @@ public boolean execute(Token token) {
6363
}
6464
};
6565

66-
ScriptService scriptService = new ScriptService(indexSettings, Collections.emptyMap(), Collections.emptyMap(), () -> 1L) {
66+
ScriptService scriptService = new ScriptService(
67+
indexSettings,
68+
Collections.emptyMap(),
69+
Collections.emptyMap(),
70+
() -> 1L,
71+
TestProjectResolvers.singleProject(randomProjectIdOrDefault())
72+
) {
6773
@Override
6874
@SuppressWarnings("unchecked")
6975
public <FactoryType> FactoryType compile(Script script, ScriptContext<FactoryType> context) {

modules/analysis-common/src/test/java/org/elasticsearch/analysis/common/ScriptedConditionTokenFilterTests.java

Lines changed: 7 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -64,7 +64,13 @@ public boolean execute(Token token) {
6464
};
6565

6666
@SuppressWarnings("unchecked")
67-
ScriptService scriptService = new ScriptService(indexSettings, Collections.emptyMap(), Collections.emptyMap(), () -> 1L) {
67+
ScriptService scriptService = new ScriptService(
68+
indexSettings,
69+
Collections.emptyMap(),
70+
Collections.emptyMap(),
71+
() -> 1L,
72+
TestProjectResolvers.singleProject(randomProjectIdOrDefault())
73+
) {
6874
@Override
6975
public <FactoryType> FactoryType compile(Script script, ScriptContext<FactoryType> context) {
7076
assertEquals(context, AnalysisPredicateScript.CONTEXT);

modules/ingest-common/src/test/java/org/elasticsearch/ingest/common/ScriptProcessorFactoryTests.java

Lines changed: 3 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -10,6 +10,7 @@
1010
package org.elasticsearch.ingest.common;
1111

1212
import org.elasticsearch.ElasticsearchException;
13+
import org.elasticsearch.cluster.project.TestProjectResolvers;
1314
import org.elasticsearch.common.settings.Settings;
1415
import org.elasticsearch.ingest.TestIngestDocument;
1516
import org.elasticsearch.script.CtxMap;
@@ -145,7 +146,8 @@ public void testInlineIsCompiled() throws Exception {
145146
return null;
146147
}), Map.of())),
147148
new HashMap<>(ScriptModule.CORE_CONTEXTS),
148-
() -> 1L
149+
() -> 1L,
150+
TestProjectResolvers.singleProject(randomProjectIdOrDefault())
149151
);
150152
factory = new ScriptProcessor.Factory(scriptService);
151153

modules/ingest-common/src/test/java/org/elasticsearch/ingest/common/ScriptProcessorTests.java

Lines changed: 3 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -9,6 +9,7 @@
99

1010
package org.elasticsearch.ingest.common;
1111

12+
import org.elasticsearch.cluster.project.TestProjectResolvers;
1213
import org.elasticsearch.common.settings.Settings;
1314
import org.elasticsearch.ingest.IngestDocument;
1415
import org.elasticsearch.ingest.RandomDocumentPicks;
@@ -47,7 +48,8 @@ public void setupScripting() {
4748
return null;
4849
}), Map.of())),
4950
new HashMap<>(ScriptModule.CORE_CONTEXTS),
50-
() -> 1L
51+
() -> 1L,
52+
TestProjectResolvers.singleProject(randomProjectIdOrDefault())
5153
);
5254
script = new Script(ScriptType.INLINE, Script.DEFAULT_SCRIPT_LANG, scriptName, Map.of());
5355
ingestScriptFactory = scriptService.compile(script, IngestScript.CONTEXT);

modules/lang-expression/src/test/java/org/elasticsearch/script/expression/ExpressionDoubleValuesScriptTests.java

Lines changed: 8 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -13,6 +13,7 @@
1313
import org.apache.lucene.search.DoubleValues;
1414
import org.apache.lucene.search.DoubleValuesSource;
1515
import org.apache.lucene.search.SortField;
16+
import org.elasticsearch.cluster.project.TestProjectResolvers;
1617
import org.elasticsearch.common.settings.Settings;
1718
import org.elasticsearch.script.DoubleValuesScript;
1819
import org.elasticsearch.script.Script;
@@ -39,7 +40,13 @@ public void setUp() throws Exception {
3940
super.setUp();
4041

4142
engine = new ExpressionScriptEngine();
42-
scriptService = new ScriptService(Settings.EMPTY, Map.of("expression", engine), ScriptModule.CORE_CONTEXTS, () -> 1L);
43+
scriptService = new ScriptService(
44+
Settings.EMPTY,
45+
Map.of("expression", engine),
46+
ScriptModule.CORE_CONTEXTS,
47+
() -> 1L,
48+
TestProjectResolvers.singleProject(randomProjectIdOrDefault())
49+
);
4350
}
4451

4552
@SuppressWarnings("unchecked")

qa/smoke-test-ingest-with-all-dependencies/src/internalClusterTest/java/org/elasticsearch/ingest/AbstractScriptTestCase.java

Lines changed: 8 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -9,6 +9,7 @@
99

1010
package org.elasticsearch.ingest;
1111

12+
import org.elasticsearch.cluster.project.TestProjectResolvers;
1213
import org.elasticsearch.common.settings.Settings;
1314
import org.elasticsearch.script.Script;
1415
import org.elasticsearch.script.ScriptEngine;
@@ -33,7 +34,13 @@ public abstract class AbstractScriptTestCase extends ESTestCase {
3334
public void init() throws Exception {
3435
MustacheScriptEngine engine = new MustacheScriptEngine(Settings.EMPTY);
3536
Map<String, ScriptEngine> engines = Collections.singletonMap(engine.getType(), engine);
36-
scriptService = new ScriptService(Settings.EMPTY, engines, ScriptModule.CORE_CONTEXTS, () -> 1L);
37+
scriptService = new ScriptService(
38+
Settings.EMPTY,
39+
engines,
40+
ScriptModule.CORE_CONTEXTS,
41+
() -> 1L,
42+
TestProjectResolvers.singleProject(randomProjectIdOrDefault())
43+
);
3744
}
3845

3946
protected TemplateScript.Factory compile(String template) {

server/src/main/java/org/elasticsearch/action/admin/cluster/storedscripts/TransportDeleteStoredScriptAction.java

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -58,7 +58,7 @@ protected void masterOperation(
5858
ClusterState state,
5959
ActionListener<AcknowledgedResponse> listener
6060
) throws Exception {
61-
ScriptService.deleteStoredScript(clusterService, request, listener);
61+
ScriptService.deleteStoredScript(clusterService, projectResolver.getProjectId(), request, listener);
6262
}
6363

6464
@Override

server/src/main/java/org/elasticsearch/action/admin/cluster/storedscripts/TransportGetStoredScriptAction.java

Lines changed: 8 additions & 10 deletions
Original file line numberDiff line numberDiff line change
@@ -11,8 +11,8 @@
1111

1212
import org.elasticsearch.action.ActionListener;
1313
import org.elasticsearch.action.support.ActionFilters;
14-
import org.elasticsearch.action.support.master.TransportMasterNodeReadAction;
15-
import org.elasticsearch.cluster.ClusterState;
14+
import org.elasticsearch.action.support.master.TransportMasterNodeReadProjectAction;
15+
import org.elasticsearch.cluster.ProjectState;
1616
import org.elasticsearch.cluster.block.ClusterBlockException;
1717
import org.elasticsearch.cluster.block.ClusterBlockLevel;
1818
import org.elasticsearch.cluster.project.ProjectResolver;
@@ -24,9 +24,7 @@
2424
import org.elasticsearch.threadpool.ThreadPool;
2525
import org.elasticsearch.transport.TransportService;
2626

27-
public class TransportGetStoredScriptAction extends TransportMasterNodeReadAction<GetStoredScriptRequest, GetStoredScriptResponse> {
28-
29-
private final ProjectResolver projectResolver;
27+
public class TransportGetStoredScriptAction extends TransportMasterNodeReadProjectAction<GetStoredScriptRequest, GetStoredScriptResponse> {
3028

3129
@Inject
3230
public TransportGetStoredScriptAction(
@@ -43,25 +41,25 @@ public TransportGetStoredScriptAction(
4341
threadPool,
4442
actionFilters,
4543
GetStoredScriptRequest::new,
44+
projectResolver,
4645
GetStoredScriptResponse::new,
4746
EsExecutors.DIRECT_EXECUTOR_SERVICE
4847
);
49-
this.projectResolver = projectResolver;
5048
}
5149

5250
@Override
5351
protected void masterOperation(
5452
Task task,
5553
GetStoredScriptRequest request,
56-
ClusterState state,
54+
ProjectState state,
5755
ActionListener<GetStoredScriptResponse> listener
5856
) throws Exception {
59-
listener.onResponse(new GetStoredScriptResponse(request.id(), ScriptService.getStoredScript(state, request)));
57+
listener.onResponse(new GetStoredScriptResponse(request.id(), ScriptService.getStoredScript(state.metadata(), request)));
6058
}
6159

6260
@Override
63-
protected ClusterBlockException checkBlock(GetStoredScriptRequest request, ClusterState state) {
64-
return state.blocks().globalBlockedException(projectResolver.getProjectId(), ClusterBlockLevel.METADATA_READ);
61+
protected ClusterBlockException checkBlock(GetStoredScriptRequest request, ProjectState state) {
62+
return state.blocks().globalBlockedException(state.projectId(), ClusterBlockLevel.METADATA_READ);
6563
}
6664

6765
}

0 commit comments

Comments
 (0)