Skip to content

Commit 7256e8b

Browse files
authored
Revert .tasks back to being created from template (#67188)
Part of #61656. Partial revert of #66640. Managing .tasks via the system index infrastructure is causing a BWC issue, so this commit reverts the index back to being created via a template until we can figure out the problem.
1 parent 39a3875 commit 7256e8b

File tree

3 files changed

+154
-111
lines changed

3 files changed

+154
-111
lines changed

server/src/main/java/org/elasticsearch/indices/SystemIndices.java

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -41,7 +41,7 @@
4141
import static java.util.Collections.singletonMap;
4242
import static java.util.Collections.unmodifiableList;
4343
import static java.util.Collections.unmodifiableMap;
44-
import static org.elasticsearch.tasks.TaskResultsService.TASKS_DESCRIPTOR;
44+
import static org.elasticsearch.tasks.TaskResultsService.TASK_INDEX;
4545

4646
/**
4747
* This class holds the {@link SystemIndexDescriptor} objects that represent system indices the
@@ -50,7 +50,7 @@
5050
*/
5151
public class SystemIndices {
5252
private static final Map<String, Collection<SystemIndexDescriptor>> SERVER_SYSTEM_INDEX_DESCRIPTORS = singletonMap(
53-
TaskResultsService.class.getName(), singletonList(TASKS_DESCRIPTOR)
53+
TaskResultsService.class.getName(), singletonList(new SystemIndexDescriptor(TASK_INDEX + "*", "Task Result Index"))
5454
);
5555

5656
private final CharacterRunAutomaton runAutomaton;

server/src/main/java/org/elasticsearch/tasks/TaskResultsService.java

Lines changed: 92 additions & 109 deletions
Original file line numberDiff line numberDiff line change
@@ -22,31 +22,41 @@
2222
import org.apache.logging.log4j.Logger;
2323
import org.apache.logging.log4j.message.ParameterizedMessage;
2424
import org.elasticsearch.ElasticsearchException;
25-
import org.elasticsearch.Version;
25+
import org.elasticsearch.ExceptionsHelper;
26+
import org.elasticsearch.ResourceAlreadyExistsException;
2627
import org.elasticsearch.action.ActionListener;
28+
import org.elasticsearch.action.admin.indices.create.CreateIndexRequest;
29+
import org.elasticsearch.action.admin.indices.create.CreateIndexResponse;
2730
import org.elasticsearch.action.bulk.BackoffPolicy;
2831
import org.elasticsearch.action.index.IndexRequestBuilder;
2932
import org.elasticsearch.action.index.IndexResponse;
3033
import org.elasticsearch.client.Client;
3134
import org.elasticsearch.client.OriginSettingClient;
3235
import org.elasticsearch.client.Requests;
36+
import org.elasticsearch.cluster.ClusterState;
3337
import org.elasticsearch.cluster.metadata.IndexMetadata;
38+
import org.elasticsearch.cluster.metadata.MappingMetadata;
39+
import org.elasticsearch.cluster.service.ClusterService;
3440
import org.elasticsearch.common.inject.Inject;
3541
import org.elasticsearch.common.settings.Settings;
3642
import org.elasticsearch.common.unit.TimeValue;
3743
import org.elasticsearch.common.util.concurrent.EsRejectedExecutionException;
3844
import org.elasticsearch.common.xcontent.ToXContent;
3945
import org.elasticsearch.common.xcontent.XContentBuilder;
4046
import org.elasticsearch.common.xcontent.XContentFactory;
41-
import org.elasticsearch.indices.SystemIndexDescriptor;
47+
import org.elasticsearch.common.xcontent.XContentType;
48+
import org.elasticsearch.core.internal.io.Streams;
4249
import org.elasticsearch.threadpool.ThreadPool;
4350

51+
import java.io.ByteArrayOutputStream;
4452
import java.io.IOException;
53+
import java.io.InputStream;
54+
import java.nio.charset.StandardCharsets;
4555
import java.util.Iterator;
56+
import java.util.Map;
4657

4758
import static org.elasticsearch.action.admin.cluster.node.tasks.get.GetTaskAction.TASKS_ORIGIN;
4859
import static org.elasticsearch.common.unit.TimeValue.timeValueMillis;
49-
import static org.elasticsearch.common.xcontent.XContentFactory.jsonBuilder;
5060

5161
/**
5262
* Service that can store task results.
@@ -55,20 +65,15 @@ public class TaskResultsService {
5565

5666
private static final Logger logger = LogManager.getLogger(TaskResultsService.class);
5767

58-
public static final String TASK_TYPE = "task";
5968
public static final String TASK_INDEX = ".tasks";
69+
70+
public static final String TASK_TYPE = "task";
71+
72+
public static final String TASK_RESULT_INDEX_MAPPING_FILE = "task-index-mapping.json";
73+
6074
public static final String TASK_RESULT_MAPPING_VERSION_META_FIELD = "version";
6175

62-
public static final SystemIndexDescriptor TASKS_DESCRIPTOR = SystemIndexDescriptor.builder()
63-
.setIndexPattern(TASK_INDEX + "*")
64-
.setPrimaryIndex(TASK_INDEX)
65-
.setDescription("Task Result Index")
66-
.setSettings(getTaskResultIndexSettings())
67-
.setMappings(getTaskResultIndexMappings())
68-
.setVersionMetaKey(TASK_RESULT_MAPPING_VERSION_META_FIELD)
69-
.setOrigin(TASKS_ORIGIN)
70-
.setIndexType(TASK_TYPE)
71-
.build();
76+
public static final int TASK_RESULT_MAPPING_VERSION = 3;
7277

7378
/**
7479
* The backoff policy to use when saving a task result fails. The total wait
@@ -79,16 +84,76 @@ public class TaskResultsService {
7984

8085
private final Client client;
8186

87+
private final ClusterService clusterService;
88+
8289
private final ThreadPool threadPool;
8390

8491
@Inject
85-
public TaskResultsService(Client client, ThreadPool threadPool) {
92+
public TaskResultsService(Client client, ClusterService clusterService, ThreadPool threadPool) {
8693
this.client = new OriginSettingClient(client, TASKS_ORIGIN);
94+
this.clusterService = clusterService;
8795
this.threadPool = threadPool;
8896
}
8997

9098
public void storeResult(TaskResult taskResult, ActionListener<Void> listener) {
91-
IndexRequestBuilder index = client.prepareIndex(TASK_INDEX, TASK_TYPE).setId(taskResult.getTask().getTaskId().toString());
99+
100+
ClusterState state = clusterService.state();
101+
102+
if (state.routingTable().hasIndex(TASK_INDEX) == false) {
103+
CreateIndexRequest createIndexRequest = new CreateIndexRequest();
104+
createIndexRequest.settings(taskResultIndexSettings());
105+
createIndexRequest.index(TASK_INDEX);
106+
createIndexRequest.mapping(TASK_TYPE, taskResultIndexMapping(), XContentType.JSON);
107+
createIndexRequest.cause("auto(task api)");
108+
109+
client.admin().indices().create(createIndexRequest, new ActionListener<CreateIndexResponse>() {
110+
@Override
111+
public void onResponse(CreateIndexResponse result) {
112+
doStoreResult(taskResult, listener);
113+
}
114+
115+
@Override
116+
public void onFailure(Exception e) {
117+
if (ExceptionsHelper.unwrapCause(e) instanceof ResourceAlreadyExistsException) {
118+
// we have the index, do it
119+
try {
120+
doStoreResult(taskResult, listener);
121+
} catch (Exception inner) {
122+
inner.addSuppressed(e);
123+
listener.onFailure(inner);
124+
}
125+
} else {
126+
listener.onFailure(e);
127+
}
128+
}
129+
});
130+
} else {
131+
IndexMetadata metadata = state.getMetadata().index(TASK_INDEX);
132+
if (getTaskResultMappingVersion(metadata) < TASK_RESULT_MAPPING_VERSION) {
133+
// The index already exists but doesn't have our mapping
134+
client.admin().indices().preparePutMapping(TASK_INDEX).setType(TASK_TYPE)
135+
.setSource(taskResultIndexMapping(), XContentType.JSON)
136+
.execute(ActionListener.delegateFailure(listener, (l, r) -> doStoreResult(taskResult, listener)));
137+
} else {
138+
doStoreResult(taskResult, listener);
139+
}
140+
}
141+
}
142+
143+
private int getTaskResultMappingVersion(IndexMetadata metadata) {
144+
MappingMetadata mappingMetadata = metadata.getMappings().get(TASK_TYPE);
145+
if (mappingMetadata == null) {
146+
return 0;
147+
}
148+
@SuppressWarnings("unchecked") Map<String, Object> meta = (Map<String, Object>) mappingMetadata.sourceAsMap().get("_meta");
149+
if (meta == null || meta.containsKey(TASK_RESULT_MAPPING_VERSION_META_FIELD) == false) {
150+
return 1; // The mapping was created before meta field was introduced
151+
}
152+
return (int) meta.get(TASK_RESULT_MAPPING_VERSION_META_FIELD);
153+
}
154+
155+
private void doStoreResult(TaskResult taskResult, ActionListener<Void> listener) {
156+
IndexRequestBuilder index = client.prepareIndex(TASK_INDEX, TASK_TYPE, taskResult.getTask().getTaskId().toString());
92157
try (XContentBuilder builder = XContentFactory.contentBuilder(Requests.INDEX_CONTENT_TYPE)) {
93158
taskResult.toXContent(builder, ToXContent.EMPTY_PARAMS);
94159
index.setSource(builder);
@@ -119,106 +184,24 @@ public void onFailure(Exception e) {
119184
});
120185
}
121186

122-
private static Settings getTaskResultIndexSettings() {
187+
private Settings taskResultIndexSettings() {
123188
return Settings.builder()
124189
.put(IndexMetadata.INDEX_NUMBER_OF_SHARDS_SETTING.getKey(), 1)
125190
.put(IndexMetadata.INDEX_AUTO_EXPAND_REPLICAS_SETTING.getKey(), "0-1")
126191
.put(IndexMetadata.SETTING_PRIORITY, Integer.MAX_VALUE)
127192
.build();
128193
}
129194

130-
private static XContentBuilder getTaskResultIndexMappings() {
131-
try {
132-
final XContentBuilder builder = jsonBuilder();
133-
134-
builder.startObject();
135-
{
136-
builder.startObject(TASK_TYPE);
137-
builder.field("dynamic", "strict");
138-
{
139-
builder.startObject("_meta");
140-
builder.field(TASK_RESULT_MAPPING_VERSION_META_FIELD, Version.CURRENT.toString());
141-
builder.endObject();
142-
143-
builder.startObject("properties");
144-
{
145-
builder.startObject("completed");
146-
builder.field("type", "boolean");
147-
builder.endObject();
148-
149-
builder.startObject("task");
150-
{
151-
builder.startObject("properties");
152-
{
153-
builder.startObject("action");
154-
builder.field("type", "keyword");
155-
builder.endObject();
156-
157-
builder.startObject("cancellable");
158-
builder.field("type", "boolean");
159-
builder.endObject();
160-
161-
builder.startObject("id");
162-
builder.field("type", "long");
163-
builder.endObject();
164-
165-
builder.startObject("parent_task_id");
166-
builder.field("type", "keyword");
167-
builder.endObject();
168-
169-
builder.startObject("node");
170-
builder.field("type", "keyword");
171-
builder.endObject();
172-
173-
builder.startObject("running_time_in_nanos");
174-
builder.field("type", "long");
175-
builder.endObject();
176-
177-
builder.startObject("start_time_in_millis");
178-
builder.field("type", "long");
179-
builder.endObject();
180-
181-
builder.startObject("type");
182-
builder.field("type", "keyword");
183-
builder.endObject();
184-
185-
builder.startObject("status");
186-
builder.field("type", "object");
187-
builder.field("enabled", false);
188-
builder.endObject();
189-
190-
builder.startObject("description");
191-
builder.field("type", "text");
192-
builder.endObject();
193-
194-
builder.startObject("headers");
195-
builder.field("type", "object");
196-
builder.field("enabled", false);
197-
builder.endObject();
198-
}
199-
builder.endObject();
200-
}
201-
builder.endObject();
202-
203-
builder.startObject("response");
204-
builder.field("type", "object");
205-
builder.field("enabled", false);
206-
builder.endObject();
207-
208-
builder.startObject("error");
209-
builder.field("type", "object");
210-
builder.field("enabled", false);
211-
builder.endObject();
212-
}
213-
builder.endObject();
214-
}
215-
builder.endObject();
216-
}
217-
218-
builder.endObject();
219-
return builder;
220-
} catch (IOException e) {
221-
throw new RuntimeException("Failed to build " + TASK_INDEX + " index mappings", e);
195+
public String taskResultIndexMapping() {
196+
try (InputStream is = getClass().getResourceAsStream(TASK_RESULT_INDEX_MAPPING_FILE)) {
197+
ByteArrayOutputStream out = new ByteArrayOutputStream();
198+
Streams.copy(is, out);
199+
return out.toString(StandardCharsets.UTF_8.name());
200+
} catch (Exception e) {
201+
logger.error(() -> new ParameterizedMessage(
202+
"failed to create tasks results index template [{}]", TASK_RESULT_INDEX_MAPPING_FILE), e);
203+
throw new IllegalStateException("failed to create tasks results index template [" + TASK_RESULT_INDEX_MAPPING_FILE + "]", e);
222204
}
205+
223206
}
224207
}
Lines changed: 60 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,60 @@
1+
{
2+
"task" : {
3+
"_meta": {
4+
"version": 3
5+
},
6+
"dynamic" : "strict",
7+
"properties" : {
8+
"completed": {
9+
"type": "boolean"
10+
},
11+
"task" : {
12+
"properties": {
13+
"action": {
14+
"type": "keyword"
15+
},
16+
"cancellable": {
17+
"type": "boolean"
18+
},
19+
"id": {
20+
"type": "long"
21+
},
22+
"parent_task_id": {
23+
"type": "keyword"
24+
},
25+
"node": {
26+
"type": "keyword"
27+
},
28+
"running_time_in_nanos": {
29+
"type": "long"
30+
},
31+
"start_time_in_millis": {
32+
"type": "long"
33+
},
34+
"type": {
35+
"type": "keyword"
36+
},
37+
"status": {
38+
"type" : "object",
39+
"enabled" : false
40+
},
41+
"description": {
42+
"type": "text"
43+
},
44+
"headers": {
45+
"type" : "object",
46+
"enabled" : false
47+
}
48+
}
49+
},
50+
"response" : {
51+
"type" : "object",
52+
"enabled" : false
53+
},
54+
"error" : {
55+
"type" : "object",
56+
"enabled" : false
57+
}
58+
}
59+
}
60+
}

0 commit comments

Comments
 (0)