From d31a8e655885b38ee90b2e4c5af17d2af235695a Mon Sep 17 00:00:00 2001 From: Alexander Lin Date: Tue, 20 Sep 2016 01:40:23 -0700 Subject: [PATCH] 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 --- .../elasticsearch/action/ActionModule.java | 2 + .../rest/action/cat/RestTemplatesAction.java | 97 ++++++++++ docs/reference/cat.asciidoc | 2 + docs/reference/cat/templates.asciidoc | 20 ++ .../rest-api-spec/api/cat.templates.json | 45 +++++ .../test/cat.templates/10_basic.yaml | 174 ++++++++++++++++++ 6 files changed, 340 insertions(+) create mode 100644 core/src/main/java/org/elasticsearch/rest/action/cat/RestTemplatesAction.java create mode 100644 docs/reference/cat/templates.asciidoc create mode 100644 rest-api-spec/src/main/resources/rest-api-spec/api/cat.templates.json create mode 100644 rest-api-spec/src/main/resources/rest-api-spec/test/cat.templates/10_basic.yaml diff --git a/core/src/main/java/org/elasticsearch/action/ActionModule.java b/core/src/main/java/org/elasticsearch/action/ActionModule.java index c9e55a42ddd..a3797c3cb88 100644 --- a/core/src/main/java/org/elasticsearch/action/ActionModule.java +++ b/core/src/main/java/org/elasticsearch/action/ActionModule.java @@ -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 handler : plugin.getRestHandlers()) { registerRestHandler(handlers, handler); diff --git a/core/src/main/java/org/elasticsearch/rest/action/cat/RestTemplatesAction.java b/core/src/main/java/org/elasticsearch/rest/action/cat/RestTemplatesAction.java new file mode 100644 index 00000000000..5ee92cbb76c --- /dev/null +++ b/core/src/main/java/org/elasticsearch/rest/action/cat/RestTemplatesAction.java @@ -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(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 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; + } +} diff --git a/docs/reference/cat.asciidoc b/docs/reference/cat.asciidoc index 5fe080458aa..f29bc9badd2 100644 --- a/docs/reference/cat.asciidoc +++ b/docs/reference/cat.asciidoc @@ -186,3 +186,5 @@ include::cat/shards.asciidoc[] include::cat/segments.asciidoc[] include::cat/snapshots.asciidoc[] + +include::cat/templates.asciidoc[] diff --git a/docs/reference/cat/templates.asciidoc b/docs/reference/cat/templates.asciidoc new file mode 100644 index 00000000000..9a6dbead98a --- /dev/null +++ b/docs/reference/cat/templates.asciidoc @@ -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`. diff --git a/rest-api-spec/src/main/resources/rest-api-spec/api/cat.templates.json b/rest-api-spec/src/main/resources/rest-api-spec/api/cat.templates.json new file mode 100644 index 00000000000..f8aaa72723a --- /dev/null +++ b/rest-api-spec/src/main/resources/rest-api-spec/api/cat.templates.json @@ -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 + } +} diff --git a/rest-api-spec/src/main/resources/rest-api-spec/test/cat.templates/10_basic.yaml b/rest-api-spec/src/main/resources/rest-api-spec/test/cat.templates/10_basic.yaml new file mode 100644 index 00000000000..e2806b068f0 --- /dev/null +++ b/rest-api-spec/src/main/resources/rest-api-spec/test/cat.templates/10_basic.yaml @@ -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 + $/ +