Skip to content

Commit b07dbe5

Browse files
authored
Adjust /_cat/templates not to request all metadata (#78812)
Today `GET /_cat/templates` retrieves the whole cluster metadata from the master, which includes all sorts of unnecessary junk and consumes significant resources. This commit reimplements these endpoints using `GetIndexTemplatesAction` and `GetComposableIndexTemplateAction` which are much more efficient. The docs for this API indicate that it accepts a comma-separated list of template names/patterns of the form `GET /_cat/templates/name1,name2` but in fact today it only accepts a single name or pattern. This commit also adds support for multiple names/patterns as the docs claim.
1 parent dd4e4c3 commit b07dbe5

2 files changed

Lines changed: 284 additions & 35 deletions

File tree

Lines changed: 179 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,179 @@
1+
setup:
2+
- do:
3+
indices.put_template:
4+
name: test-legacy-1
5+
body:
6+
order: 12
7+
version: 3
8+
index_patterns: foo*
9+
10+
- do:
11+
indices.put_template:
12+
name: test-legacy-2
13+
body:
14+
order: 45
15+
version: 6
16+
index_patterns:
17+
- bar*
18+
- baz*
19+
20+
- do:
21+
cluster.put_component_template:
22+
name: test-component-template
23+
body:
24+
template:
25+
settings:
26+
number_of_shards: 1
27+
number_of_replicas: 0
28+
29+
- do:
30+
indices.put_index_template:
31+
name: test-composable-1
32+
body:
33+
index_patterns:
34+
- quux*
35+
priority: 78
36+
version: 9
37+
composed_of:
38+
- test-component-template
39+
40+
- do:
41+
indices.put_index_template:
42+
name: test-composable-2
43+
body:
44+
index_patterns:
45+
- gruly*
46+
priority: 99
47+
version: 1
48+
composed_of:
49+
- test-component-template
50+
51+
---
52+
"Matching all templates":
53+
54+
- do:
55+
cat.templates:
56+
h: [name]
57+
s: [name]
58+
59+
- match:
60+
$body: /test-composable-1\ntest-composable-2\ntest-legacy-1\ntest-legacy-2\n/
61+
62+
- do:
63+
cat.templates:
64+
name: "*"
65+
h: [name]
66+
s: [name]
67+
68+
- match:
69+
$body: /test-composable-1\ntest-composable-2\ntest-legacy-1\ntest-legacy-2\n/
70+
71+
---
72+
"Matching all templates with other patterns":
73+
- skip:
74+
version: " - 7.99.99"
75+
reason: "support for multiple patterns added in 8.0.0"
76+
77+
- do:
78+
cat.templates:
79+
name: "nonexistent*,*,other-name"
80+
h: [name]
81+
s: [name]
82+
83+
- match:
84+
$body: /test-composable-1\ntest-composable-2\ntest-legacy-1\ntest-legacy-2\n/
85+
86+
---
87+
"Matching no templates":
88+
89+
- do:
90+
cat.templates:
91+
name: "nonexistent"
92+
h: [name]
93+
s: [name]
94+
95+
- match:
96+
$body: /^$/
97+
98+
---
99+
"Matching single names":
100+
101+
- do:
102+
cat.templates:
103+
name: "test-legacy-1"
104+
h: [name]
105+
s: [name]
106+
107+
- match:
108+
$body: /^test-legacy-1\n$/
109+
110+
111+
- do:
112+
cat.templates:
113+
name: "test-composable-2"
114+
h: [name]
115+
s: [name]
116+
117+
- match:
118+
$body: /^test-composable-2\n$/
119+
120+
---
121+
"Matching single patterns":
122+
123+
- do:
124+
cat.templates:
125+
name: "test-legacy-*"
126+
h: [name]
127+
s: [name]
128+
129+
- match:
130+
$body: /^test-legacy-1\ntest-legacy-2\n$/
131+
132+
133+
- do:
134+
cat.templates:
135+
name: "test-*-2"
136+
h: [name]
137+
s: [name]
138+
139+
- match:
140+
$body: /^test-composable-2\ntest-legacy-2\n$/
141+
142+
---
143+
"Matching lists of names":
144+
- skip:
145+
version: " - 7.99.99"
146+
reason: "support for multiple patterns added in 8.0.0"
147+
148+
- do:
149+
cat.templates:
150+
name: "test-legacy-1,test-composable-2"
151+
h: [name]
152+
s: [name]
153+
154+
- match:
155+
$body: /^test-composable-2\ntest-legacy-1\n$/
156+
157+
---
158+
"Matching names and wildcards":
159+
- skip:
160+
version: " - 7.99.99"
161+
reason: "support for multiple patterns added in 8.0.0"
162+
163+
- do:
164+
cat.templates:
165+
name: "test-legacy-1,test-composable-*"
166+
h: [name]
167+
s: [name]
168+
169+
- match:
170+
$body: /^test-composable-1\ntest-composable-2\ntest-legacy-1\n$/
171+
172+
- do:
173+
cat.templates:
174+
name: "test-legacy-*,test-composable-2"
175+
h: [name]
176+
s: [name]
177+
178+
- match:
179+
$body: /^test-composable-2\ntest-legacy-1\ntest-legacy-2\n$/

server/src/main/java/org/elasticsearch/rest/action/cat/RestTemplatesAction.java

Lines changed: 105 additions & 35 deletions
Original file line numberDiff line numberDiff line change
@@ -8,21 +8,27 @@
88

99
package org.elasticsearch.rest.action.cat;
1010

11-
import com.carrotsearch.hppc.cursors.ObjectObjectCursor;
12-
import org.elasticsearch.action.admin.cluster.state.ClusterStateRequest;
13-
import org.elasticsearch.action.admin.cluster.state.ClusterStateResponse;
11+
import org.elasticsearch.action.ActionListener;
12+
import org.elasticsearch.action.StepListener;
13+
import org.elasticsearch.action.admin.indices.template.get.GetComposableIndexTemplateAction;
14+
import org.elasticsearch.action.admin.indices.template.get.GetIndexTemplatesRequest;
15+
import org.elasticsearch.action.admin.indices.template.get.GetIndexTemplatesResponse;
1416
import org.elasticsearch.client.node.NodeClient;
15-
import org.elasticsearch.cluster.metadata.IndexTemplateMetadata;
1617
import org.elasticsearch.cluster.metadata.ComposableIndexTemplate;
17-
import org.elasticsearch.cluster.metadata.Metadata;
18+
import org.elasticsearch.cluster.metadata.IndexTemplateMetadata;
19+
import org.elasticsearch.common.Strings;
1820
import org.elasticsearch.common.Table;
1921
import org.elasticsearch.common.regex.Regex;
2022
import org.elasticsearch.rest.RestRequest;
2123
import org.elasticsearch.rest.RestResponse;
2224
import org.elasticsearch.rest.action.RestResponseListener;
2325

26+
import java.util.ArrayList;
27+
import java.util.HashSet;
2428
import java.util.List;
2529
import java.util.Map;
30+
import java.util.Set;
31+
import java.util.function.Predicate;
2632

2733
import static org.elasticsearch.rest.RestRequest.Method.GET;
2834

@@ -47,18 +53,43 @@ protected void documentation(StringBuilder sb) {
4753

4854
@Override
4955
protected RestChannelConsumer doCatRequest(final RestRequest request, NodeClient client) {
50-
final String matchPattern = request.hasParam("name") ? request.param("name") : null;
51-
final ClusterStateRequest clusterStateRequest = new ClusterStateRequest();
52-
clusterStateRequest.clear().metadata(true);
53-
clusterStateRequest.local(request.paramAsBoolean("local", clusterStateRequest.local()));
54-
clusterStateRequest.masterNodeTimeout(request.paramAsTime("master_timeout", clusterStateRequest.masterNodeTimeout()));
55-
56-
return channel -> client.admin().cluster().state(clusterStateRequest, new RestResponseListener<ClusterStateResponse>(channel) {
57-
@Override
58-
public RestResponse buildResponse(ClusterStateResponse clusterStateResponse) throws Exception {
59-
return RestTable.buildResponse(buildTable(request, clusterStateResponse, matchPattern), channel);
60-
}
61-
});
56+
final String[] templateNames = Strings.splitStringByCommaToArray(request.param("name", ""));
57+
58+
final GetIndexTemplatesRequest getIndexTemplatesRequest = new GetIndexTemplatesRequest(templateNames);
59+
getIndexTemplatesRequest.local(request.paramAsBoolean("local", getIndexTemplatesRequest.local()));
60+
getIndexTemplatesRequest.masterNodeTimeout(request.paramAsTime("master_timeout", getIndexTemplatesRequest.masterNodeTimeout()));
61+
62+
final GetComposableIndexTemplateAction.Request getComposableTemplatesRequest
63+
= new GetComposableIndexTemplateAction.Request();
64+
getComposableTemplatesRequest.local(request.paramAsBoolean("local", getComposableTemplatesRequest.local()));
65+
getComposableTemplatesRequest.masterNodeTimeout(
66+
request.paramAsTime("master_timeout", getComposableTemplatesRequest.masterNodeTimeout()));
67+
68+
return channel -> {
69+
70+
final StepListener<GetIndexTemplatesResponse> getIndexTemplatesStep = new StepListener<>();
71+
client.admin().indices().getTemplates(getIndexTemplatesRequest, getIndexTemplatesStep);
72+
73+
final StepListener<GetComposableIndexTemplateAction.Response> getComposableTemplatesStep = new StepListener<>();
74+
client.execute(GetComposableIndexTemplateAction.INSTANCE, getComposableTemplatesRequest, getComposableTemplatesStep);
75+
76+
final ActionListener<Table> tableListener = new RestResponseListener<>(channel) {
77+
@Override
78+
public RestResponse buildResponse(Table table) throws Exception {
79+
return RestTable.buildResponse(table, channel);
80+
}
81+
};
82+
83+
getIndexTemplatesStep.whenComplete(getIndexTemplatesResponse ->
84+
getComposableTemplatesStep.whenComplete(getComposableIndexTemplatesResponse ->
85+
ActionListener.completeWith(tableListener, () -> buildTable(
86+
request,
87+
getIndexTemplatesResponse,
88+
getComposableIndexTemplatesResponse,
89+
templateNames)
90+
), tableListener::onFailure
91+
), tableListener::onFailure);
92+
};
6293
}
6394

6495
@Override
@@ -74,26 +105,30 @@ protected Table getTableWithHeader(RestRequest request) {
74105
return table;
75106
}
76107

77-
private Table buildTable(RestRequest request, ClusterStateResponse clusterStateResponse, String patternString) {
78-
Table table = getTableWithHeader(request);
79-
Metadata metadata = clusterStateResponse.getState().metadata();
80-
for (ObjectObjectCursor<String, IndexTemplateMetadata> entry : metadata.templates()) {
81-
IndexTemplateMetadata indexData = entry.value;
82-
if (patternString == null || Regex.simpleMatch(patternString, indexData.name())) {
83-
table.startRow();
84-
table.addCell(indexData.name());
85-
table.addCell("[" + String.join(", ", indexData.patterns()) + "]");
86-
table.addCell(indexData.getOrder());
87-
table.addCell(indexData.getVersion());
88-
table.addCell("");
89-
table.endRow();
90-
}
108+
private Table buildTable(
109+
RestRequest request,
110+
GetIndexTemplatesResponse getIndexTemplatesResponse,
111+
GetComposableIndexTemplateAction.Response getComposableIndexTemplatesResponse,
112+
String[] requestedNames
113+
) {
114+
final Predicate<String> namePredicate = getNamePredicate(requestedNames);
115+
116+
final Table table = getTableWithHeader(request);
117+
for (IndexTemplateMetadata indexData : getIndexTemplatesResponse.getIndexTemplates()) {
118+
assert namePredicate.test(indexData.getName());
119+
table.startRow();
120+
table.addCell(indexData.name());
121+
table.addCell("[" + String.join(", ", indexData.patterns()) + "]");
122+
table.addCell(indexData.getOrder());
123+
table.addCell(indexData.getVersion());
124+
table.addCell("");
125+
table.endRow();
91126
}
92127

93-
for (Map.Entry<String, ComposableIndexTemplate> entry : metadata.templatesV2().entrySet()) {
94-
String name = entry.getKey();
95-
ComposableIndexTemplate template = entry.getValue();
96-
if (patternString == null || Regex.simpleMatch(patternString, name)) {
128+
for (Map.Entry<String, ComposableIndexTemplate> entry : getComposableIndexTemplatesResponse.indexTemplates().entrySet()) {
129+
final String name = entry.getKey();
130+
if (namePredicate.test(name)) {
131+
final ComposableIndexTemplate template = entry.getValue();
97132
table.startRow();
98133
table.addCell(name);
99134
table.addCell("[" + String.join(", ", template.indexPatterns()) + "]");
@@ -103,6 +138,41 @@ private Table buildTable(RestRequest request, ClusterStateResponse clusterStateR
103138
table.endRow();
104139
}
105140
}
141+
106142
return table;
107143
}
144+
145+
private Predicate<String> getNamePredicate(String[] requestedNames) {
146+
if (requestedNames.length == 0) {
147+
return name -> true;
148+
}
149+
150+
final Set<String> exactMatches = new HashSet<>();
151+
final List<String> patterns = new ArrayList<>();
152+
for (String requestedName : requestedNames) {
153+
if (Regex.isMatchAllPattern(requestedName)) {
154+
return name -> true;
155+
} else if (Regex.isSimpleMatchPattern(requestedName)) {
156+
patterns.add(requestedName);
157+
} else {
158+
exactMatches.add(requestedName);
159+
}
160+
}
161+
162+
if (patterns.isEmpty()) {
163+
return exactMatches::contains;
164+
}
165+
166+
return name -> {
167+
if (exactMatches.contains(name)) {
168+
return true;
169+
}
170+
for (String pattern : patterns) {
171+
if (Regex.simpleMatch(pattern, name)) {
172+
return true;
173+
}
174+
}
175+
return false;
176+
};
177+
}
108178
}

0 commit comments

Comments
 (0)