Skip to content

Commit 5baadb1

Browse files
authored
Template upgrades should happen in a system context (elastic#30621)
The TemplateUpgradeService is a system service that allows for plugins to register templates that need to be upgraded. These template upgrades should always happen in a system context as they are not a user initiated action. For security integrations, the lack of running this in a system context could lead to unexpected failures. The changes in this commit set an empty system context for the execution of the template upgrades performed by this service. Relates elastic#30603
1 parent cd1ed90 commit 5baadb1

File tree

2 files changed

+26
-4
lines changed

2 files changed

+26
-4
lines changed

server/src/main/java/org/elasticsearch/cluster/metadata/TemplateUpgradeService.java

+13-3
Original file line numberDiff line numberDiff line change
@@ -41,6 +41,7 @@
4141
import org.elasticsearch.common.component.AbstractComponent;
4242
import org.elasticsearch.common.settings.Settings;
4343
import org.elasticsearch.common.unit.TimeValue;
44+
import org.elasticsearch.common.util.concurrent.ThreadContext;
4445
import org.elasticsearch.common.xcontent.ToXContent;
4546
import org.elasticsearch.common.xcontent.XContentHelper;
4647
import org.elasticsearch.common.xcontent.XContentType;
@@ -128,20 +129,29 @@ public void clusterChanged(ClusterChangedEvent event) {
128129
Version.CURRENT,
129130
changes.get().v1().size(),
130131
changes.get().v2().size());
131-
threadPool.generic().execute(() -> updateTemplates(changes.get().v1(), changes.get().v2()));
132+
133+
final ThreadContext threadContext = threadPool.getThreadContext();
134+
try (ThreadContext.StoredContext ignore = threadContext.stashContext()) {
135+
threadContext.markAsSystemContext();
136+
threadPool.generic().execute(() -> updateTemplates(changes.get().v1(), changes.get().v2()));
137+
}
132138
}
133139
}
134140
}
135141

136142
void updateTemplates(Map<String, BytesReference> changes, Set<String> deletions) {
143+
if (threadPool.getThreadContext().isSystemContext() == false) {
144+
throw new IllegalStateException("template updates from the template upgrade service should always happen in a system context");
145+
}
146+
137147
for (Map.Entry<String, BytesReference> change : changes.entrySet()) {
138148
PutIndexTemplateRequest request =
139149
new PutIndexTemplateRequest(change.getKey()).source(change.getValue(), XContentType.JSON);
140150
request.masterNodeTimeout(TimeValue.timeValueMinutes(1));
141151
client.admin().indices().putTemplate(request, new ActionListener<PutIndexTemplateResponse>() {
142152
@Override
143153
public void onResponse(PutIndexTemplateResponse response) {
144-
if(updatesInProgress.decrementAndGet() == 0) {
154+
if (updatesInProgress.decrementAndGet() == 0) {
145155
logger.info("Finished upgrading templates to version {}", Version.CURRENT);
146156
}
147157
if (response.isAcknowledged() == false) {
@@ -151,7 +161,7 @@ public void onResponse(PutIndexTemplateResponse response) {
151161

152162
@Override
153163
public void onFailure(Exception e) {
154-
if(updatesInProgress.decrementAndGet() == 0) {
164+
if (updatesInProgress.decrementAndGet() == 0) {
155165
logger.info("Templates were upgraded to version {}", Version.CURRENT);
156166
}
157167
logger.warn(new ParameterizedMessage("Error updating template [{}]", change.getKey()), e);

server/src/test/java/org/elasticsearch/cluster/metadata/TemplateUpgradeServiceTests.java

+13-1
Original file line numberDiff line numberDiff line change
@@ -38,6 +38,7 @@
3838
import org.elasticsearch.common.collect.Tuple;
3939
import org.elasticsearch.common.settings.ClusterSettings;
4040
import org.elasticsearch.common.settings.Settings;
41+
import org.elasticsearch.common.util.concurrent.ThreadContext;
4142
import org.elasticsearch.test.ESTestCase;
4243
import org.elasticsearch.threadpool.ThreadPool;
4344

@@ -61,6 +62,7 @@
6162
import static org.elasticsearch.test.VersionUtils.randomVersion;
6263
import static org.hamcrest.CoreMatchers.nullValue;
6364
import static org.hamcrest.CoreMatchers.startsWith;
65+
import static org.hamcrest.Matchers.containsString;
6466
import static org.hamcrest.Matchers.empty;
6567
import static org.hamcrest.Matchers.equalTo;
6668
import static org.hamcrest.Matchers.hasSize;
@@ -188,9 +190,16 @@ public void testUpdateTemplates() {
188190
additions.put("add_template_" + i, new BytesArray("{\"index_patterns\" : \"*\", \"order\" : " + i + "}"));
189191
}
190192

191-
TemplateUpgradeService service = new TemplateUpgradeService(Settings.EMPTY, mockClient, clusterService, null,
193+
ThreadPool threadPool = mock(ThreadPool.class);
194+
ThreadContext threadContext = new ThreadContext(Settings.EMPTY);
195+
when(threadPool.getThreadContext()).thenReturn(threadContext);
196+
TemplateUpgradeService service = new TemplateUpgradeService(Settings.EMPTY, mockClient, clusterService, threadPool,
192197
Collections.emptyList());
193198

199+
IllegalStateException ise = expectThrows(IllegalStateException.class, () -> service.updateTemplates(additions, deletions));
200+
assertThat(ise.getMessage(), containsString("template upgrade service should always happen in a system context"));
201+
202+
threadContext.markAsSystemContext();
194203
service.updateTemplates(additions, deletions);
195204
int updatesInProgress = service.getUpdatesInProgress();
196205

@@ -241,11 +250,14 @@ public void testClusterStateUpdate() {
241250
);
242251

243252
ThreadPool threadPool = mock(ThreadPool.class);
253+
ThreadContext threadContext = new ThreadContext(Settings.EMPTY);
254+
when(threadPool.getThreadContext()).thenReturn(threadContext);
244255
ExecutorService executorService = mock(ExecutorService.class);
245256
when(threadPool.generic()).thenReturn(executorService);
246257
doAnswer(invocation -> {
247258
Object[] args = invocation.getArguments();
248259
assert args.length == 1;
260+
assertTrue(threadContext.isSystemContext());
249261
Runnable runnable = (Runnable) args[0];
250262
runnable.run();
251263
updateInvocation.incrementAndGet();

0 commit comments

Comments
 (0)