Skip to content

Commit 65e4ec1

Browse files
authored
Run TransportGetComposableIndexTemplate on local node (#119830)
This action solely needs the cluster state, it can run on any node. Additionally, it needs to be cancellable to avoid doing unnecessary work after a client failure or timeout. As a drive-by, this removes another usage of the trappy default master node timeout.
1 parent 48b9fae commit 65e4ec1

File tree

16 files changed

+129
-160
lines changed

16 files changed

+129
-160
lines changed

docs/changelog/119830.yaml

Lines changed: 5 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,5 @@
1+
pr: 119830
2+
summary: Run `TransportGetComposableIndexTemplate` on local node
3+
area: Indices APIs
4+
type: enhancement
5+
issues: []

docs/reference/indices/get-index-template.asciidoc

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -65,7 +65,7 @@ expressions. If omitted, all templates are returned.
6565

6666
include::{docdir}/rest-api/common-parms.asciidoc[tag=flat-settings]
6767

68-
include::{docdir}/rest-api/common-parms.asciidoc[tag=local]
68+
include::{docdir}/rest-api/common-parms.asciidoc[tag=local-deprecated-9.0.0]
6969

7070
include::{docdir}/rest-api/common-parms.asciidoc[tag=master-timeout]
7171

modules/data-streams/src/internalClusterTest/java/org/elasticsearch/datastreams/DataStreamIT.java

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -722,7 +722,7 @@ public void testCannotDeleteComposableTemplateUsedByDataStream() throws Exceptio
722722
TransportDeleteComposableIndexTemplateAction.Request deleteRequest = new TransportDeleteComposableIndexTemplateAction.Request("id");
723723
client().execute(TransportDeleteComposableIndexTemplateAction.TYPE, deleteRequest).get();
724724

725-
GetComposableIndexTemplateAction.Request getReq = new GetComposableIndexTemplateAction.Request("id");
725+
GetComposableIndexTemplateAction.Request getReq = new GetComposableIndexTemplateAction.Request(TEST_REQUEST_TIMEOUT, "id");
726726
Exception e3 = expectThrows(Exception.class, client().execute(GetComposableIndexTemplateAction.INSTANCE, getReq));
727727
maybeE = ExceptionsHelper.unwrapCausesAndSuppressed(e3, err -> err.getMessage().contains("index template matching [id] not found"));
728728
assertTrue(maybeE.isPresent());

qa/smoke-test-http/src/javaRestTest/java/org/elasticsearch/http/RestActionCancellationIT.java

Lines changed: 5 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -16,6 +16,7 @@
1616
import org.elasticsearch.action.admin.indices.alias.get.GetAliasesAction;
1717
import org.elasticsearch.action.admin.indices.recovery.RecoveryAction;
1818
import org.elasticsearch.action.admin.indices.template.get.GetComponentTemplateAction;
19+
import org.elasticsearch.action.admin.indices.template.get.GetComposableIndexTemplateAction;
1920
import org.elasticsearch.action.support.CancellableActionTestPlugin;
2021
import org.elasticsearch.action.support.PlainActionFuture;
2122
import org.elasticsearch.action.support.RefCountingListener;
@@ -71,6 +72,10 @@ public void testGetComponentTemplateCancellation() {
7172
runRestActionCancellationTest(new Request(HttpGet.METHOD_NAME, "/_component_template"), GetComponentTemplateAction.NAME);
7273
}
7374

75+
public void testGetComposableTemplateCancellation() {
76+
runRestActionCancellationTest(new Request(HttpGet.METHOD_NAME, "/_index_template"), GetComposableIndexTemplateAction.NAME);
77+
}
78+
7479
private void runRestActionCancellationTest(Request request, String actionName) {
7580
final var node = usually() ? internalCluster().getRandomNodeName() : internalCluster().startCoordinatingOnlyNode(Settings.EMPTY);
7681

rest-api-spec/src/main/resources/rest-api-spec/api/indices.exists_template.json

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -32,9 +32,10 @@
3232
},
3333
"master_timeout":{
3434
"type":"time",
35-
"description":"Explicit operation timeout for connection to master node"
35+
"description":"Timeout for waiting for new cluster state in case it is blocked"
3636
},
3737
"local":{
38+
"deprecated":true,
3839
"type":"boolean",
3940
"description":"Return local information, do not retrieve the state from master node (default: false)"
4041
}

rest-api-spec/src/main/resources/rest-api-spec/api/indices.get_index_template.json

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -38,9 +38,10 @@
3838
},
3939
"master_timeout":{
4040
"type":"time",
41-
"description":"Explicit operation timeout for connection to master node"
41+
"description":"Timeout for waiting for new cluster state in case it is blocked"
4242
},
4343
"local":{
44+
"deprecated":true,
4445
"type":"boolean",
4546
"description":"Return local information, do not retrieve the state from master node (default: false)"
4647
},

rest-api-spec/src/yamlRestTest/resources/rest-api-spec/test/indices.get_index_template/10_basic.yml

Lines changed: 34 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -82,14 +82,48 @@ setup:
8282

8383
---
8484
"Get index template with local flag":
85+
- requires:
86+
test_runner_features: ["allowed_warnings"]
8587

8688
- do:
8789
indices.get_index_template:
8890
name: test
8991
local: true
92+
allowed_warnings:
93+
- "the [?local] query parameter to this API has no effect, is now deprecated, and will be removed in a future version"
9094

9195
- match: {index_templates.0.name: test}
9296

97+
---
98+
"Deprecated local parameter":
99+
- requires:
100+
capabilities:
101+
- method: GET
102+
path: /_get_index_template
103+
capabilities: ["local_param_deprecated"]
104+
test_runner_features: ["capabilities", "warnings"]
105+
reason: Deprecation was implemented with capability
106+
107+
- do:
108+
indices.get_index_template:
109+
local: true
110+
warnings:
111+
- "the [?local] query parameter to this API has no effect, is now deprecated, and will be removed in a future version"
112+
113+
---
114+
"Deprecated local parameter works in v8 compat mode":
115+
- requires:
116+
test_runner_features: ["headers"]
117+
118+
- do:
119+
headers:
120+
Content-Type: "application/vnd.elasticsearch+json;compatible-with=8"
121+
Accept: "application/vnd.elasticsearch+json;compatible-with=8"
122+
indices.get_index_template:
123+
local: true
124+
125+
- exists: index_templates
126+
93127
---
94128
"Add data stream lifecycle":
95129
- requires:

server/src/internalClusterTest/java/org/elasticsearch/reservedstate/service/ComponentTemplatesFileSettingsIT.java

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -456,7 +456,7 @@ private void assertComponentAndIndexTemplateDelete(CountDownLatch savedClusterSt
456456

457457
final var response = client().execute(
458458
GetComposableIndexTemplateAction.INSTANCE,
459-
new GetComposableIndexTemplateAction.Request("template*")
459+
new GetComposableIndexTemplateAction.Request(TEST_REQUEST_TIMEOUT, "template*")
460460
).get();
461461

462462
assertThat(response.indexTemplates().keySet().stream().collect(Collectors.toSet()), containsInAnyOrder("template_1", "template_2"));
@@ -594,7 +594,7 @@ private void assertClusterStateNotSaved(CountDownLatch savedClusterState, Atomic
594594

595595
final var response = client().execute(
596596
GetComposableIndexTemplateAction.INSTANCE,
597-
new GetComposableIndexTemplateAction.Request("err*")
597+
new GetComposableIndexTemplateAction.Request(TEST_REQUEST_TIMEOUT, "err*")
598598
).get();
599599

600600
assertTrue(response.indexTemplates().isEmpty());

server/src/main/java/org/elasticsearch/action/admin/indices/template/get/GetComposableIndexTemplateAction.java

Lines changed: 25 additions & 26 deletions
Original file line numberDiff line numberDiff line change
@@ -14,12 +14,17 @@
1414
import org.elasticsearch.action.ActionResponse;
1515
import org.elasticsearch.action.ActionType;
1616
import org.elasticsearch.action.admin.indices.rollover.RolloverConfiguration;
17-
import org.elasticsearch.action.support.master.MasterNodeReadRequest;
17+
import org.elasticsearch.action.support.local.LocalClusterStateRequest;
1818
import org.elasticsearch.cluster.metadata.ComposableIndexTemplate;
1919
import org.elasticsearch.cluster.metadata.DataStreamGlobalRetention;
2020
import org.elasticsearch.common.io.stream.StreamInput;
2121
import org.elasticsearch.common.io.stream.StreamOutput;
2222
import org.elasticsearch.core.Nullable;
23+
import org.elasticsearch.core.TimeValue;
24+
import org.elasticsearch.core.UpdateForV10;
25+
import org.elasticsearch.tasks.CancellableTask;
26+
import org.elasticsearch.tasks.Task;
27+
import org.elasticsearch.tasks.TaskId;
2328
import org.elasticsearch.xcontent.ParseField;
2429
import org.elasticsearch.xcontent.ToXContentObject;
2530
import org.elasticsearch.xcontent.XContentBuilder;
@@ -40,24 +45,30 @@ private GetComposableIndexTemplateAction() {
4045
/**
4146
* Request that to retrieve one or more index templates
4247
*/
43-
public static class Request extends MasterNodeReadRequest<Request> {
48+
public static class Request extends LocalClusterStateRequest {
4449

4550
@Nullable
4651
private final String name;
4752
private boolean includeDefaults;
4853

4954
/**
55+
* @param masterTimeout Timeout for waiting for new cluster state in case it is blocked.
5056
* @param name A template name or pattern, or {@code null} to retrieve all templates.
5157
*/
52-
public Request(@Nullable String name) {
53-
super(TRAPPY_IMPLICIT_DEFAULT_MASTER_NODE_TIMEOUT);
58+
public Request(TimeValue masterTimeout, @Nullable String name) {
59+
super(masterTimeout);
5460
if (name != null && name.contains(",")) {
5561
throw new IllegalArgumentException("template name may not contain ','");
5662
}
5763
this.name = name;
5864
this.includeDefaults = false;
5965
}
6066

67+
/**
68+
* NB prior to 9.0 this was a TransportMasterNodeReadAction so for BwC we must remain able to read these requests until
69+
* we no longer need to support calling this action remotely.
70+
*/
71+
@UpdateForV10(owner = UpdateForV10.Owner.DATA_MANAGEMENT)
6172
public Request(StreamInput in) throws IOException {
6273
super(in);
6374
name = in.readOptionalString();
@@ -68,15 +79,6 @@ public Request(StreamInput in) throws IOException {
6879
}
6980
}
7081

71-
@Override
72-
public void writeTo(StreamOutput out) throws IOException {
73-
super.writeTo(out);
74-
out.writeOptionalString(name);
75-
if (out.getTransportVersion().onOrAfter(TransportVersions.V_8_9_X)) {
76-
out.writeBoolean(includeDefaults);
77-
}
78-
}
79-
8082
public void includeDefaults(boolean includeDefaults) {
8183
this.includeDefaults = includeDefaults;
8284
}
@@ -90,6 +92,11 @@ public ActionRequestValidationException validate() {
9092
return null;
9193
}
9294

95+
@Override
96+
public Task createTask(long id, String type, String action, TaskId parentTaskId, Map<String, String> headers) {
97+
return new CancellableTask(id, type, action, "", parentTaskId, headers);
98+
}
99+
93100
/**
94101
* The name of the index templates.
95102
*/
@@ -124,19 +131,6 @@ public static class Response extends ActionResponse implements ToXContentObject
124131
@Nullable
125132
private final RolloverConfiguration rolloverConfiguration;
126133

127-
public Response(StreamInput in) throws IOException {
128-
super(in);
129-
indexTemplates = in.readMap(ComposableIndexTemplate::new);
130-
if (in.getTransportVersion().onOrAfter(TransportVersions.V_8_9_X)) {
131-
rolloverConfiguration = in.readOptionalWriteable(RolloverConfiguration::new);
132-
} else {
133-
rolloverConfiguration = null;
134-
}
135-
if (in.getTransportVersion().between(TransportVersions.V_8_14_0, TransportVersions.V_8_16_0)) {
136-
in.readOptionalWriteable(DataStreamGlobalRetention::read);
137-
}
138-
}
139-
140134
/**
141135
* Please use {@link GetComposableIndexTemplateAction.Response#Response(Map)}
142136
*/
@@ -184,6 +178,11 @@ public RolloverConfiguration getRolloverConfiguration() {
184178
return rolloverConfiguration;
185179
}
186180

181+
/**
182+
* NB prior to 9.0 this was a TransportMasterNodeReadAction so for BwC we must remain able to write these responses until
183+
* we no longer need to support calling this action remotely.
184+
*/
185+
@UpdateForV10(owner = UpdateForV10.Owner.DATA_MANAGEMENT)
187186
@Override
188187
public void writeTo(StreamOutput out) throws IOException {
189188
out.writeMap(indexTemplates, StreamOutput::writeWriteable);

server/src/main/java/org/elasticsearch/action/admin/indices/template/get/TransportGetComposableIndexTemplateAction.java

Lines changed: 26 additions & 14 deletions
Original file line numberDiff line numberDiff line change
@@ -12,51 +12,61 @@
1212
import org.elasticsearch.ResourceNotFoundException;
1313
import org.elasticsearch.action.ActionListener;
1414
import org.elasticsearch.action.support.ActionFilters;
15-
import org.elasticsearch.action.support.master.TransportMasterNodeReadAction;
15+
import org.elasticsearch.action.support.ChannelActionListener;
16+
import org.elasticsearch.action.support.local.TransportLocalClusterStateAction;
1617
import org.elasticsearch.cluster.ClusterState;
1718
import org.elasticsearch.cluster.block.ClusterBlockException;
1819
import org.elasticsearch.cluster.block.ClusterBlockLevel;
1920
import org.elasticsearch.cluster.metadata.ComposableIndexTemplate;
2021
import org.elasticsearch.cluster.metadata.DataStreamLifecycle;
21-
import org.elasticsearch.cluster.metadata.IndexNameExpressionResolver;
2222
import org.elasticsearch.cluster.service.ClusterService;
2323
import org.elasticsearch.common.regex.Regex;
2424
import org.elasticsearch.common.settings.ClusterSettings;
2525
import org.elasticsearch.common.util.concurrent.EsExecutors;
26+
import org.elasticsearch.core.UpdateForV10;
2627
import org.elasticsearch.injection.guice.Inject;
28+
import org.elasticsearch.tasks.CancellableTask;
2729
import org.elasticsearch.tasks.Task;
28-
import org.elasticsearch.threadpool.ThreadPool;
2930
import org.elasticsearch.transport.TransportService;
3031

3132
import java.util.HashMap;
3233
import java.util.Map;
3334

34-
public class TransportGetComposableIndexTemplateAction extends TransportMasterNodeReadAction<
35+
public class TransportGetComposableIndexTemplateAction extends TransportLocalClusterStateAction<
3536
GetComposableIndexTemplateAction.Request,
3637
GetComposableIndexTemplateAction.Response> {
3738

3839
private final ClusterSettings clusterSettings;
3940

41+
/**
42+
* NB prior to 9.0 this was a TransportMasterNodeReadAction so for BwC it must be registered with the TransportService until
43+
* we no longer need to support calling this action remotely.
44+
*/
45+
@UpdateForV10(owner = UpdateForV10.Owner.DATA_MANAGEMENT)
46+
@SuppressWarnings("this-escape")
4047
@Inject
4148
public TransportGetComposableIndexTemplateAction(
4249
TransportService transportService,
4350
ClusterService clusterService,
44-
ThreadPool threadPool,
45-
ActionFilters actionFilters,
46-
IndexNameExpressionResolver indexNameExpressionResolver
51+
ActionFilters actionFilters
4752
) {
4853
super(
4954
GetComposableIndexTemplateAction.NAME,
50-
transportService,
51-
clusterService,
52-
threadPool,
5355
actionFilters,
54-
GetComposableIndexTemplateAction.Request::new,
55-
indexNameExpressionResolver,
56-
GetComposableIndexTemplateAction.Response::new,
56+
transportService.getTaskManager(),
57+
clusterService,
5758
EsExecutors.DIRECT_EXECUTOR_SERVICE
5859
);
5960
clusterSettings = clusterService.getClusterSettings();
61+
62+
transportService.registerRequestHandler(
63+
actionName,
64+
executor,
65+
false,
66+
true,
67+
GetComposableIndexTemplateAction.Request::new,
68+
(request, channel, task) -> executeDirect(task, request, new ChannelActionListener<>(channel))
69+
);
6070
}
6171

6272
@Override
@@ -65,12 +75,13 @@ protected ClusterBlockException checkBlock(GetComposableIndexTemplateAction.Requ
6575
}
6676

6777
@Override
68-
protected void masterOperation(
78+
protected void localClusterStateOperation(
6979
Task task,
7080
GetComposableIndexTemplateAction.Request request,
7181
ClusterState state,
7282
ActionListener<GetComposableIndexTemplateAction.Response> listener
7383
) {
84+
final var cancellableTask = (CancellableTask) task;
7485
Map<String, ComposableIndexTemplate> allTemplates = state.metadata().templatesV2();
7586
Map<String, ComposableIndexTemplate> results;
7687
// If we did not ask for a specific name, then we return all templates
@@ -91,6 +102,7 @@ protected void masterOperation(
91102
throw new ResourceNotFoundException("index template matching [" + request.name() + "] not found");
92103
}
93104
}
105+
cancellableTask.ensureNotCancelled();
94106
if (request.includeDefaults()) {
95107
listener.onResponse(
96108
new GetComposableIndexTemplateAction.Response(

0 commit comments

Comments
 (0)