Provides a cat api endpoint for templates. (#20545)

Adds a cat api endpoint: /_cat/templates and its more specific version, /_cat/templates/{name}.

It looks something like:

$ curl "localhost:9200/_cat/templates?v"
name                  template     order version
sushi_california_roll *avocado*    1     1
pizza_hawaiian        *pineapples* 1
pizza_pepperoni       *pepperoni*  1

The specified version (only allows * globs) looks like:

$ curl "localhost:9200/_cat/templates/pizza*"
name            template     order version
pizza_hawaiian  *pineapples* 1
pizza_pepperoni *pepperoni*  1

Partially specified columns:

$ curl "localhost:9200/_cat/templates/pizza*?v=true&h=name,template"
name            template
pizza_hawaiian  *pineapples*
pizza_pepperoni *pepperoni*

The help text:

$ curl "localhost:9200/_cat/templates/pizza*?help"
name     | n | template name
template | t | template pattern string
order    | o | template application order number
version  | v | version

Closes #20467
This commit is contained in:
Alexander Lin 2016-09-20 01:40:23 -07:00 committed by Tanguy Leroux
parent 6921b4a66b
commit d31a8e6558
6 changed files with 340 additions and 0 deletions

View File

@ -288,6 +288,7 @@ import org.elasticsearch.rest.action.cat.RestSegmentsAction;
import org.elasticsearch.rest.action.cat.RestShardsAction;
import org.elasticsearch.rest.action.cat.RestSnapshotAction;
import org.elasticsearch.rest.action.cat.RestTasksAction;
import org.elasticsearch.rest.action.cat.RestTemplatesAction;
import org.elasticsearch.rest.action.cat.RestThreadPoolAction;
import org.elasticsearch.rest.action.document.RestBulkAction;
import org.elasticsearch.rest.action.document.RestDeleteAction;
@ -603,6 +604,7 @@ public class ActionModule extends AbstractModule {
registerRestHandler(handlers, RestNodeAttrsAction.class);
registerRestHandler(handlers, RestRepositoriesAction.class);
registerRestHandler(handlers, RestSnapshotAction.class);
registerRestHandler(handlers, RestTemplatesAction.class);
for (ActionPlugin plugin : actionPlugins) {
for (Class<? extends RestHandler> handler : plugin.getRestHandlers()) {
registerRestHandler(handlers, handler);

View File

@ -0,0 +1,97 @@
/*
* Licensed to Elasticsearch under one or more contributor
* license agreements. See the NOTICE file distributed with
* this work for additional information regarding copyright
* ownership. Elasticsearch licenses this file to you under
* the Apache License, Version 2.0 (the "License"); you may
* not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing,
* software distributed under the License is distributed on an
* "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
* KIND, either express or implied. See the License for the
* specific language governing permissions and limitations
* under the License.
*/
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.client.node.NodeClient;
import org.elasticsearch.cluster.metadata.IndexTemplateMetaData;
import org.elasticsearch.cluster.metadata.MetaData;
import org.elasticsearch.common.Table;
import org.elasticsearch.common.inject.Inject;
import org.elasticsearch.common.regex.Regex;
import org.elasticsearch.common.settings.Settings;
import org.elasticsearch.rest.RestChannel;
import org.elasticsearch.rest.RestController;
import org.elasticsearch.rest.RestRequest;
import org.elasticsearch.rest.RestResponse;
import org.elasticsearch.rest.action.RestResponseListener;
import static org.elasticsearch.rest.RestRequest.Method.GET;
public class RestTemplatesAction extends AbstractCatAction {
@Inject
public RestTemplatesAction(Settings settings, RestController controller) {
super(settings);
controller.registerHandler(GET, "/_cat/templates", this);
controller.registerHandler(GET, "/_cat/templates/{name}", this);
}
@Override
protected void documentation(StringBuilder sb) {
sb.append("/_cat/templates\n");
}
@Override
protected void doRequest(final RestRequest request, RestChannel channel, 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()));
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);
}
});
}
@Override
protected Table getTableWithHeader(RestRequest request) {
Table table = new Table();
table.startHeaders();
table.addCell("name", "alias:n;desc:template name");
table.addCell("template", "alias:t;desc:template pattern string");
table.addCell("order", "alias:o;desc:template application order number");
table.addCell("version", "alias:v;desc:version");
table.endHeaders();
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(indexData.getTemplate());
table.addCell(indexData.getOrder());
table.addCell(indexData.getVersion());
table.endRow();
}
}
return table;
}
}

View File

@ -186,3 +186,5 @@ include::cat/shards.asciidoc[]
include::cat/segments.asciidoc[]
include::cat/snapshots.asciidoc[]
include::cat/templates.asciidoc[]

View File

@ -0,0 +1,20 @@
[[cat-templates]]
== cat templates
The `templates` command provides information about existing templates.
[source, sh]
--------------------------------------------------
% curl 'localhost:9200/_cat/templates?v=true'
name template order version
template0 te* 0
template1 tea* 1
template2 teak* 2 7
--------------------------------------------------
The output shows that there are three existing templates,
with template_2 having a version value.
The endpoint also supports giving a template name or pattern in the url
to filter the results, for example `/_cat/templates/template*` or
`/_cat/templates/template0`.

View File

@ -0,0 +1,45 @@
{
"cat.templates": {
"documentation": "http://www.elastic.co/guide/en/elasticsearch/reference/master/cat-templates.html",
"methods": ["GET"],
"url": {
"path": "/_cat/templates",
"paths": ["/_cat/templates", "/_cat/templates/{name}"],
"parts": {
"name": {
"type" : "string",
"description" : "A pattern that returned template names must match"
}
},
"params": {
"format": {
"type" : "string",
"description" : "a short version of the Accept header, e.g. json, yaml"
},
"local": {
"type" : "boolean",
"description" : "Return local information, do not retrieve the state from master node (default: false)"
},
"master_timeout": {
"type" : "time",
"description" : "Explicit operation timeout for connection to master node"
},
"h": {
"type": "list",
"description" : "Comma-separated list of column names to display"
},
"help": {
"type": "boolean",
"description": "Return help information",
"default": false
},
"v": {
"type": "boolean",
"description": "Verbose mode. Display column headers",
"default": false
}
}
},
"body": null
}
}

View File

@ -0,0 +1,174 @@
---
"Help":
- do:
cat.templates:
help: true
- match:
$body: |
/^ name .+ \n
template .+ \n
order .+ \n
version .+ \n
$/
---
"No templates":
- do:
cat.templates: {}
- match:
$body: |
/^
$/
---
"Normal templates":
- do:
indices.put_template:
name: test
body:
order: 0
version: 1
template: test-*
settings:
number_of_shards: 1
number_of_replicas: 0
- do:
indices.put_template:
name: test_2
body:
order: 1
version: 2
template: test-2*
settings:
number_of_shards: 1
number_of_replicas: 0
- do:
cat.templates: {}
- match:
$body: /
(^|\n)test \s+
test-\* \s+
0 \s+
1
(\n|$)
/
- match:
$body: /
(^|\n)test_2 \s+
test-2\* \s+
1 \s+
2
(\n|$)
/
---
"Filtered templates":
- do:
indices.put_template:
name: test
body:
order: 0
version: 1
template: t*
settings:
number_of_shards: 1
number_of_replicas: 0
- do:
indices.put_template:
name: nomatch
body:
order: 2
version: 1
template: tea*
settings:
number_of_shards: 1
number_of_replicas: 0
- do:
cat.templates:
name: test*
- match:
$body: |
/^
test \s+
t\* \s+
0 \s+
1
\n
$/
---
"Column headers":
- do:
indices.put_template:
name: test
body:
order: 0
version: 1
template: t*
settings:
number_of_shards: 1
number_of_replicas: 0
- do:
cat.templates:
v: true
- match:
$body: |
/^
name \s+
template \s+
order \s+
version
\n
test \s+
t\* \s+
0 \s+
1
\n
$/
---
"Select columns":
- do:
indices.put_template:
name: test
body:
order: 0
version: 1
template: t*
settings:
number_of_shards: 1
number_of_replicas: 0
- do:
cat.templates:
h: [name, template]
v: true
- match:
$body: |
/^
name \s+
template
\n
test \s+
t\*
\n
$/