From 5fe782b784f3007de2ad74db661bc73c7726e32a Mon Sep 17 00:00:00 2001 From: Colin Goodheart-Smithe Date: Tue, 12 Aug 2014 11:42:12 +0100 Subject: [PATCH] Indices API: Added GET Index API Returns information about settings, aliases, warmers, and mappings. Basically returns the IndexMetadata. This new endpoint replaces the /{index}/_alias|_aliases|_mapping|_mappings|_settings|_warmer|_warmers and /_alias|_aliases|_mapping|_mappings|_settings|_warmer|_warmers endpoints whilst maintaining the same response formats. The only exception to this is on the /_alias|_aliases|_warmer|_warmers endpoint which will now return a section for 'aliases' or 'warmers' even if no aliases or warmers exist. This backwards compatibility change is documented in the reference docs. Closes #4069 --- docs/reference/indices.asciidoc | 3 + docs/reference/indices/aliases.asciidoc | 2 + docs/reference/indices/get-index.asciidoc | 30 ++ docs/reference/indices/warmers.asciidoc | 7 +- docs/reference/migration/migrate_1_x.asciidoc | 22 ++ rest-api-spec/api/indices.get.json | 38 ++ .../50_wildcard_expansion.yaml | 3 +- .../indices.put_mapping/all_path_options.yaml | 6 +- rest-api-spec/test/indices/get/10_basic.yaml | 192 ++++++++++ .../elasticsearch/action/ActionModule.java | 3 + .../admin/indices/get/GetIndexAction.java | 45 +++ .../admin/indices/get/GetIndexRequest.java | 67 ++++ .../indices/get/GetIndexRequestBuilder.java | 50 +++ .../admin/indices/get/GetIndexResponse.java | 192 ++++++++++ .../indices/get/TransportGetIndexAction.java | 113 ++++++ .../client/IndicesAdminClient.java | 32 +- .../support/AbstractIndicesAdminClient.java | 27 +- .../elasticsearch/common/path/PathTrie.java | 9 +- .../rest/action/RestActionModule.java | 2 + .../alias/get/RestGetAliasesAction.java | 2 - .../get/RestGetIndicesAliasesAction.java | 2 - .../indices/get/RestGetIndicesAction.java | 160 +++++++++ .../mapping/get/RestGetMappingAction.java | 2 - .../settings/RestGetSettingsAction.java | 2 - .../warmer/get/RestGetWarmerAction.java | 2 - .../admin/indices/get/GetIndexTests.java | 334 ++++++++++++++++++ .../common/path/PathTrieTests.java | 4 + .../transport/ActionNamesTests.java | 2 + 28 files changed, 1329 insertions(+), 24 deletions(-) create mode 100644 docs/reference/indices/get-index.asciidoc create mode 100644 rest-api-spec/api/indices.get.json create mode 100644 rest-api-spec/test/indices/get/10_basic.yaml create mode 100644 src/main/java/org/elasticsearch/action/admin/indices/get/GetIndexAction.java create mode 100644 src/main/java/org/elasticsearch/action/admin/indices/get/GetIndexRequest.java create mode 100644 src/main/java/org/elasticsearch/action/admin/indices/get/GetIndexRequestBuilder.java create mode 100644 src/main/java/org/elasticsearch/action/admin/indices/get/GetIndexResponse.java create mode 100644 src/main/java/org/elasticsearch/action/admin/indices/get/TransportGetIndexAction.java create mode 100644 src/main/java/org/elasticsearch/rest/action/admin/indices/get/RestGetIndicesAction.java create mode 100644 src/test/java/org/elasticsearch/action/admin/indices/get/GetIndexTests.java diff --git a/docs/reference/indices.asciidoc b/docs/reference/indices.asciidoc index 2d51a0e252e..d7e7dd6627a 100644 --- a/docs/reference/indices.asciidoc +++ b/docs/reference/indices.asciidoc @@ -13,6 +13,7 @@ and warmers. * <> * <> +* <> * <> * <> @@ -61,6 +62,8 @@ include::indices/create-index.asciidoc[] include::indices/delete-index.asciidoc[] +include::indices/get-index.asciidoc[] + include::indices/indices-exists.asciidoc[] include::indices/open-close.asciidoc[] diff --git a/docs/reference/indices/aliases.asciidoc b/docs/reference/indices/aliases.asciidoc index 8c99b892e90..af51de69478 100644 --- a/docs/reference/indices/aliases.asciidoc +++ b/docs/reference/indices/aliases.asciidoc @@ -314,6 +314,8 @@ Possible options: The rest endpoint is: `/{index}/_alias/{alias}`. +coming[1.4.0,The API will always include an `aliases` section, even if there aren't any aliases. Previous versions would not return the `aliases` section] + [float] ==== Examples: diff --git a/docs/reference/indices/get-index.asciidoc b/docs/reference/indices/get-index.asciidoc new file mode 100644 index 00000000000..78cfa074550 --- /dev/null +++ b/docs/reference/indices/get-index.asciidoc @@ -0,0 +1,30 @@ +[[indices-get-index]] +== Get Index + +The get index API allows to retrieve information about one or more indexes. + +[source,js] +-------------------------------------------------- +$ curl -XGET 'http://localhost:9200/twitter/' +-------------------------------------------------- + +The above example gets the information for an index called `twitter`. Specifying an index, +alias or wildcard expression is required. + +The get index API can also be applied to more than one index, or on +all indices by using `_all` or `*` as index. + +[float] +=== Filtering index information + +The information returned by the get API can be filtered to include only specific features +by specifying a comma delimited list of features in the URL: + +[source,js] +-------------------------------------------------- +$ curl -XGET 'http://localhost:9200/twitter/_settings,_mappings' +-------------------------------------------------- + +The above command will only return the settings and mappings for the index called `twitter`. + +The available features are `_settings`, `_mappings`, `_warmers` and `_aliases`. \ No newline at end of file diff --git a/docs/reference/indices/warmers.asciidoc b/docs/reference/indices/warmers.asciidoc index c1635dde4cf..3df10c5c6dc 100644 --- a/docs/reference/indices/warmers.asciidoc +++ b/docs/reference/indices/warmers.asciidoc @@ -180,7 +180,11 @@ Instead of `_warmer` you can also use the plural `_warmers`. Getting a warmer for specific index (or alias, or several indices) based on its name. The provided name can be a simple wildcard expression or -omitted to get all warmers. Some examples: +omitted to get all warmers. + +coming[1.4.0,The API will always include a `warmers` section, even if there aren't any warmers. Previous versions would not return the `warmers` section] + +Some examples: [source,js] -------------------------------------------------- @@ -193,3 +197,4 @@ curl -XGET localhost:9200/test/_warmer/warm* # get all warmers for test index curl -XGET localhost:9200/test/_warmer/ -------------------------------------------------- + diff --git a/docs/reference/migration/migrate_1_x.asciidoc b/docs/reference/migration/migrate_1_x.asciidoc index 407ac0136ef..72378087e62 100644 --- a/docs/reference/migration/migrate_1_x.asciidoc +++ b/docs/reference/migration/migrate_1_x.asciidoc @@ -36,3 +36,25 @@ pointed to by the alias. Add or update a mapping via the <> or <> apis. +==== Indices APIs + +The <> will return a section for `warmers` even if there are +no warmers. This ensures that the following two examples are equivalent: + +[source,js] +-------------------------------------------------- +curl -XGET 'http://localhost:9200/_all/_warmers' + +curl -XGET 'http://localhost:9200/_warmers' +-------------------------------------------------- + +Similarly, the <> will return a section for `aliases` even if there are +no aliases. This ensures that the following two examples are equivalent: + +[source,js] +-------------------------------------------------- +curl -XGET 'http://localhost:9200/_all/_aliases' + +curl -XGET 'http://localhost:9200/_aliases' +-------------------------------------------------- + diff --git a/rest-api-spec/api/indices.get.json b/rest-api-spec/api/indices.get.json new file mode 100644 index 00000000000..51967934b9f --- /dev/null +++ b/rest-api-spec/api/indices.get.json @@ -0,0 +1,38 @@ +{ + "indices.get":{ + "documentation":"http://www.elasticsearch.org/guide/en/elasticsearch/reference/master/indices-get.html", + "methods":[ "GET" ], + "url":{ + "path":"/{index}", + "paths":[ "/{index}", "/{index}/{feature}" ], + "parts":{ + "index":{ + "type":"list", + "description":"A comma-separated list of index names" + }, + "feature":{ + "type":"list", + "description":"A comma-separated list of features" + } + }, + "params":{ + "local":{ + "type":"boolean", + "description":"Return local information, do not retrieve the state from master node (default: false)" + }, + "ignore_unavailable":{ + "type":"boolean", + "description":"Ignore unavailable indexes (default: false)" + }, + "allow_no_indices":{ + "type":"boolean", + "description":"Ignore if a wildcard expression resolves to no concrete indices (default: false)" + }, + "expand_wildcards":{ + "type":"list", + "description":"Whether wildcard expressions should get expanded to open or closed indices (default: open)" + } + } + } + } +} \ No newline at end of file diff --git a/rest-api-spec/test/indices.get_mapping/50_wildcard_expansion.yaml b/rest-api-spec/test/indices.get_mapping/50_wildcard_expansion.yaml index 316c98e6271..84a7a5bd9b3 100644 --- a/rest-api-spec/test/indices.get_mapping/50_wildcard_expansion.yaml +++ b/rest-api-spec/test/indices.get_mapping/50_wildcard_expansion.yaml @@ -96,11 +96,12 @@ setup: "Get test-* with wildcard_expansion=none": - do: - catch: missing indices.get_mapping: index: test-x* expand_wildcards: none + - match: { $body: "{}" } + --- "Get test-* with wildcard_expansion=open,closed": diff --git a/rest-api-spec/test/indices.put_mapping/all_path_options.yaml b/rest-api-spec/test/indices.put_mapping/all_path_options.yaml index 23b02f2cde2..174fa83b787 100644 --- a/rest-api-spec/test/indices.put_mapping/all_path_options.yaml +++ b/rest-api-spec/test/indices.put_mapping/all_path_options.yaml @@ -43,7 +43,7 @@ setup: - match: {test_index2.mappings.test_type.properties.text.type: string} - match: {test_index2.mappings.test_type.properties.text.analyzer: whitespace} - - is_false: foo + - match: { foo.mappings: {} } --- "put mapping in _all index": @@ -118,7 +118,7 @@ setup: - match: {test_index2.mappings.test_type.properties.text.type: string} - match: {test_index2.mappings.test_type.properties.text.analyzer: whitespace} - - is_false: foo + - match: { foo.mappings: {} } --- "put mapping in list of indices": @@ -142,7 +142,7 @@ setup: - match: {test_index2.mappings.test_type.properties.text.type: string} - match: {test_index2.mappings.test_type.properties.text.analyzer: whitespace} - - is_false: foo + - match: { foo.mappings: {} } --- "put mapping with blank index": diff --git a/rest-api-spec/test/indices/get/10_basic.yaml b/rest-api-spec/test/indices/get/10_basic.yaml new file mode 100644 index 00000000000..5bf963b2dd0 --- /dev/null +++ b/rest-api-spec/test/indices/get/10_basic.yaml @@ -0,0 +1,192 @@ +--- +setup: + + - do: + indices.create: + index: test_index + body: + aliases: + test_alias: {} + test_blias: {} + mappings: + type_1: {} + warmers: + test_warmer: + source: + query: + match_all: {} + settings: + number_of_shards: 1 + number_of_replicas: 1 + + - do: + indices.create: + index: test_index_2 + body: + settings: + number_of_shards: 1 + number_of_replicas: 2 + aliases: + test_alias: {} + test_blias: {} + + - do: + indices.create: + index: test_index_3 + body: + aliases: + test_alias: {} + test_blias: {} + + - do: + cluster.health: + wait_for_status: yellow + + - do: + indices.close: + index: test_index_3 + + - do: + cluster.health: + wait_for_status: yellow + +--- +"Get index infos": + + - do: + indices.get: + index: test_index + + - is_true: test_index.aliases + - is_true: test_index.settings + - is_true: test_index.warmers + - is_true: test_index.mappings + +--- +"Get index infos for mappings only": + + - do: + indices.get: + index: test_index + feature: _mapping + + - is_true: test_index.mappings + - is_false: test_index.aliases + - is_false: test_index.settings + - is_false: test_index.warmers + +--- +"Get index infos for mappings and warmers only": + + - do: + indices.get: + index: test_index + feature: _mapping,_warmer + + - is_true: test_index.mappings + - is_true: test_index.warmers + - is_false: test_index.aliases + - is_false: test_index.settings + +--- +"Get index infos should work on aliases": + + - do: + indices.get: + index: test_blias + feature: _mapping,_warmer + + - is_true: test_index.mappings + - is_true: test_index.warmers + - is_false: test_index.aliases + - is_false: test_index.settings + +--- +"Get index infos should work for wildcards": + + - do: + indices.get: + index: test_* + feature: _mapping,_settings + + - is_true: test_index.mappings + - is_true: test_index.settings + - is_true: test_index_2.settings + - is_false: test_index.aliases + - is_false: test_index.warmers + +--- +"Missing index should throw an Error": + + - do: + catch: missing + indices.get: + index: test_not_found + +--- +"Missing index should return empty object if ignore_unavailable": + + - do: + indices.get: + index: test_not_found + ignore_unavailable: true + + - match: { $body: "{}" } + +--- +"Should return empty object if allow_no_indices": + + - do: + indices.get: + index: test_not* + + - match: { $body: "{}" } + +--- +"Should throw error if allow_no_indices=false": + + - do: + catch: missing + indices.get: + index: test_not* + allow_no_indices: false + +--- +"Should return test_index_2 if expand_wildcards=open": + + - do: + indices.get: + index: test_index_* + expand_wildcards: open + + - is_true: test_index_2.settings + - is_false: test_index_3.settings + +--- +"Should return test_index_3 if expand_wildcards=closed": + + - skip: + version: "0 - 2.0.0" + reason: Requires fix for issue 7258 + + - do: + indices.get: + index: test_index_* + feature: _settings + expand_wildcards: closed + + - is_false: test_index_2.settings + - is_true: test_index_3.settings + +--- +"Should return test_index_2 and test_index_3 if expand_wildcards=open,closed": + + - do: + indices.get: + index: test_index_* + feature: _settings + expand_wildcards: open,closed + + - is_true: test_index_2.settings + - is_true: test_index_3.settings + diff --git a/src/main/java/org/elasticsearch/action/ActionModule.java b/src/main/java/org/elasticsearch/action/ActionModule.java index 8917b16c061..579d9556ebc 100644 --- a/src/main/java/org/elasticsearch/action/ActionModule.java +++ b/src/main/java/org/elasticsearch/action/ActionModule.java @@ -83,6 +83,8 @@ import org.elasticsearch.action.admin.indices.exists.types.TransportTypesExistsA import org.elasticsearch.action.admin.indices.exists.types.TypesExistsAction; import org.elasticsearch.action.admin.indices.flush.FlushAction; import org.elasticsearch.action.admin.indices.flush.TransportFlushAction; +import org.elasticsearch.action.admin.indices.get.GetIndexAction; +import org.elasticsearch.action.admin.indices.get.TransportGetIndexAction; import org.elasticsearch.action.admin.indices.mapping.delete.DeleteMappingAction; import org.elasticsearch.action.admin.indices.mapping.delete.TransportDeleteMappingAction; import org.elasticsearch.action.admin.indices.mapping.get.*; @@ -246,6 +248,7 @@ public class ActionModule extends AbstractModule { registerAction(IndicesSegmentsAction.INSTANCE, TransportIndicesSegmentsAction.class); registerAction(CreateIndexAction.INSTANCE, TransportCreateIndexAction.class); registerAction(DeleteIndexAction.INSTANCE, TransportDeleteIndexAction.class); + registerAction(GetIndexAction.INSTANCE, TransportGetIndexAction.class); registerAction(OpenIndexAction.INSTANCE, TransportOpenIndexAction.class); registerAction(CloseIndexAction.INSTANCE, TransportCloseIndexAction.class); registerAction(IndicesExistsAction.INSTANCE, TransportIndicesExistsAction.class); diff --git a/src/main/java/org/elasticsearch/action/admin/indices/get/GetIndexAction.java b/src/main/java/org/elasticsearch/action/admin/indices/get/GetIndexAction.java new file mode 100644 index 00000000000..6481808c616 --- /dev/null +++ b/src/main/java/org/elasticsearch/action/admin/indices/get/GetIndexAction.java @@ -0,0 +1,45 @@ +/* + * 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.action.admin.indices.get; + +import org.elasticsearch.action.admin.indices.IndicesAction; +import org.elasticsearch.client.IndicesAdminClient; + +/** + */ +public class GetIndexAction extends IndicesAction { + + public static final GetIndexAction INSTANCE = new GetIndexAction(); + public static final String NAME = "indices:admin/get"; + + private GetIndexAction() { + super(NAME); + } + + @Override + public GetIndexRequestBuilder newRequestBuilder(IndicesAdminClient client) { + return new GetIndexRequestBuilder(client); + } + + @Override + public GetIndexResponse newResponse() { + return new GetIndexResponse(); + } +} diff --git a/src/main/java/org/elasticsearch/action/admin/indices/get/GetIndexRequest.java b/src/main/java/org/elasticsearch/action/admin/indices/get/GetIndexRequest.java new file mode 100644 index 00000000000..2a0a881a93d --- /dev/null +++ b/src/main/java/org/elasticsearch/action/admin/indices/get/GetIndexRequest.java @@ -0,0 +1,67 @@ +/* + * 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.action.admin.indices.get; + +import org.elasticsearch.ElasticsearchIllegalArgumentException; +import org.elasticsearch.action.ActionRequestValidationException; +import org.elasticsearch.action.support.master.info.ClusterInfoRequest; +import org.elasticsearch.common.io.stream.StreamInput; +import org.elasticsearch.common.io.stream.StreamOutput; + +import java.io.IOException; + +/** + * A request to delete an index. Best created with {@link org.elasticsearch.client.Requests#deleteIndexRequest(String)}. + */ +public class GetIndexRequest extends ClusterInfoRequest { + + private String[] features = new String[] { "_settings", "_warmers", "_mappings", "_aliases" }; + + public GetIndexRequest features(String[] features) { + if (features == null) { + throw new ElasticsearchIllegalArgumentException("features cannot be null"); + } else { + this.features = features; + } + return this; + } + + public String[] features() { + return features; + } + + @Override + public ActionRequestValidationException validate() { + return null; + } + + @Override + public void readFrom(StreamInput in) throws IOException { + super.readFrom(in); + features = in.readStringArray(); + } + + @Override + public void writeTo(StreamOutput out) throws IOException { + super.writeTo(out); + out.writeStringArray(features); + } + +} diff --git a/src/main/java/org/elasticsearch/action/admin/indices/get/GetIndexRequestBuilder.java b/src/main/java/org/elasticsearch/action/admin/indices/get/GetIndexRequestBuilder.java new file mode 100644 index 00000000000..984ea141e5e --- /dev/null +++ b/src/main/java/org/elasticsearch/action/admin/indices/get/GetIndexRequestBuilder.java @@ -0,0 +1,50 @@ +/* + * 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.action.admin.indices.get; + +import com.google.common.collect.ObjectArrays; +import org.elasticsearch.action.ActionListener; +import org.elasticsearch.action.support.master.info.ClusterInfoRequestBuilder; +import org.elasticsearch.client.IndicesAdminClient; + +/** + * + */ +public class GetIndexRequestBuilder extends ClusterInfoRequestBuilder { + + public GetIndexRequestBuilder(IndicesAdminClient client, String... indices) { + super(client, new GetIndexRequest().indices(indices)); + } + + public GetIndexRequestBuilder setFeatures(String... features) { + request.features(features); + return this; + } + + public GetIndexRequestBuilder addFeatures(String... features) { + request.features(ObjectArrays.concat(request.features(), features, String.class)); + return this; + } + + @Override + protected void doExecute(ActionListener listener) { + client.getIndex(request, listener); + } +} diff --git a/src/main/java/org/elasticsearch/action/admin/indices/get/GetIndexResponse.java b/src/main/java/org/elasticsearch/action/admin/indices/get/GetIndexResponse.java new file mode 100644 index 00000000000..f09a298092e --- /dev/null +++ b/src/main/java/org/elasticsearch/action/admin/indices/get/GetIndexResponse.java @@ -0,0 +1,192 @@ +/* + * 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.action.admin.indices.get; + +import com.carrotsearch.hppc.cursors.ObjectObjectCursor; +import com.google.common.collect.ImmutableList; +import org.elasticsearch.action.ActionResponse; +import org.elasticsearch.cluster.metadata.AliasMetaData; +import org.elasticsearch.cluster.metadata.MappingMetaData; +import org.elasticsearch.common.collect.ImmutableOpenMap; +import org.elasticsearch.common.io.stream.StreamInput; +import org.elasticsearch.common.io.stream.StreamOutput; +import org.elasticsearch.common.settings.ImmutableSettings; +import org.elasticsearch.common.settings.Settings; +import org.elasticsearch.search.warmer.IndexWarmersMetaData; + +import java.io.IOException; + +/** + * A response for a delete index action. + */ +public class GetIndexResponse extends ActionResponse { + + private ImmutableOpenMap> warmers = ImmutableOpenMap.of(); + private ImmutableOpenMap> mappings = ImmutableOpenMap.of(); + private ImmutableOpenMap> aliases = ImmutableOpenMap.of(); + private ImmutableOpenMap settings = ImmutableOpenMap.of(); + private String[] indices; + + GetIndexResponse(String[] indices, ImmutableOpenMap> warmers, + ImmutableOpenMap> mappings, + ImmutableOpenMap> aliases, ImmutableOpenMap settings) { + this.indices = indices; + this.warmers = warmers; + this.mappings = mappings; + this.aliases = aliases; + this.settings = settings; + } + + GetIndexResponse() { + } + + public String[] indices() { + return indices; + } + + public String[] getIndices() { + return indices(); + } + + public ImmutableOpenMap> warmers() { + return warmers; + } + + public ImmutableOpenMap> getWarmers() { + return warmers(); + } + + public ImmutableOpenMap> mappings() { + return mappings; + } + + public ImmutableOpenMap> getMappings() { + return mappings(); + } + + public ImmutableOpenMap> aliases() { + return aliases; + } + + public ImmutableOpenMap> getAliases() { + return aliases(); + } + + public ImmutableOpenMap settings() { + return settings; + } + + public ImmutableOpenMap getSettings() { + return settings(); + } + + @Override + public void readFrom(StreamInput in) throws IOException { + super.readFrom(in); + this.indices = in.readStringArray(); + int warmersSize = in.readVInt(); + ImmutableOpenMap.Builder> warmersMapBuilder = ImmutableOpenMap.builder(); + for (int i = 0; i < warmersSize; i++) { + String key = in.readString(); + int valueSize = in.readVInt(); + ImmutableList.Builder warmerEntryBuilder = ImmutableList.builder(); + for (int j = 0; j < valueSize; j++) { + warmerEntryBuilder.add(new IndexWarmersMetaData.Entry( + in.readString(), + in.readStringArray(), + in.readOptionalBoolean(), + in.readBytesReference()) + ); + } + warmersMapBuilder.put(key, warmerEntryBuilder.build()); + } + warmers = warmersMapBuilder.build(); + int mappingsSize = in.readVInt(); + ImmutableOpenMap.Builder> mappingsMapBuilder = ImmutableOpenMap.builder(); + for (int i = 0; i < mappingsSize; i++) { + String key = in.readString(); + int valueSize = in.readVInt(); + ImmutableOpenMap.Builder mappingEntryBuilder = ImmutableOpenMap.builder(); + for (int j = 0; j < valueSize; j++) { + mappingEntryBuilder.put(in.readString(), MappingMetaData.readFrom(in)); + } + mappingsMapBuilder.put(key, mappingEntryBuilder.build()); + } + mappings = mappingsMapBuilder.build(); + int aliasesSize = in.readVInt(); + ImmutableOpenMap.Builder> aliasesMapBuilder = ImmutableOpenMap.builder(); + for (int i = 0; i < aliasesSize; i++) { + String key = in.readString(); + int valueSize = in.readVInt(); + ImmutableList.Builder aliasEntryBuilder = ImmutableList.builder(); + for (int j = 0; j < valueSize; j++) { + aliasEntryBuilder.add(AliasMetaData.Builder.readFrom(in)); + } + aliasesMapBuilder.put(key, aliasEntryBuilder.build()); + } + aliases = aliasesMapBuilder.build(); + int settingsSize = in.readVInt(); + ImmutableOpenMap.Builder settingsMapBuilder = ImmutableOpenMap.builder(); + for (int i = 0; i < settingsSize; i++) { + String key = in.readString(); + settingsMapBuilder.put(key, ImmutableSettings.readSettingsFromStream(in)); + } + settings = settingsMapBuilder.build(); + } + + @Override + public void writeTo(StreamOutput out) throws IOException { + super.writeTo(out); + out.writeStringArray(indices); + out.writeVInt(warmers.size()); + for (ObjectObjectCursor> indexEntry : warmers) { + out.writeString(indexEntry.key); + out.writeVInt(indexEntry.value.size()); + for (IndexWarmersMetaData.Entry warmerEntry : indexEntry.value) { + out.writeString(warmerEntry.name()); + out.writeStringArray(warmerEntry.types()); + out.writeOptionalBoolean(warmerEntry.queryCache()); + out.writeBytesReference(warmerEntry.source()); + } + } + out.writeVInt(mappings.size()); + for (ObjectObjectCursor> indexEntry : mappings) { + out.writeString(indexEntry.key); + out.writeVInt(indexEntry.value.size()); + for (ObjectObjectCursor mappingEntry : indexEntry.value) { + out.writeString(mappingEntry.key); + MappingMetaData.writeTo(mappingEntry.value, out); + } + } + out.writeVInt(aliases.size()); + for (ObjectObjectCursor> indexEntry : aliases) { + out.writeString(indexEntry.key); + out.writeVInt(indexEntry.value.size()); + for (AliasMetaData aliasEntry : indexEntry.value) { + AliasMetaData.Builder.writeTo(aliasEntry, out); + } + } + out.writeVInt(settings.size()); + for (ObjectObjectCursor indexEntry : settings) { + out.writeString(indexEntry.key); + ImmutableSettings.writeSettingsToStream(indexEntry.value, out); + } + } +} diff --git a/src/main/java/org/elasticsearch/action/admin/indices/get/TransportGetIndexAction.java b/src/main/java/org/elasticsearch/action/admin/indices/get/TransportGetIndexAction.java new file mode 100644 index 00000000000..992ec8adf36 --- /dev/null +++ b/src/main/java/org/elasticsearch/action/admin/indices/get/TransportGetIndexAction.java @@ -0,0 +1,113 @@ +/* + * 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.action.admin.indices.get; + +import com.google.common.collect.ImmutableList; +import org.elasticsearch.ElasticsearchException; +import org.elasticsearch.ElasticsearchIllegalStateException; +import org.elasticsearch.action.ActionListener; +import org.elasticsearch.action.support.ActionFilters; +import org.elasticsearch.action.support.master.info.TransportClusterInfoAction; +import org.elasticsearch.cluster.ClusterService; +import org.elasticsearch.cluster.ClusterState; +import org.elasticsearch.cluster.metadata.AliasMetaData; +import org.elasticsearch.cluster.metadata.MappingMetaData; +import org.elasticsearch.common.Strings; +import org.elasticsearch.common.collect.ImmutableOpenMap; +import org.elasticsearch.common.inject.Inject; +import org.elasticsearch.common.settings.Settings; +import org.elasticsearch.search.warmer.IndexWarmersMetaData.Entry; +import org.elasticsearch.threadpool.ThreadPool; +import org.elasticsearch.transport.TransportService; + +/** + * Get index action. + */ +public class TransportGetIndexAction extends TransportClusterInfoAction { + + @Inject + public TransportGetIndexAction(Settings settings, TransportService transportService, ClusterService clusterService, + ThreadPool threadPool, ActionFilters actionFilters) { + super(settings, GetIndexAction.NAME, transportService, clusterService, threadPool, actionFilters); + } + + @Override + protected GetIndexRequest newRequest() { + return new GetIndexRequest(); + } + + @Override + protected GetIndexResponse newResponse() { + return new GetIndexResponse(); + } + + @Override + protected void doMasterOperation(final GetIndexRequest request, String[] concreteIndices, final ClusterState state, + final ActionListener listener) throws ElasticsearchException { + ImmutableOpenMap> warmersResult = ImmutableOpenMap.of(); + ImmutableOpenMap> mappingsResult = ImmutableOpenMap.of(); + ImmutableOpenMap> aliasesResult = ImmutableOpenMap.of(); + ImmutableOpenMap settings = ImmutableOpenMap.of(); + String[] features = request.features(); + boolean doneAliases = false; + boolean doneMappings = false; + boolean doneSettings = false; + boolean doneWarmers = false; + for (String feature : features) { + switch (feature) { + case "_warmer": + case "_warmers": + if (!doneWarmers) { + warmersResult = state.metaData().findWarmers(concreteIndices, request.types(), Strings.EMPTY_ARRAY); + doneWarmers = true; + } + break; + case "_mapping": + case "_mappings": + if (!doneMappings) { + mappingsResult = state.metaData().findMappings(concreteIndices, request.types()); + doneMappings = true; + } + break; + case "_alias": + case "_aliases": + if (!doneAliases) { + aliasesResult = state.metaData().findAliases(Strings.EMPTY_ARRAY, concreteIndices); + doneAliases = true; + } + break; + case "_settings": + if (!doneSettings) { + ImmutableOpenMap.Builder settingsMapBuilder = ImmutableOpenMap.builder(); + for (String index : concreteIndices) { + settingsMapBuilder.put(index, state.metaData().index(index).getSettings()); + } + settings = settingsMapBuilder.build(); + doneSettings = true; + } + break; + + default: + throw new ElasticsearchIllegalStateException("feature [" + feature + "] is not valid"); + } + } + listener.onResponse(new GetIndexResponse(concreteIndices, warmersResult, mappingsResult, aliasesResult, settings)); + } +} diff --git a/src/main/java/org/elasticsearch/client/IndicesAdminClient.java b/src/main/java/org/elasticsearch/client/IndicesAdminClient.java index b720c918fc4..609a5450e84 100644 --- a/src/main/java/org/elasticsearch/client/IndicesAdminClient.java +++ b/src/main/java/org/elasticsearch/client/IndicesAdminClient.java @@ -19,7 +19,8 @@ package org.elasticsearch.client; -import org.elasticsearch.action.*; +import org.elasticsearch.action.ActionFuture; +import org.elasticsearch.action.ActionListener; import org.elasticsearch.action.admin.indices.alias.IndicesAliasesRequest; import org.elasticsearch.action.admin.indices.alias.IndicesAliasesRequestBuilder; import org.elasticsearch.action.admin.indices.alias.IndicesAliasesResponse; @@ -52,6 +53,9 @@ import org.elasticsearch.action.admin.indices.exists.types.TypesExistsResponse; import org.elasticsearch.action.admin.indices.flush.FlushRequest; import org.elasticsearch.action.admin.indices.flush.FlushRequestBuilder; import org.elasticsearch.action.admin.indices.flush.FlushResponse; +import org.elasticsearch.action.admin.indices.get.GetIndexRequest; +import org.elasticsearch.action.admin.indices.get.GetIndexRequestBuilder; +import org.elasticsearch.action.admin.indices.get.GetIndexResponse; import org.elasticsearch.action.admin.indices.mapping.delete.DeleteMappingRequest; import org.elasticsearch.action.admin.indices.mapping.delete.DeleteMappingRequestBuilder; import org.elasticsearch.action.admin.indices.mapping.delete.DeleteMappingResponse; @@ -65,6 +69,9 @@ import org.elasticsearch.action.admin.indices.open.OpenIndexResponse; import org.elasticsearch.action.admin.indices.optimize.OptimizeRequest; import org.elasticsearch.action.admin.indices.optimize.OptimizeRequestBuilder; import org.elasticsearch.action.admin.indices.optimize.OptimizeResponse; +import org.elasticsearch.action.admin.indices.recovery.RecoveryRequest; +import org.elasticsearch.action.admin.indices.recovery.RecoveryRequestBuilder; +import org.elasticsearch.action.admin.indices.recovery.RecoveryResponse; import org.elasticsearch.action.admin.indices.refresh.RefreshRequest; import org.elasticsearch.action.admin.indices.refresh.RefreshRequestBuilder; import org.elasticsearch.action.admin.indices.refresh.RefreshResponse; @@ -80,9 +87,6 @@ import org.elasticsearch.action.admin.indices.settings.put.UpdateSettingsRespons import org.elasticsearch.action.admin.indices.stats.IndicesStatsRequest; import org.elasticsearch.action.admin.indices.stats.IndicesStatsRequestBuilder; import org.elasticsearch.action.admin.indices.stats.IndicesStatsResponse; -import org.elasticsearch.action.admin.indices.recovery.RecoveryRequest; -import org.elasticsearch.action.admin.indices.recovery.RecoveryRequestBuilder; -import org.elasticsearch.action.admin.indices.recovery.RecoveryResponse; import org.elasticsearch.action.admin.indices.template.delete.DeleteIndexTemplateRequest; import org.elasticsearch.action.admin.indices.template.delete.DeleteIndexTemplateRequestBuilder; import org.elasticsearch.action.admin.indices.template.delete.DeleteIndexTemplateResponse; @@ -520,6 +524,26 @@ public interface IndicesAdminClient extends ElasticsearchClient listener); + /** + * Get index metadata for particular indices. + * + * @param request The result future + */ + ActionFuture getIndex(GetIndexRequest request); + + /** + * Get index metadata for particular indices. + * + * @param request The index aliases request + * @param listener A listener to be notified with a result + */ + void getIndex(GetIndexRequest request, ActionListener listener); + + /** + * Get index metadata for particular indices. + */ + GetIndexRequestBuilder prepareGetIndex(); + /** * Clear indices cache. * diff --git a/src/main/java/org/elasticsearch/client/support/AbstractIndicesAdminClient.java b/src/main/java/org/elasticsearch/client/support/AbstractIndicesAdminClient.java index 56a598de139..143df3bacc1 100644 --- a/src/main/java/org/elasticsearch/client/support/AbstractIndicesAdminClient.java +++ b/src/main/java/org/elasticsearch/client/support/AbstractIndicesAdminClient.java @@ -63,6 +63,10 @@ import org.elasticsearch.action.admin.indices.flush.FlushAction; import org.elasticsearch.action.admin.indices.flush.FlushRequest; import org.elasticsearch.action.admin.indices.flush.FlushRequestBuilder; import org.elasticsearch.action.admin.indices.flush.FlushResponse; +import org.elasticsearch.action.admin.indices.get.GetIndexAction; +import org.elasticsearch.action.admin.indices.get.GetIndexRequest; +import org.elasticsearch.action.admin.indices.get.GetIndexRequestBuilder; +import org.elasticsearch.action.admin.indices.get.GetIndexResponse; import org.elasticsearch.action.admin.indices.mapping.delete.DeleteMappingAction; import org.elasticsearch.action.admin.indices.mapping.delete.DeleteMappingRequest; import org.elasticsearch.action.admin.indices.mapping.delete.DeleteMappingRequestBuilder; @@ -80,14 +84,14 @@ import org.elasticsearch.action.admin.indices.optimize.OptimizeAction; import org.elasticsearch.action.admin.indices.optimize.OptimizeRequest; import org.elasticsearch.action.admin.indices.optimize.OptimizeRequestBuilder; import org.elasticsearch.action.admin.indices.optimize.OptimizeResponse; -import org.elasticsearch.action.admin.indices.refresh.RefreshAction; -import org.elasticsearch.action.admin.indices.refresh.RefreshRequest; -import org.elasticsearch.action.admin.indices.refresh.RefreshRequestBuilder; -import org.elasticsearch.action.admin.indices.refresh.RefreshResponse; import org.elasticsearch.action.admin.indices.recovery.RecoveryAction; import org.elasticsearch.action.admin.indices.recovery.RecoveryRequest; import org.elasticsearch.action.admin.indices.recovery.RecoveryRequestBuilder; import org.elasticsearch.action.admin.indices.recovery.RecoveryResponse; +import org.elasticsearch.action.admin.indices.refresh.RefreshAction; +import org.elasticsearch.action.admin.indices.refresh.RefreshRequest; +import org.elasticsearch.action.admin.indices.refresh.RefreshRequestBuilder; +import org.elasticsearch.action.admin.indices.refresh.RefreshResponse; import org.elasticsearch.action.admin.indices.segments.IndicesSegmentResponse; import org.elasticsearch.action.admin.indices.segments.IndicesSegmentsAction; import org.elasticsearch.action.admin.indices.segments.IndicesSegmentsRequest; @@ -225,6 +229,21 @@ public abstract class AbstractIndicesAdminClient implements IndicesAdminClient { return new AliasesExistRequestBuilder(this, aliases); } + @Override + public ActionFuture getIndex(GetIndexRequest request) { + return execute(GetIndexAction.INSTANCE, request); + } + + @Override + public void getIndex(GetIndexRequest request, ActionListener listener) { + execute(GetIndexAction.INSTANCE, request, listener); + } + + @Override + public GetIndexRequestBuilder prepareGetIndex() { + return new GetIndexRequestBuilder(this); + } + @Override public void clearCache(final ClearIndicesCacheRequest request, final ActionListener listener) { execute(ClearIndicesCacheAction.INSTANCE, request, listener); diff --git a/src/main/java/org/elasticsearch/common/path/PathTrie.java b/src/main/java/org/elasticsearch/common/path/PathTrie.java index e77bad08080..0cc1d09c997 100644 --- a/src/main/java/org/elasticsearch/common/path/PathTrie.java +++ b/src/main/java/org/elasticsearch/common/path/PathTrie.java @@ -165,7 +165,14 @@ public class PathTrie { } usedWildcard = true; } else { - usedWildcard = token.equals(wildcard); + // If we are at the end of the path, the current node does not have a value but there + // is a child wildcard node, use the child wildcard node + if (index + 1 == path.length && node.value == null && children.get(wildcard) != null) { + node = children.get(wildcard); + usedWildcard = true; + } else { + usedWildcard = token.equals(wildcard); + } } put(params, node, token); diff --git a/src/main/java/org/elasticsearch/rest/action/RestActionModule.java b/src/main/java/org/elasticsearch/rest/action/RestActionModule.java index 7dc3ab18b76..1eb9016f40f 100644 --- a/src/main/java/org/elasticsearch/rest/action/RestActionModule.java +++ b/src/main/java/org/elasticsearch/rest/action/RestActionModule.java @@ -59,6 +59,7 @@ import org.elasticsearch.rest.action.admin.indices.delete.RestDeleteIndexAction; import org.elasticsearch.rest.action.admin.indices.exists.indices.RestIndicesExistsAction; import org.elasticsearch.rest.action.admin.indices.exists.types.RestTypesExistsAction; import org.elasticsearch.rest.action.admin.indices.flush.RestFlushAction; +import org.elasticsearch.rest.action.admin.indices.get.RestGetIndicesAction; import org.elasticsearch.rest.action.admin.indices.mapping.delete.RestDeleteMappingAction; import org.elasticsearch.rest.action.admin.indices.mapping.get.RestGetFieldMappingAction; import org.elasticsearch.rest.action.admin.indices.mapping.get.RestGetMappingAction; @@ -153,6 +154,7 @@ public class RestActionModule extends AbstractModule { bind(RestIndicesExistsAction.class).asEagerSingleton(); bind(RestTypesExistsAction.class).asEagerSingleton(); + bind(RestGetIndicesAction.class).asEagerSingleton(); bind(RestIndicesStatsAction.class).asEagerSingleton(); bind(RestIndicesSegmentsAction.class).asEagerSingleton(); bind(RestGetAliasesAction.class).asEagerSingleton(); diff --git a/src/main/java/org/elasticsearch/rest/action/admin/indices/alias/get/RestGetAliasesAction.java b/src/main/java/org/elasticsearch/rest/action/admin/indices/alias/get/RestGetAliasesAction.java index f17e8dc4cf8..3bd8e858c51 100644 --- a/src/main/java/org/elasticsearch/rest/action/admin/indices/alias/get/RestGetAliasesAction.java +++ b/src/main/java/org/elasticsearch/rest/action/admin/indices/alias/get/RestGetAliasesAction.java @@ -47,10 +47,8 @@ public class RestGetAliasesAction extends BaseRestHandler { @Inject public RestGetAliasesAction(Settings settings, RestController controller, RestClientFactory restClientFactory) { super(settings, restClientFactory); - controller.registerHandler(GET, "/_alias/", this); controller.registerHandler(GET, "/_alias/{name}", this); controller.registerHandler(GET, "/{index}/_alias/{name}", this); - controller.registerHandler(GET, "/{index}/_alias", this); } @Override diff --git a/src/main/java/org/elasticsearch/rest/action/admin/indices/alias/get/RestGetIndicesAliasesAction.java b/src/main/java/org/elasticsearch/rest/action/admin/indices/alias/get/RestGetIndicesAliasesAction.java index cb2540bc48b..3c8acbe6913 100644 --- a/src/main/java/org/elasticsearch/rest/action/admin/indices/alias/get/RestGetIndicesAliasesAction.java +++ b/src/main/java/org/elasticsearch/rest/action/admin/indices/alias/get/RestGetIndicesAliasesAction.java @@ -47,8 +47,6 @@ public class RestGetIndicesAliasesAction extends BaseRestHandler { @Inject public RestGetIndicesAliasesAction(Settings settings, RestController controller, RestClientFactory restClientFactory) { super(settings, restClientFactory); - controller.registerHandler(GET, "/_aliases", this); - controller.registerHandler(GET, "/{index}/_aliases", this); controller.registerHandler(GET, "/{index}/_aliases/{name}", this); controller.registerHandler(GET, "/_aliases/{name}", this); } diff --git a/src/main/java/org/elasticsearch/rest/action/admin/indices/get/RestGetIndicesAction.java b/src/main/java/org/elasticsearch/rest/action/admin/indices/get/RestGetIndicesAction.java new file mode 100644 index 00000000000..9ad2bd6c9b0 --- /dev/null +++ b/src/main/java/org/elasticsearch/rest/action/admin/indices/get/RestGetIndicesAction.java @@ -0,0 +1,160 @@ +/* + * 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.admin.indices.get; + +import com.carrotsearch.hppc.cursors.ObjectObjectCursor; +import com.google.common.collect.ImmutableList; +import org.elasticsearch.ElasticsearchIllegalStateException; +import org.elasticsearch.action.admin.indices.get.GetIndexRequest; +import org.elasticsearch.action.admin.indices.get.GetIndexResponse; +import org.elasticsearch.action.support.IndicesOptions; +import org.elasticsearch.client.Client; +import org.elasticsearch.cluster.metadata.AliasMetaData; +import org.elasticsearch.cluster.metadata.MappingMetaData; +import org.elasticsearch.common.Strings; +import org.elasticsearch.common.collect.ImmutableOpenMap; +import org.elasticsearch.common.inject.Inject; +import org.elasticsearch.common.settings.Settings; +import org.elasticsearch.common.xcontent.ToXContent.Params; +import org.elasticsearch.common.xcontent.XContentBuilder; +import org.elasticsearch.common.xcontent.XContentBuilderString; +import org.elasticsearch.rest.*; +import org.elasticsearch.rest.action.support.RestBuilderListener; +import org.elasticsearch.search.warmer.IndexWarmersMetaData; + +import java.io.IOException; + +import static org.elasticsearch.rest.RestRequest.Method.GET; +import static org.elasticsearch.rest.RestStatus.OK; + +/** + * + */ +public class RestGetIndicesAction extends BaseRestHandler { + + @Inject + public RestGetIndicesAction(Settings settings, RestController controller, RestClientFactory restClientFactory) { + super(settings, restClientFactory); + controller.registerHandler(GET, "/{index}", this); + controller.registerHandler(GET, "/{index}/{type}", this); + } + + @Override + public void handleRequest(final RestRequest request, final RestChannel channel, final Client client) { + String[] indices = Strings.splitStringByCommaToArray(request.param("index")); + String[] features = request.paramAsStringArray("type", null); + // Work out if the indices is a list of features + if (features == null && indices.length > 0 && indices[0] != null && indices[0].startsWith("_") && !"_all".equals(indices[0])) { + features = indices; + indices = new String[] {"_all"}; + } + final GetIndexRequest getIndexRequest = new GetIndexRequest(); + getIndexRequest.indices(indices); + if (features != null) { + getIndexRequest.features(features); + } + getIndexRequest.indicesOptions(IndicesOptions.fromRequest(request, getIndexRequest.indicesOptions())); + getIndexRequest.local(request.paramAsBoolean("local", getIndexRequest.local())); + client.admin().indices().getIndex(getIndexRequest, new RestBuilderListener(channel) { + + @Override + public RestResponse buildResponse(GetIndexResponse response, XContentBuilder builder) throws Exception { + + String[] features = getIndexRequest.features(); + String[] indices = response.indices(); + + builder.startObject(); + for (String index : indices) { + builder.startObject(index); + for (String feature : features) { + switch (feature) { + case "_alias": + case "_aliases": + writeAliases(response.aliases().get(index), builder, request); + break; + case "_mapping": + case "_mappings": + writeMappings(response.mappings().get(index), builder, request); + break; + case "_settings": + writeSettings(response.settings().get(index), builder, request); + break; + case "_warmer": + case "_warmers": + writeWarmers(response.warmers().get(index), builder, request); + break; + default: + throw new ElasticsearchIllegalStateException("feature [" + feature + "] is not valid"); + } + } + builder.endObject(); + + } + builder.endObject(); + + return new BytesRestResponse(OK, builder); + } + + private void writeAliases(ImmutableList aliases, XContentBuilder builder, Params params) throws IOException { + if (aliases != null) { + builder.startObject(Fields.ALIASES); + for (AliasMetaData alias : aliases) { + AliasMetaData.Builder.toXContent(alias, builder, params); + } + builder.endObject(); + } + } + + private void writeMappings(ImmutableOpenMap mappings, XContentBuilder builder, Params params) throws IOException { + if (mappings != null) { + builder.startObject(Fields.MAPPINGS); + for (ObjectObjectCursor typeEntry : mappings) { + builder.field(typeEntry.key); + builder.map(typeEntry.value.sourceAsMap()); + } + builder.endObject(); + } + } + + private void writeSettings(Settings settings, XContentBuilder builder, Params params) throws IOException { + builder.startObject(Fields.SETTINGS); + settings.toXContent(builder, params); + builder.endObject(); + } + + private void writeWarmers(ImmutableList warmers, XContentBuilder builder, Params params) throws IOException { + if (warmers != null) { + builder.startObject(Fields.WARMERS); + for (IndexWarmersMetaData.Entry warmer : warmers) { + IndexWarmersMetaData.FACTORY.toXContent(warmer, builder, params); + } + builder.endObject(); + } + } + }); + } + + static class Fields { + static final XContentBuilderString ALIASES = new XContentBuilderString("aliases"); + static final XContentBuilderString MAPPINGS = new XContentBuilderString("mappings"); + static final XContentBuilderString SETTINGS = new XContentBuilderString("settings"); + static final XContentBuilderString WARMERS = new XContentBuilderString("warmers"); + } + +} \ No newline at end of file diff --git a/src/main/java/org/elasticsearch/rest/action/admin/indices/mapping/get/RestGetMappingAction.java b/src/main/java/org/elasticsearch/rest/action/admin/indices/mapping/get/RestGetMappingAction.java index ff0741594e5..2ce1a7232db 100644 --- a/src/main/java/org/elasticsearch/rest/action/admin/indices/mapping/get/RestGetMappingAction.java +++ b/src/main/java/org/elasticsearch/rest/action/admin/indices/mapping/get/RestGetMappingAction.java @@ -48,8 +48,6 @@ public class RestGetMappingAction extends BaseRestHandler { @Inject public RestGetMappingAction(Settings settings, RestController controller, RestClientFactory restClientFactory) { super(settings, restClientFactory); - controller.registerHandler(GET, "/_mapping", this); - controller.registerHandler(GET, "/{index}/_mapping", this); controller.registerHandler(GET, "/{index}/{type}/_mapping", this); controller.registerHandler(GET, "/{index}/_mappings/{type}", this); controller.registerHandler(GET, "/{index}/_mapping/{type}", this); diff --git a/src/main/java/org/elasticsearch/rest/action/admin/indices/settings/RestGetSettingsAction.java b/src/main/java/org/elasticsearch/rest/action/admin/indices/settings/RestGetSettingsAction.java index 452b72a629b..573ab862a6f 100644 --- a/src/main/java/org/elasticsearch/rest/action/admin/indices/settings/RestGetSettingsAction.java +++ b/src/main/java/org/elasticsearch/rest/action/admin/indices/settings/RestGetSettingsAction.java @@ -40,8 +40,6 @@ public class RestGetSettingsAction extends BaseRestHandler { @Inject public RestGetSettingsAction(Settings settings, RestController controller, RestClientFactory restClientFactory) { super(settings, restClientFactory); - controller.registerHandler(GET, "/_settings", this); - controller.registerHandler(GET, "/{index}/_settings", this); controller.registerHandler(GET, "/{index}/_settings/{name}", this); controller.registerHandler(GET, "/_settings/{name}", this); controller.registerHandler(GET, "/{index}/_setting/{name}", this); diff --git a/src/main/java/org/elasticsearch/rest/action/admin/indices/warmer/get/RestGetWarmerAction.java b/src/main/java/org/elasticsearch/rest/action/admin/indices/warmer/get/RestGetWarmerAction.java index 92c44d29623..106c028e0b0 100644 --- a/src/main/java/org/elasticsearch/rest/action/admin/indices/warmer/get/RestGetWarmerAction.java +++ b/src/main/java/org/elasticsearch/rest/action/admin/indices/warmer/get/RestGetWarmerAction.java @@ -43,9 +43,7 @@ public class RestGetWarmerAction extends BaseRestHandler { @Inject public RestGetWarmerAction(Settings settings, RestController controller, RestClientFactory restClientFactory) { super(settings, restClientFactory); - controller.registerHandler(GET, "/_warmer", this); controller.registerHandler(GET, "/_warmer/{name}", this); - controller.registerHandler(GET, "/{index}/_warmer", this); controller.registerHandler(GET, "/{index}/_warmer/{name}", this); controller.registerHandler(GET, "/{index}/_warmers/{name}", this); controller.registerHandler(GET, "/{index}/{type}/_warmer/{name}", this); diff --git a/src/test/java/org/elasticsearch/action/admin/indices/get/GetIndexTests.java b/src/test/java/org/elasticsearch/action/admin/indices/get/GetIndexTests.java new file mode 100644 index 00000000000..29a48d0458b --- /dev/null +++ b/src/test/java/org/elasticsearch/action/admin/indices/get/GetIndexTests.java @@ -0,0 +1,334 @@ +/* + * 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.action.admin.indices.get; + +import com.google.common.collect.ImmutableList; +import org.elasticsearch.ElasticsearchIllegalStateException; +import org.elasticsearch.action.admin.indices.alias.Alias; +import org.elasticsearch.cluster.metadata.AliasMetaData; +import org.elasticsearch.cluster.metadata.MappingMetaData; +import org.elasticsearch.common.collect.ImmutableOpenMap; +import org.elasticsearch.common.settings.ImmutableSettings; +import org.elasticsearch.common.settings.Settings; +import org.elasticsearch.indices.IndexMissingException; +import org.elasticsearch.search.warmer.IndexWarmersMetaData.Entry; +import org.elasticsearch.test.ElasticsearchIntegrationTest; +import org.junit.Test; + +import java.util.ArrayList; +import java.util.List; + +import static org.elasticsearch.test.hamcrest.ElasticsearchAssertions.assertAcked; +import static org.hamcrest.Matchers.*; + +@ElasticsearchIntegrationTest.SuiteScopeTest +public class GetIndexTests extends ElasticsearchIntegrationTest { + + private static final String[] allFeatures = { "_alias", "_aliases", "_mapping", "_mappings", "_settings", "_warmer", "_warmers" }; + + @Override + protected void setupSuiteScopeCluster() throws Exception { + assertAcked(prepareCreate("idx").addAlias(new Alias("alias_idx")).addMapping("type1", "{\"type1\":{}}") + .setSettings(ImmutableSettings.builder().put("number_of_shards", 1)).get()); + ensureSearchable("idx"); + assertAcked(client().admin().indices().preparePutWarmer("warmer1").setSearchRequest(client().prepareSearch("idx")).get()); + createIndex("empty_idx"); + ensureSearchable("idx", "empty_idx"); + } + + @Test + public void testSimple() { + GetIndexResponse response = client().admin().indices().prepareGetIndex().addIndices("idx").get(); + String[] indices = response.indices(); + assertThat(indices, notNullValue()); + assertThat(indices.length, equalTo(1)); + assertThat(indices[0], equalTo("idx")); + assertAliases(response, "idx"); + assertMappings(response, "idx"); + assertSettings(response, "idx"); + assertWarmers(response, "idx"); + } + + @Test + public void testSimpleMapping() { + GetIndexResponse response = client().admin().indices().prepareGetIndex().addIndices("idx").setFeatures("_mapping").get(); + String[] indices = response.indices(); + assertThat(indices, notNullValue()); + assertThat(indices.length, equalTo(1)); + assertThat(indices[0], equalTo("idx")); + assertMappings(response, "idx"); + assertEmptyAliases(response); + assertEmptySettings(response); + assertEmptyWarmers(response); + } + + @Test + public void testSimpleMappings() { + GetIndexResponse response = client().admin().indices().prepareGetIndex().addIndices("idx").setFeatures("_mappings").get(); + String[] indices = response.indices(); + assertThat(indices, notNullValue()); + assertThat(indices.length, equalTo(1)); + assertThat(indices[0], equalTo("idx")); + assertMappings(response, "idx"); + assertEmptyAliases(response); + assertEmptySettings(response); + assertEmptyWarmers(response); + } + + @Test + public void testSimpleAlias() { + GetIndexResponse response = client().admin().indices().prepareGetIndex().addIndices("idx").setFeatures("_alias").get(); + String[] indices = response.indices(); + assertThat(indices, notNullValue()); + assertThat(indices.length, equalTo(1)); + assertThat(indices[0], equalTo("idx")); + assertAliases(response, "idx"); + assertEmptyMappings(response); + assertEmptySettings(response); + assertEmptyWarmers(response); + } + + @Test + public void testSimpleAliases() { + GetIndexResponse response = client().admin().indices().prepareGetIndex().addIndices("idx").setFeatures("_aliases").get(); + String[] indices = response.indices(); + assertThat(indices, notNullValue()); + assertThat(indices.length, equalTo(1)); + assertThat(indices[0], equalTo("idx")); + assertAliases(response, "idx"); + assertEmptyMappings(response); + assertEmptySettings(response); + assertEmptyWarmers(response); + } + + @Test + public void testSimpleSettings() { + GetIndexResponse response = client().admin().indices().prepareGetIndex().addIndices("idx").setFeatures("_settings").get(); + String[] indices = response.indices(); + assertThat(indices, notNullValue()); + assertThat(indices.length, equalTo(1)); + assertThat(indices[0], equalTo("idx")); + assertSettings(response, "idx"); + assertEmptyAliases(response); + assertEmptyMappings(response); + assertEmptyWarmers(response); + } + + @Test + public void testSimpleWarmer() { + GetIndexResponse response = client().admin().indices().prepareGetIndex().addIndices("idx").setFeatures("_warmer").get(); + String[] indices = response.indices(); + assertThat(indices, notNullValue()); + assertThat(indices.length, equalTo(1)); + assertThat(indices[0], equalTo("idx")); + assertWarmers(response, "idx"); + assertEmptyAliases(response); + assertEmptyMappings(response); + assertEmptySettings(response); + } + + @Test + public void testSimpleWarmers() { + GetIndexResponse response = client().admin().indices().prepareGetIndex().addIndices("idx").setFeatures("_warmers").get(); + String[] indices = response.indices(); + assertThat(indices, notNullValue()); + assertThat(indices.length, equalTo(1)); + assertThat(indices[0], equalTo("idx")); + assertWarmers(response, "idx"); + assertEmptyAliases(response); + assertEmptyMappings(response); + assertEmptySettings(response); + } + + @Test(expected=IndexMissingException.class) + public void testSimpleUnknownIndex() { + client().admin().indices().prepareGetIndex().addIndices("missing_idx").get(); + } + + @Test(expected=ElasticsearchIllegalStateException.class) + public void testSimpleUnknownFeature() { + client().admin().indices().prepareGetIndex().addIndices("idx").setFeatures("_foo").get(); + } + + @Test + public void testSimpleMixedFeatures() { + int numFeatures = randomIntBetween(1, allFeatures.length); + List features = new ArrayList(numFeatures); + for (int i = 0; i < numFeatures; i++) { + features.add(randomFrom(allFeatures)); + } + GetIndexResponse response = client().admin().indices().prepareGetIndex().addIndices("idx") + .setFeatures(features.toArray(new String[features.size()])).get(); + String[] indices = response.indices(); + assertThat(indices, notNullValue()); + assertThat(indices.length, equalTo(1)); + assertThat(indices[0], equalTo("idx")); + if (features.contains("_alias") || features.contains("_aliases")) { + assertAliases(response, "idx"); + } else { + assertEmptyAliases(response); + } + if (features.contains("_mapping") || features.contains("_mappings")) { + assertMappings(response, "idx"); + } else { + assertEmptyMappings(response); + } + if (features.contains("_settings")) { + assertSettings(response, "idx"); + } else { + assertEmptySettings(response); + } + if (features.contains("_warmer") || features.contains("_warmers")) { + assertWarmers(response, "idx"); + } else { + assertEmptyWarmers(response); + } + } + + @Test + public void testEmpty() { + GetIndexResponse response = client().admin().indices().prepareGetIndex().addIndices("empty_idx").get(); + String[] indices = response.indices(); + assertThat(indices, notNullValue()); + assertThat(indices.length, equalTo(1)); + assertThat(indices[0], equalTo("empty_idx")); + assertEmptyAliases(response); + assertEmptyOrOnlyDefaultMappings(response, "empty_idx"); + assertNonEmptySettings(response, "empty_idx"); + assertEmptyWarmers(response); + } + + @Test + public void testEmptyMixedFeatures() { + int numFeatures = randomIntBetween(1, allFeatures.length); + List features = new ArrayList(numFeatures); + for (int i = 0; i < numFeatures; i++) { + features.add(randomFrom(allFeatures)); + } + GetIndexResponse response = client().admin().indices().prepareGetIndex().addIndices("empty_idx") + .setFeatures(features.toArray(new String[features.size()])).get(); + String[] indices = response.indices(); + assertThat(indices, notNullValue()); + assertThat(indices.length, equalTo(1)); + assertThat(indices[0], equalTo("empty_idx")); + assertEmptyAliases(response); + if (features.contains("_mapping") || features.contains("_mappings")) { + assertEmptyOrOnlyDefaultMappings(response, "empty_idx"); + } else { + assertEmptyMappings(response); + } + if (features.contains("_settings")) { + assertNonEmptySettings(response, "empty_idx"); + } else { + assertEmptySettings(response); + } + assertEmptyWarmers(response); + } + + private void assertWarmers(GetIndexResponse response, String indexName) { + ImmutableOpenMap> warmers = response.warmers(); + assertThat(warmers, notNullValue()); + assertThat(warmers.size(), equalTo(1)); + ImmutableList indexWarmers = warmers.get(indexName); + assertThat(indexWarmers, notNullValue()); + assertThat(indexWarmers.size(), equalTo(1)); + Entry warmer = indexWarmers.get(0); + assertThat(warmer, notNullValue()); + assertThat(warmer.name(), equalTo("warmer1")); + } + + private void assertSettings(GetIndexResponse response, String indexName) { + ImmutableOpenMap settings = response.settings(); + assertThat(settings, notNullValue()); + assertThat(settings.size(), equalTo(1)); + Settings indexSettings = settings.get(indexName); + assertThat(indexSettings, notNullValue()); + assertThat(indexSettings.get("index.number_of_shards"), equalTo("1")); + } + + private void assertNonEmptySettings(GetIndexResponse response, String indexName) { + ImmutableOpenMap settings = response.settings(); + assertThat(settings, notNullValue()); + assertThat(settings.size(), equalTo(1)); + Settings indexSettings = settings.get(indexName); + assertThat(indexSettings, notNullValue()); + } + + private void assertMappings(GetIndexResponse response, String indexName) { + ImmutableOpenMap> mappings = response.mappings(); + assertThat(mappings, notNullValue()); + assertThat(mappings.size(), equalTo(1)); + ImmutableOpenMap indexMappings = mappings.get(indexName); + assertThat(indexMappings, notNullValue()); + assertThat(indexMappings.size(), anyOf(equalTo(1), equalTo(2))); + if (indexMappings.size() == 2) { + MappingMetaData mapping = indexMappings.get("_default_"); + assertThat(mapping, notNullValue()); + } + MappingMetaData mapping = indexMappings.get("type1"); + assertThat(mapping, notNullValue()); + assertThat(mapping.type(), equalTo("type1")); + } + + private void assertEmptyOrOnlyDefaultMappings(GetIndexResponse response, String indexName) { + ImmutableOpenMap> mappings = response.mappings(); + assertThat(mappings, notNullValue()); + assertThat(mappings.size(), equalTo(1)); + ImmutableOpenMap indexMappings = mappings.get(indexName); + assertThat(indexMappings, notNullValue()); + assertThat(indexMappings.size(), anyOf(equalTo(0), equalTo(1))); + if (indexMappings.size() == 1) { + MappingMetaData mapping = indexMappings.get("_default_"); + assertThat(mapping, notNullValue()); + } + } + + private void assertAliases(GetIndexResponse response, String indexName) { + ImmutableOpenMap> aliases = response.aliases(); + assertThat(aliases, notNullValue()); + assertThat(aliases.size(), equalTo(1)); + ImmutableList indexAliases = aliases.get(indexName); + assertThat(indexAliases, notNullValue()); + assertThat(indexAliases.size(), equalTo(1)); + AliasMetaData alias = indexAliases.get(0); + assertThat(alias, notNullValue()); + assertThat(alias.alias(), equalTo("alias_idx")); + } + + private void assertEmptyWarmers(GetIndexResponse response) { + assertThat(response.warmers(), notNullValue()); + assertThat(response.warmers().isEmpty(), equalTo(true)); + } + + private void assertEmptySettings(GetIndexResponse response) { + assertThat(response.settings(), notNullValue()); + assertThat(response.settings().isEmpty(), equalTo(true)); + } + + private void assertEmptyMappings(GetIndexResponse response) { + assertThat(response.mappings(), notNullValue()); + assertThat(response.mappings().isEmpty(), equalTo(true)); + } + + private void assertEmptyAliases(GetIndexResponse response) { + assertThat(response.aliases(), notNullValue()); + assertThat(response.aliases().isEmpty(), equalTo(true)); + } +} diff --git a/src/test/java/org/elasticsearch/common/path/PathTrieTests.java b/src/test/java/org/elasticsearch/common/path/PathTrieTests.java index 66cff55e559..3151352c1ee 100644 --- a/src/test/java/org/elasticsearch/common/path/PathTrieTests.java +++ b/src/test/java/org/elasticsearch/common/path/PathTrieTests.java @@ -105,10 +105,14 @@ public class PathTrieTests extends ElasticsearchTestCase { trie.insert("b", "test2"); trie.insert("{test}/a", "test3"); trie.insert("b/a", "test4"); + trie.insert("{test}/{testB}", "test5"); + trie.insert("{test}/x/{testC}", "test6"); Map params = newHashMap(); assertThat(trie.retrieve("/b", params), equalTo("test2")); assertThat(trie.retrieve("/b/a", params), equalTo("test4")); + assertThat(trie.retrieve("/v/x", params), equalTo("test5")); + assertThat(trie.retrieve("/v/x/c", params), equalTo("test6")); } @Test diff --git a/src/test/java/org/elasticsearch/transport/ActionNamesTests.java b/src/test/java/org/elasticsearch/transport/ActionNamesTests.java index 1ad687bfe02..3b44eb7c897 100644 --- a/src/test/java/org/elasticsearch/transport/ActionNamesTests.java +++ b/src/test/java/org/elasticsearch/transport/ActionNamesTests.java @@ -20,6 +20,7 @@ package org.elasticsearch.transport; import org.elasticsearch.Version; +import org.elasticsearch.action.admin.indices.get.GetIndexAction; import org.elasticsearch.action.bench.AbortBenchmarkAction; import org.elasticsearch.action.bench.BenchmarkAction; import org.elasticsearch.action.bench.BenchmarkService; @@ -131,5 +132,6 @@ public class ActionNamesTests extends ElasticsearchIntegrationTest { post_1_4_actions.add(AbortBenchmarkAction.NAME); post_1_4_actions.add(ExistsAction.NAME); post_1_4_actions.add(ExistsAction.NAME + "[s]"); + post_1_4_actions.add(GetIndexAction.NAME); } }