Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Adjust /_cat/templates not to request all metadata #78812

Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
Original file line number Diff line number Diff line change
@@ -0,0 +1,179 @@
setup:
- do:
indices.put_template:
name: test-legacy-1
body:
order: 12
version: 3
index_patterns: foo*

- do:
indices.put_template:
name: test-legacy-2
body:
order: 45
version: 6
index_patterns:
- bar*
- baz*

- do:
cluster.put_component_template:
name: test-component-template
body:
template:
settings:
number_of_shards: 1
number_of_replicas: 0

- do:
indices.put_index_template:
name: test-composable-1
body:
index_patterns:
- quux*
priority: 78
version: 9
composed_of:
- test-component-template

- do:
indices.put_index_template:
name: test-composable-2
body:
index_patterns:
- gruly*
priority: 99
version: 1
composed_of:
- test-component-template

---
"Matching all templates":

- do:
cat.templates:
h: [name]
s: [name]

- match:
$body: /test-composable-1\ntest-composable-2\ntest-legacy-1\ntest-legacy-2\n/

- do:
cat.templates:
name: "*"
h: [name]
s: [name]

- match:
$body: /test-composable-1\ntest-composable-2\ntest-legacy-1\ntest-legacy-2\n/

---
"Matching all templates with other patterns":
- skip:
version: " - 7.99.99"
reason: "support for multiple patterns added in 8.0.0"

- do:
cat.templates:
name: "nonexistent*,*,other-name"
h: [name]
s: [name]

- match:
$body: /test-composable-1\ntest-composable-2\ntest-legacy-1\ntest-legacy-2\n/

---
"Matching no templates":

- do:
cat.templates:
name: "nonexistent"
h: [name]
s: [name]

- match:
$body: /^$/

---
"Matching single names":

- do:
cat.templates:
name: "test-legacy-1"
h: [name]
s: [name]

- match:
$body: /^test-legacy-1\n$/


- do:
cat.templates:
name: "test-composable-2"
h: [name]
s: [name]

- match:
$body: /^test-composable-2\n$/

---
"Matching single patterns":

- do:
cat.templates:
name: "test-legacy-*"
h: [name]
s: [name]

- match:
$body: /^test-legacy-1\ntest-legacy-2\n$/


- do:
cat.templates:
name: "test-*-2"
h: [name]
s: [name]

- match:
$body: /^test-composable-2\ntest-legacy-2\n$/

---
"Matching lists of names":
- skip:
version: " - 7.99.99"
reason: "support for multiple patterns added in 8.0.0"

- do:
cat.templates:
name: "test-legacy-1,test-composable-2"
h: [name]
s: [name]

- match:
$body: /^test-composable-2\ntest-legacy-1\n$/

---
"Matching names and wildcards":
- skip:
version: " - 7.99.99"
reason: "support for multiple patterns added in 8.0.0"

- do:
cat.templates:
name: "test-legacy-1,test-composable-*"
h: [name]
s: [name]

- match:
$body: /^test-composable-1\ntest-composable-2\ntest-legacy-1\n$/

- do:
cat.templates:
name: "test-legacy-*,test-composable-2"
h: [name]
s: [name]

- match:
$body: /^test-composable-2\ntest-legacy-1\ntest-legacy-2\n$/
Original file line number Diff line number Diff line change
Expand Up @@ -8,21 +8,27 @@

package org.elasticsearch.rest.action.cat;

import com.carrotsearch.hppc.cursors.ObjectObjectCursor;
import org.elasticsearch.action.admin.cluster.state.ClusterStateRequest;
import org.elasticsearch.action.admin.cluster.state.ClusterStateResponse;
import org.elasticsearch.action.ActionListener;
import org.elasticsearch.action.StepListener;
import org.elasticsearch.action.admin.indices.template.get.GetComposableIndexTemplateAction;
import org.elasticsearch.action.admin.indices.template.get.GetIndexTemplatesRequest;
import org.elasticsearch.action.admin.indices.template.get.GetIndexTemplatesResponse;
import org.elasticsearch.client.node.NodeClient;
import org.elasticsearch.cluster.metadata.IndexTemplateMetadata;
import org.elasticsearch.cluster.metadata.ComposableIndexTemplate;
import org.elasticsearch.cluster.metadata.Metadata;
import org.elasticsearch.cluster.metadata.IndexTemplateMetadata;
import org.elasticsearch.common.Strings;
import org.elasticsearch.common.Table;
import org.elasticsearch.common.regex.Regex;
import org.elasticsearch.rest.RestRequest;
import org.elasticsearch.rest.RestResponse;
import org.elasticsearch.rest.action.RestResponseListener;

import java.util.ArrayList;
import java.util.HashSet;
import java.util.List;
import java.util.Map;
import java.util.Set;
import java.util.function.Predicate;

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

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

@Override
protected RestChannelConsumer doCatRequest(final RestRequest request, NodeClient client) {
final String matchPattern = request.hasParam("name") ? request.param("name") : null;
final ClusterStateRequest clusterStateRequest = new ClusterStateRequest();
clusterStateRequest.clear().metadata(true);
clusterStateRequest.local(request.paramAsBoolean("local", clusterStateRequest.local()));
clusterStateRequest.masterNodeTimeout(request.paramAsTime("master_timeout", clusterStateRequest.masterNodeTimeout()));

return channel -> client.admin().cluster().state(clusterStateRequest, new RestResponseListener<ClusterStateResponse>(channel) {
@Override
public RestResponse buildResponse(ClusterStateResponse clusterStateResponse) throws Exception {
return RestTable.buildResponse(buildTable(request, clusterStateResponse, matchPattern), channel);
}
});
final String[] templateNames = Strings.splitStringByCommaToArray(request.param("name", ""));

final GetIndexTemplatesRequest getIndexTemplatesRequest = new GetIndexTemplatesRequest(templateNames);
getIndexTemplatesRequest.local(request.paramAsBoolean("local", getIndexTemplatesRequest.local()));
getIndexTemplatesRequest.masterNodeTimeout(request.paramAsTime("master_timeout", getIndexTemplatesRequest.masterNodeTimeout()));

final GetComposableIndexTemplateAction.Request getComposableTemplatesRequest
= new GetComposableIndexTemplateAction.Request();
getComposableTemplatesRequest.local(request.paramAsBoolean("local", getComposableTemplatesRequest.local()));
getComposableTemplatesRequest.masterNodeTimeout(
request.paramAsTime("master_timeout", getComposableTemplatesRequest.masterNodeTimeout()));

return channel -> {

final StepListener<GetIndexTemplatesResponse> getIndexTemplatesStep = new StepListener<>();
client.admin().indices().getTemplates(getIndexTemplatesRequest, getIndexTemplatesStep);

final StepListener<GetComposableIndexTemplateAction.Response> getComposableTemplatesStep = new StepListener<>();
client.execute(GetComposableIndexTemplateAction.INSTANCE, getComposableTemplatesRequest, getComposableTemplatesStep);

final ActionListener<Table> tableListener = new RestResponseListener<>(channel) {
@Override
public RestResponse buildResponse(Table table) throws Exception {
return RestTable.buildResponse(table, channel);
}
};

getIndexTemplatesStep.whenComplete(getIndexTemplatesResponse ->
getComposableTemplatesStep.whenComplete(getComposableIndexTemplatesResponse ->
ActionListener.completeWith(tableListener, () -> buildTable(
request,
getIndexTemplatesResponse,
getComposableIndexTemplatesResponse,
templateNames)
), tableListener::onFailure
), tableListener::onFailure);
};
}

@Override
Expand All @@ -74,26 +105,30 @@ protected Table getTableWithHeader(RestRequest request) {
return table;
}

private Table buildTable(RestRequest request, ClusterStateResponse clusterStateResponse, String patternString) {
Table table = getTableWithHeader(request);
Metadata metadata = clusterStateResponse.getState().metadata();
for (ObjectObjectCursor<String, IndexTemplateMetadata> entry : metadata.templates()) {
IndexTemplateMetadata indexData = entry.value;
if (patternString == null || Regex.simpleMatch(patternString, indexData.name())) {
table.startRow();
table.addCell(indexData.name());
table.addCell("[" + String.join(", ", indexData.patterns()) + "]");
table.addCell(indexData.getOrder());
table.addCell(indexData.getVersion());
table.addCell("");
table.endRow();
}
private Table buildTable(
RestRequest request,
GetIndexTemplatesResponse getIndexTemplatesResponse,
GetComposableIndexTemplateAction.Response getComposableIndexTemplatesResponse,
String[] requestedNames
) {
final Predicate<String> namePredicate = getNamePredicate(requestedNames);

final Table table = getTableWithHeader(request);
for (IndexTemplateMetadata indexData : getIndexTemplatesResponse.getIndexTemplates()) {
assert namePredicate.test(indexData.getName());
table.startRow();
table.addCell(indexData.name());
table.addCell("[" + String.join(", ", indexData.patterns()) + "]");
table.addCell(indexData.getOrder());
table.addCell(indexData.getVersion());
table.addCell("");
table.endRow();
}

for (Map.Entry<String, ComposableIndexTemplate> entry : metadata.templatesV2().entrySet()) {
String name = entry.getKey();
ComposableIndexTemplate template = entry.getValue();
if (patternString == null || Regex.simpleMatch(patternString, name)) {
for (Map.Entry<String, ComposableIndexTemplate> entry : getComposableIndexTemplatesResponse.indexTemplates().entrySet()) {
final String name = entry.getKey();
if (namePredicate.test(name)) {
final ComposableIndexTemplate template = entry.getValue();
table.startRow();
table.addCell(name);
table.addCell("[" + String.join(", ", template.indexPatterns()) + "]");
Expand All @@ -103,6 +138,41 @@ private Table buildTable(RestRequest request, ClusterStateResponse clusterStateR
table.endRow();
}
}

return table;
}

private Predicate<String> getNamePredicate(String[] requestedNames) {
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Why do we need this, shouldn't we rely on the template request to only returns stuff matching our initial cat request since we pass on the index name? (I'm sure we do, but I can't really figure out why I must admit :))

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

TransportGetComponentTemplateAction only accepts a single name or pattern and throws an exception if it's not found - it might be not found because it's a legacy template name or because it's really just not there but in any case this API doesn't return a 404 in that case, just an empty response. We could optimise for the one-argument case if we think the number of component templates will be ovewhelming otherwise, but I judge that it's ok to just get them all.

if (requestedNames.length == 0) {
return name -> true;
}

final Set<String> exactMatches = new HashSet<>();
final List<String> patterns = new ArrayList<>();
for (String requestedName : requestedNames) {
if (Regex.isMatchAllPattern(requestedName)) {
return name -> true;
} else if (Regex.isSimpleMatchPattern(requestedName)) {
patterns.add(requestedName);
} else {
exactMatches.add(requestedName);
}
}

if (patterns.isEmpty()) {
return exactMatches::contains;
}

return name -> {
if (exactMatches.contains(name)) {
return true;
}
for (String pattern : patterns) {
if (Regex.simpleMatch(pattern, name)) {
return true;
}
}
return false;
};
}
}