Skip to content

Commit 347c4d9

Browse files
committed
Allow storing scripts in multiple projects
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. The method `ScriptService#compile` has a lot of usages, so we introduce a temporary method that hard-codes the default project ID. Follow-up PRs will update the remaining usages to pass the correct project ID.
1 parent 547d4a4 commit 347c4d9

File tree

13 files changed

+180
-118
lines changed

13 files changed

+180
-118
lines changed

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

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -16,6 +16,7 @@
1616
import org.elasticsearch.client.internal.Client;
1717
import org.elasticsearch.client.internal.support.AbstractClient;
1818
import org.elasticsearch.cluster.metadata.IndexMetadata;
19+
import org.elasticsearch.cluster.metadata.ProjectId;
1920
import org.elasticsearch.cluster.project.TestProjectResolvers;
2021
import org.elasticsearch.common.settings.Settings;
2122
import org.elasticsearch.env.Environment;
@@ -66,7 +67,7 @@ public boolean execute(Token token) {
6667
ScriptService scriptService = new ScriptService(indexSettings, Collections.emptyMap(), Collections.emptyMap(), () -> 1L) {
6768
@Override
6869
@SuppressWarnings("unchecked")
69-
public <FactoryType> FactoryType compile(Script script, ScriptContext<FactoryType> context) {
70+
public <FactoryType> FactoryType compile(ProjectId projectId, Script script, ScriptContext<FactoryType> context) {
7071
assertEquals(context, AnalysisPredicateScript.CONTEXT);
7172
assertEquals(new Script("my_script"), script);
7273
return (FactoryType) factory;

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

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -16,6 +16,7 @@
1616
import org.elasticsearch.client.internal.Client;
1717
import org.elasticsearch.client.internal.support.AbstractClient;
1818
import org.elasticsearch.cluster.metadata.IndexMetadata;
19+
import org.elasticsearch.cluster.metadata.ProjectId;
1920
import org.elasticsearch.cluster.project.TestProjectResolvers;
2021
import org.elasticsearch.common.settings.Settings;
2122
import org.elasticsearch.env.Environment;
@@ -66,7 +67,7 @@ public boolean execute(Token token) {
6667
@SuppressWarnings("unchecked")
6768
ScriptService scriptService = new ScriptService(indexSettings, Collections.emptyMap(), Collections.emptyMap(), () -> 1L) {
6869
@Override
69-
public <FactoryType> FactoryType compile(Script script, ScriptContext<FactoryType> context) {
70+
public <FactoryType> FactoryType compile(ProjectId projectId, Script script, ScriptContext<FactoryType> context) {
7071
assertEquals(context, AnalysisPredicateScript.CONTEXT);
7172
assertEquals(new Script("token.getPosition() > 1"), script);
7273
return (FactoryType) factory;

modules/lang-mustache/src/main/java/org/elasticsearch/script/mustache/TransportMultiSearchTemplateAction.java

Lines changed: 6 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -20,6 +20,7 @@
2020
import org.elasticsearch.action.support.HandledTransportAction;
2121
import org.elasticsearch.client.internal.node.NodeClient;
2222
import org.elasticsearch.cluster.ClusterState;
23+
import org.elasticsearch.cluster.project.ProjectResolver;
2324
import org.elasticsearch.cluster.service.ClusterService;
2425
import org.elasticsearch.common.util.concurrent.EsExecutors;
2526
import org.elasticsearch.features.FeatureService;
@@ -47,6 +48,7 @@ public class TransportMultiSearchTemplateAction extends HandledTransportAction<M
4748
private final Predicate<NodeFeature> clusterSupportsFeature;
4849
private final NodeClient client;
4950
private final SearchUsageHolder searchUsageHolder;
51+
private final ProjectResolver projectResolver;
5052

5153
@Inject
5254
public TransportMultiSearchTemplateAction(
@@ -57,7 +59,8 @@ public TransportMultiSearchTemplateAction(
5759
NodeClient client,
5860
UsageService usageService,
5961
ClusterService clusterService,
60-
FeatureService featureService
62+
FeatureService featureService,
63+
ProjectResolver projectResolver
6164
) {
6265
super(
6366
MustachePlugin.MULTI_SEARCH_TEMPLATE_ACTION.name(),
@@ -68,6 +71,7 @@ public TransportMultiSearchTemplateAction(
6871
);
6972
this.scriptService = scriptService;
7073
this.xContentRegistry = xContentRegistry;
74+
this.projectResolver = projectResolver;
7175
this.clusterSupportsFeature = f -> {
7276
ClusterState state = clusterService.state();
7377
return state.clusterRecovered() && featureService.clusterHasFeature(state, f);
@@ -92,6 +96,7 @@ protected void doExecute(Task task, MultiSearchTemplateRequest request, ActionLi
9296
SearchRequest searchRequest;
9397
try {
9498
searchRequest = convert(
99+
projectResolver.getProjectId(),
95100
searchTemplateRequest,
96101
searchTemplateResponse,
97102
scriptService,

modules/lang-mustache/src/main/java/org/elasticsearch/script/mustache/TransportSearchTemplateAction.java

Lines changed: 9 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -15,6 +15,8 @@
1515
import org.elasticsearch.action.support.HandledTransportAction;
1616
import org.elasticsearch.client.internal.node.NodeClient;
1717
import org.elasticsearch.cluster.ClusterState;
18+
import org.elasticsearch.cluster.metadata.ProjectId;
19+
import org.elasticsearch.cluster.project.ProjectResolver;
1820
import org.elasticsearch.cluster.service.ClusterService;
1921
import org.elasticsearch.common.bytes.BytesArray;
2022
import org.elasticsearch.common.util.concurrent.EsExecutors;
@@ -52,6 +54,7 @@ public class TransportSearchTemplateAction extends HandledTransportAction<Search
5254
private final Predicate<NodeFeature> clusterSupportsFeature;
5355
private final NodeClient client;
5456
private final SearchUsageHolder searchUsageHolder;
57+
private final ProjectResolver projectResolver;
5558

5659
@Inject
5760
public TransportSearchTemplateAction(
@@ -62,7 +65,8 @@ public TransportSearchTemplateAction(
6265
NodeClient client,
6366
UsageService usageService,
6467
ClusterService clusterService,
65-
FeatureService featureService
68+
FeatureService featureService,
69+
ProjectResolver projectResolver
6670
) {
6771
super(
6872
MustachePlugin.SEARCH_TEMPLATE_ACTION.name(),
@@ -73,6 +77,7 @@ public TransportSearchTemplateAction(
7377
);
7478
this.scriptService = scriptService;
7579
this.xContentRegistry = xContentRegistry;
80+
this.projectResolver = projectResolver;
7681
this.clusterSupportsFeature = f -> {
7782
ClusterState state = clusterService.state();
7883
return state.clusterRecovered() && featureService.clusterHasFeature(state, f);
@@ -87,6 +92,7 @@ protected void doExecute(Task task, SearchTemplateRequest request, ActionListene
8792
boolean success = false;
8893
try {
8994
SearchRequest searchRequest = convert(
95+
projectResolver.getProjectId(),
9096
request,
9197
response,
9298
scriptService,
@@ -118,6 +124,7 @@ protected void doExecute(Task task, SearchTemplateRequest request, ActionListene
118124
}
119125

120126
static SearchRequest convert(
127+
ProjectId projectId,
121128
SearchTemplateRequest searchTemplateRequest,
122129
SearchTemplateResponse response,
123130
ScriptService scriptService,
@@ -131,7 +138,7 @@ static SearchRequest convert(
131138
searchTemplateRequest.getScript(),
132139
searchTemplateRequest.getScriptParams() == null ? Collections.emptyMap() : searchTemplateRequest.getScriptParams()
133140
);
134-
TemplateScript compiledScript = scriptService.compile(script, TemplateScript.CONTEXT).newInstance(script.getParams());
141+
TemplateScript compiledScript = scriptService.compile(projectId, script, TemplateScript.CONTEXT).newInstance(script.getParams());
135142
String source = compiledScript.execute();
136143
response.setSource(new BytesArray(source));
137144

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
}

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

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -61,7 +61,7 @@ protected void masterOperation(
6161
ClusterState state,
6262
ActionListener<AcknowledgedResponse> listener
6363
) throws Exception {
64-
scriptService.putStoredScript(clusterService, request, listener);
64+
scriptService.putStoredScript(clusterService, projectResolver.getProjectId(), request, listener);
6565
}
6666

6767
@Override

server/src/main/java/org/elasticsearch/script/ScriptCache.java

Lines changed: 6 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -11,6 +11,7 @@
1111

1212
import org.apache.logging.log4j.LogManager;
1313
import org.apache.logging.log4j.Logger;
14+
import org.elasticsearch.cluster.metadata.ProjectId;
1415
import org.elasticsearch.common.breaker.CircuitBreaker;
1516
import org.elasticsearch.common.breaker.CircuitBreakingException;
1617
import org.elasticsearch.common.cache.Cache;
@@ -78,13 +79,14 @@ public class ScriptCache {
7879
<FactoryType> FactoryType compile(
7980
ScriptContext<FactoryType> context,
8081
ScriptEngine scriptEngine,
82+
ProjectId projectId,
8183
String id,
8284
String idOrCode,
8385
ScriptType type,
8486
Map<String, String> options
8587
) {
8688
String lang = scriptEngine.getType();
87-
CacheKey cacheKey = new CacheKey(lang, idOrCode, context.name, options);
89+
CacheKey cacheKey = new CacheKey(lang, projectId, idOrCode, context.name, options);
8890

8991
// Relying on computeIfAbsent to avoid multiple threads from compiling the same script
9092
try {
@@ -204,12 +206,14 @@ public void onRemoval(RemovalNotification<CacheKey, Object> notification) {
204206

205207
private static final class CacheKey {
206208
final String lang;
209+
final ProjectId projectId;
207210
final String idOrCode;
208211
final String context;
209212
final Map<String, String> options;
210213

211-
private CacheKey(String lang, String idOrCode, String context, Map<String, String> options) {
214+
private CacheKey(String lang, ProjectId projectId, String idOrCode, String context, Map<String, String> options) {
212215
this.lang = lang;
216+
this.projectId = projectId;
213217
this.idOrCode = idOrCode;
214218
this.context = context;
215219
this.options = options;

0 commit comments

Comments
 (0)