Implemented XContent serialisation for GetIndexResponse (#31675)

This PR does the server side work for adding the Get Index API to the REST
high-level-client, namely moving resolving default settings to the
transport action. A follow up would be the client side changes.
This commit is contained in:
Sohaib Iftikhar 2018-07-03 14:08:50 +02:00 committed by Nik Everett
parent ce78925732
commit a5fd4a7709
10 changed files with 652 additions and 126 deletions

View File

@ -170,8 +170,8 @@ task verifyVersions {
* the enabled state of every bwc task. It should be set back to true
* after the backport of the backcompat code is complete.
*/
final boolean bwc_tests_enabled = true
final String bwc_tests_disabled_issue = "" /* place a PR link here when commiting bwc changes */
final boolean bwc_tests_enabled = false
final String bwc_tests_disabled_issue = "https://github.com/elastic/elasticsearch/pull/31675" /* place a PR link here when commiting bwc changes */
if (bwc_tests_enabled == false) {
if (bwc_tests_disabled_issue.isEmpty()) {
throw new GradleException("bwc_tests_disabled_issue must be set when bwc_tests_enabled == false")

View File

@ -59,7 +59,7 @@ public class GetAliasesResponseTests extends AbstractXContentTestCase<GetAliases
return map;
}
private static AliasMetaData createAliasMetaData() {
public static AliasMetaData createAliasMetaData() {
AliasMetaData.Builder builder = AliasMetaData.builder(randomAlphaOfLengthBetween(3, 10));
if (randomBoolean()) {
builder.routing(randomAlphaOfLengthBetween(3, 10));

View File

@ -557,7 +557,7 @@ public class ActionModule extends AbstractModule {
registerHandler.accept(new RestRestoreSnapshotAction(settings, restController));
registerHandler.accept(new RestDeleteSnapshotAction(settings, restController));
registerHandler.accept(new RestSnapshotsStatusAction(settings, restController));
registerHandler.accept(new RestGetIndicesAction(settings, restController, indexScopedSettings, settingsFilter));
registerHandler.accept(new RestGetIndicesAction(settings, restController));
registerHandler.accept(new RestIndicesStatsAction(settings, restController));
registerHandler.accept(new RestIndicesSegmentsAction(settings, restController));
registerHandler.accept(new RestIndicesShardStoresAction(settings, restController));

View File

@ -19,6 +19,7 @@
package org.elasticsearch.action.admin.indices.get;
import org.elasticsearch.Version;
import org.elasticsearch.action.ActionRequestValidationException;
import org.elasticsearch.action.support.master.info.ClusterInfoRequest;
import org.elasticsearch.common.io.stream.StreamInput;
@ -80,6 +81,9 @@ public class GetIndexRequest extends ClusterInfoRequest<GetIndexRequest> {
features[i] = Feature.fromId(in.readByte());
}
humanReadable = in.readBoolean();
if (in.getVersion().onOrAfter(Version.V_6_4_0)) {
includeDefaults = in.readBoolean();
}
}
public GetIndexRequest features(Feature... features) {
@ -119,8 +123,7 @@ public class GetIndexRequest extends ClusterInfoRequest<GetIndexRequest> {
/**
* Sets the value of "include_defaults".
* Used only by the high-level REST client.
*
*
* @param includeDefaults value of "include_defaults" to be set.
* @return this request
*/
@ -131,8 +134,7 @@ public class GetIndexRequest extends ClusterInfoRequest<GetIndexRequest> {
/**
* Whether to return all default settings for each of the indices.
* Used only by the high-level REST client.
*
*
* @return <code>true</code> if defaults settings for each of the indices need to returned;
* <code>false</code> otherwise.
*/
@ -153,6 +155,9 @@ public class GetIndexRequest extends ClusterInfoRequest<GetIndexRequest> {
out.writeByte(feature.id);
}
out.writeBoolean(humanReadable);
if (out.getVersion().onOrAfter(Version.V_6_4_0)) {
out.writeBoolean(includeDefaults);
}
}
}

View File

@ -20,33 +20,50 @@
package org.elasticsearch.action.admin.indices.get;
import com.carrotsearch.hppc.cursors.ObjectObjectCursor;
import org.apache.lucene.util.CollectionUtil;
import org.elasticsearch.Version;
import org.elasticsearch.action.ActionResponse;
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.io.stream.StreamInput;
import org.elasticsearch.common.io.stream.StreamOutput;
import org.elasticsearch.common.settings.Settings;
import org.elasticsearch.common.xcontent.ToXContentObject;
import org.elasticsearch.common.xcontent.XContentBuilder;
import org.elasticsearch.common.xcontent.XContentParser;
import org.elasticsearch.common.xcontent.XContentParser.Token;
import java.io.IOException;
import java.util.ArrayList;
import java.util.Arrays;
import java.util.Collections;
import java.util.Comparator;
import java.util.List;
import java.util.Objects;
import static org.elasticsearch.common.xcontent.XContentParserUtils.ensureExpectedToken;
/**
* A response for a delete index action.
* A response for a get index action.
*/
public class GetIndexResponse extends ActionResponse {
public class GetIndexResponse extends ActionResponse implements ToXContentObject {
private ImmutableOpenMap<String, ImmutableOpenMap<String, MappingMetaData>> mappings = ImmutableOpenMap.of();
private ImmutableOpenMap<String, List<AliasMetaData>> aliases = ImmutableOpenMap.of();
private ImmutableOpenMap<String, Settings> settings = ImmutableOpenMap.of();
private ImmutableOpenMap<String, Settings> defaultSettings = ImmutableOpenMap.of();
private String[] indices;
GetIndexResponse(String[] indices,
ImmutableOpenMap<String, ImmutableOpenMap<String, MappingMetaData>> mappings,
ImmutableOpenMap<String, List<AliasMetaData>> aliases, ImmutableOpenMap<String, Settings> settings) {
ImmutableOpenMap<String, ImmutableOpenMap<String, MappingMetaData>> mappings,
ImmutableOpenMap<String, List<AliasMetaData>> aliases,
ImmutableOpenMap<String, Settings> settings,
ImmutableOpenMap<String, Settings> defaultSettings) {
this.indices = indices;
// to have deterministic order
Arrays.sort(indices);
if (mappings != null) {
this.mappings = mappings;
}
@ -56,6 +73,9 @@ public class GetIndexResponse extends ActionResponse {
if (settings != null) {
this.settings = settings;
}
if (defaultSettings != null) {
this.defaultSettings = defaultSettings;
}
}
GetIndexResponse() {
@ -89,14 +109,51 @@ public class GetIndexResponse extends ActionResponse {
return settings;
}
/**
* If the originating {@link GetIndexRequest} object was configured to include
* defaults, this will contain a mapping of index name to {@link Settings} objects.
* The returned {@link Settings} objects will contain only those settings taking
* effect as defaults. Any settings explicitly set on the index will be available
* via {@link #settings()}.
* See also {@link GetIndexRequest#includeDefaults(boolean)}
*/
public ImmutableOpenMap<String, Settings> defaultSettings() {
return defaultSettings;
}
public ImmutableOpenMap<String, Settings> getSettings() {
return settings();
}
/**
* Returns the string value for the specified index and setting. If the includeDefaults flag was not set or set to
* false on the {@link GetIndexRequest}, this method will only return a value where the setting was explicitly set
* on the index. If the includeDefaults flag was set to true on the {@link GetIndexRequest}, this method will fall
* back to return the default value if the setting was not explicitly set.
*/
public String getSetting(String index, String setting) {
Settings indexSettings = settings.get(index);
if (setting != null) {
if (indexSettings != null && indexSettings.hasValue(setting)) {
return indexSettings.get(setting);
} else {
Settings defaultIndexSettings = defaultSettings.get(index);
if (defaultIndexSettings != null) {
return defaultIndexSettings.get(setting);
} else {
return null;
}
}
} else {
return null;
}
}
@Override
public void readFrom(StreamInput in) throws IOException {
super.readFrom(in);
this.indices = in.readStringArray();
int mappingsSize = in.readVInt();
ImmutableOpenMap.Builder<String, ImmutableOpenMap<String, MappingMetaData>> mappingsMapBuilder = ImmutableOpenMap.builder();
for (int i = 0; i < mappingsSize; i++) {
@ -109,6 +166,7 @@ public class GetIndexResponse extends ActionResponse {
mappingsMapBuilder.put(key, mappingEntryBuilder.build());
}
mappings = mappingsMapBuilder.build();
int aliasesSize = in.readVInt();
ImmutableOpenMap.Builder<String, List<AliasMetaData>> aliasesMapBuilder = ImmutableOpenMap.builder();
for (int i = 0; i < aliasesSize; i++) {
@ -121,6 +179,7 @@ public class GetIndexResponse extends ActionResponse {
aliasesMapBuilder.put(key, Collections.unmodifiableList(aliasEntryBuilder));
}
aliases = aliasesMapBuilder.build();
int settingsSize = in.readVInt();
ImmutableOpenMap.Builder<String, Settings> settingsMapBuilder = ImmutableOpenMap.builder();
for (int i = 0; i < settingsSize; i++) {
@ -128,6 +187,15 @@ public class GetIndexResponse extends ActionResponse {
settingsMapBuilder.put(key, Settings.readSettingsFromStream(in));
}
settings = settingsMapBuilder.build();
ImmutableOpenMap.Builder<String, Settings> defaultSettingsMapBuilder = ImmutableOpenMap.builder();
if (in.getVersion().onOrAfter(Version.V_6_4_0)) {
int defaultSettingsSize = in.readVInt();
for (int i = 0; i < defaultSettingsSize ; i++) {
defaultSettingsMapBuilder.put(in.readString(), Settings.readSettingsFromStream(in));
}
}
defaultSettings = defaultSettingsMapBuilder.build();
}
@Override
@ -156,5 +224,202 @@ public class GetIndexResponse extends ActionResponse {
out.writeString(indexEntry.key);
Settings.writeSettingsToStream(indexEntry.value, out);
}
if (out.getVersion().onOrAfter(Version.V_6_4_0)) {
out.writeVInt(defaultSettings.size());
for (ObjectObjectCursor<String, Settings> indexEntry : defaultSettings) {
out.writeString(indexEntry.key);
Settings.writeSettingsToStream(indexEntry.value, out);
}
}
}
@Override
public XContentBuilder toXContent(XContentBuilder builder, Params params) throws IOException {
builder.startObject();
{
for (final String index : indices) {
builder.startObject(index);
{
builder.startObject("aliases");
List<AliasMetaData> indexAliases = aliases.get(index);
if (indexAliases != null) {
for (final AliasMetaData alias : indexAliases) {
AliasMetaData.Builder.toXContent(alias, builder, params);
}
}
builder.endObject();
builder.startObject("mappings");
ImmutableOpenMap<String, MappingMetaData> indexMappings = mappings.get(index);
if (indexMappings != null) {
for (final ObjectObjectCursor<String, MappingMetaData> typeEntry : indexMappings) {
builder.field(typeEntry.key);
builder.map(typeEntry.value.sourceAsMap());
}
}
builder.endObject();
builder.startObject("settings");
Settings indexSettings = settings.get(index);
if (indexSettings != null) {
indexSettings.toXContent(builder, params);
}
builder.endObject();
Settings defaultIndexSettings = defaultSettings.get(index);
if (defaultIndexSettings != null && defaultIndexSettings.isEmpty() == false) {
builder.startObject("defaults");
defaultIndexSettings.toXContent(builder, params);
builder.endObject();
}
}
builder.endObject();
}
}
builder.endObject();
return builder;
}
private static List<AliasMetaData> parseAliases(XContentParser parser) throws IOException {
List<AliasMetaData> indexAliases = new ArrayList<>();
// We start at START_OBJECT since parseIndexEntry ensures that
while (parser.nextToken() != Token.END_OBJECT) {
ensureExpectedToken(Token.FIELD_NAME, parser.currentToken(), parser::getTokenLocation);
indexAliases.add(AliasMetaData.Builder.fromXContent(parser));
}
return indexAliases;
}
private static ImmutableOpenMap<String, MappingMetaData> parseMappings(XContentParser parser) throws IOException {
ImmutableOpenMap.Builder<String, MappingMetaData> indexMappings = ImmutableOpenMap.builder();
// We start at START_OBJECT since parseIndexEntry ensures that
while (parser.nextToken() != Token.END_OBJECT) {
ensureExpectedToken(Token.FIELD_NAME, parser.currentToken(), parser::getTokenLocation);
parser.nextToken();
if (parser.currentToken() == Token.START_OBJECT) {
String mappingType = parser.currentName();
indexMappings.put(mappingType, new MappingMetaData(mappingType, parser.map()));
} else if (parser.currentToken() == Token.START_ARRAY) {
parser.skipChildren();
}
}
return indexMappings.build();
}
private static IndexEntry parseIndexEntry(XContentParser parser) throws IOException {
List<AliasMetaData> indexAliases = null;
ImmutableOpenMap<String, MappingMetaData> indexMappings = null;
Settings indexSettings = null;
Settings indexDefaultSettings = null;
// We start at START_OBJECT since fromXContent ensures that
while (parser.nextToken() != Token.END_OBJECT) {
ensureExpectedToken(Token.FIELD_NAME, parser.currentToken(), parser::getTokenLocation);
parser.nextToken();
if (parser.currentToken() == Token.START_OBJECT) {
switch (parser.currentName()) {
case "aliases":
indexAliases = parseAliases(parser);
break;
case "mappings":
indexMappings = parseMappings(parser);
break;
case "settings":
indexSettings = Settings.fromXContent(parser);
break;
case "defaults":
indexDefaultSettings = Settings.fromXContent(parser);
break;
default:
parser.skipChildren();
}
} else if (parser.currentToken() == Token.START_ARRAY) {
parser.skipChildren();
}
}
return new IndexEntry(indexAliases, indexMappings, indexSettings, indexDefaultSettings);
}
// This is just an internal container to make stuff easier for returning
private static class IndexEntry {
List<AliasMetaData> indexAliases = new ArrayList<>();
ImmutableOpenMap<String, MappingMetaData> indexMappings = ImmutableOpenMap.of();
Settings indexSettings = Settings.EMPTY;
Settings indexDefaultSettings = Settings.EMPTY;
IndexEntry(List<AliasMetaData> indexAliases, ImmutableOpenMap<String, MappingMetaData> indexMappings,
Settings indexSettings, Settings indexDefaultSettings) {
if (indexAliases != null) this.indexAliases = indexAliases;
if (indexMappings != null) this.indexMappings = indexMappings;
if (indexSettings != null) this.indexSettings = indexSettings;
if (indexDefaultSettings != null) this.indexDefaultSettings = indexDefaultSettings;
}
}
public static GetIndexResponse fromXContent(XContentParser parser) throws IOException {
ImmutableOpenMap.Builder<String, List<AliasMetaData>> aliases = ImmutableOpenMap.builder();
ImmutableOpenMap.Builder<String, ImmutableOpenMap<String, MappingMetaData>> mappings = ImmutableOpenMap.builder();
ImmutableOpenMap.Builder<String, Settings> settings = ImmutableOpenMap.builder();
ImmutableOpenMap.Builder<String, Settings> defaultSettings = ImmutableOpenMap.builder();
List<String> indices = new ArrayList<>();
if (parser.currentToken() == null) {
parser.nextToken();
}
ensureExpectedToken(Token.START_OBJECT, parser.currentToken(), parser::getTokenLocation);
parser.nextToken();
while (!parser.isClosed()) {
if (parser.currentToken() == Token.START_OBJECT) {
// we assume this is an index entry
String indexName = parser.currentName();
indices.add(indexName);
IndexEntry indexEntry = parseIndexEntry(parser);
// make the order deterministic
CollectionUtil.timSort(indexEntry.indexAliases, Comparator.comparing(AliasMetaData::alias));
aliases.put(indexName, Collections.unmodifiableList(indexEntry.indexAliases));
mappings.put(indexName, indexEntry.indexMappings);
settings.put(indexName, indexEntry.indexSettings);
if (indexEntry.indexDefaultSettings.isEmpty() == false) {
defaultSettings.put(indexName, indexEntry.indexDefaultSettings);
}
} else if (parser.currentToken() == Token.START_ARRAY) {
parser.skipChildren();
} else {
parser.nextToken();
}
}
return
new GetIndexResponse(
indices.toArray(new String[0]), mappings.build(), aliases.build(),
settings.build(), defaultSettings.build()
);
}
@Override
public String toString() {
return Strings.toString(this);
}
@Override
public boolean equals(Object o) {
if (this == o) return true;
if (o== null || getClass() != o.getClass()) return false;
GetIndexResponse that = (GetIndexResponse) o;
return Arrays.equals(indices, that.indices) &&
Objects.equals(aliases, that.aliases) &&
Objects.equals(mappings, that.mappings) &&
Objects.equals(settings, that.settings) &&
Objects.equals(defaultSettings, that.defaultSettings);
}
@Override
public int hashCode() {
return
Objects.hash(
Arrays.hashCode(indices),
aliases,
mappings,
settings,
defaultSettings
);
}
}

View File

@ -36,9 +36,11 @@ 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.settings.SettingsFilter;
import org.elasticsearch.indices.IndicesService;
import org.elasticsearch.threadpool.ThreadPool;
import org.elasticsearch.transport.TransportService;
import org.elasticsearch.common.settings.IndexScopedSettings;
import java.io.IOException;
import java.util.List;
@ -49,14 +51,19 @@ import java.util.List;
public class TransportGetIndexAction extends TransportClusterInfoAction<GetIndexRequest, GetIndexResponse> {
private final IndicesService indicesService;
private final IndexScopedSettings indexScopedSettings;
private final SettingsFilter settingsFilter;
@Inject
public TransportGetIndexAction(Settings settings, TransportService transportService, ClusterService clusterService,
ThreadPool threadPool, ActionFilters actionFilters,
IndexNameExpressionResolver indexNameExpressionResolver, IndicesService indicesService) {
ThreadPool threadPool, SettingsFilter settingsFilter, ActionFilters actionFilters,
IndexNameExpressionResolver indexNameExpressionResolver, IndicesService indicesService,
IndexScopedSettings indexScopedSettings) {
super(settings, GetIndexAction.NAME, transportService, clusterService, threadPool, actionFilters, GetIndexRequest::new,
indexNameExpressionResolver);
this.indicesService = indicesService;
this.settingsFilter = settingsFilter;
this.indexScopedSettings = indexScopedSettings;
}
@Override
@ -82,6 +89,7 @@ public class TransportGetIndexAction extends TransportClusterInfoAction<GetIndex
ImmutableOpenMap<String, ImmutableOpenMap<String, MappingMetaData>> mappingsResult = ImmutableOpenMap.of();
ImmutableOpenMap<String, List<AliasMetaData>> aliasesResult = ImmutableOpenMap.of();
ImmutableOpenMap<String, Settings> settings = ImmutableOpenMap.of();
ImmutableOpenMap<String, Settings> defaultSettings = ImmutableOpenMap.of();
Feature[] features = request.features();
boolean doneAliases = false;
boolean doneMappings = false;
@ -109,14 +117,21 @@ public class TransportGetIndexAction extends TransportClusterInfoAction<GetIndex
case SETTINGS:
if (!doneSettings) {
ImmutableOpenMap.Builder<String, Settings> settingsMapBuilder = ImmutableOpenMap.builder();
ImmutableOpenMap.Builder<String, Settings> defaultSettingsMapBuilder = ImmutableOpenMap.builder();
for (String index : concreteIndices) {
Settings indexSettings = state.metaData().index(index).getSettings();
if (request.humanReadable()) {
indexSettings = IndexMetaData.addHumanReadableSettings(indexSettings);
}
settingsMapBuilder.put(index, indexSettings);
if (request.includeDefaults()) {
Settings defaultIndexSettings =
settingsFilter.filter(indexScopedSettings.diff(indexSettings, Settings.EMPTY));
defaultSettingsMapBuilder.put(index, defaultIndexSettings);
}
}
settings = settingsMapBuilder.build();
defaultSettings = defaultSettingsMapBuilder.build();
doneSettings = true;
}
break;
@ -125,6 +140,8 @@ public class TransportGetIndexAction extends TransportClusterInfoAction<GetIndex
throw new IllegalStateException("feature [" + feature + "] is not valid");
}
}
listener.onResponse(new GetIndexResponse(concreteIndices, mappingsResult, aliasesResult, settings));
listener.onResponse(
new GetIndexResponse(concreteIndices, mappingsResult, aliasesResult, settings, defaultSettings)
);
}
}

View File

@ -19,55 +19,35 @@
package org.elasticsearch.rest.action.admin.indices;
import com.carrotsearch.hppc.cursors.ObjectObjectCursor;
import org.elasticsearch.action.admin.indices.get.GetIndexRequest;
import org.elasticsearch.action.admin.indices.get.GetIndexRequest.Feature;
import org.elasticsearch.action.admin.indices.get.GetIndexResponse;
import org.elasticsearch.action.support.IndicesOptions;
import org.elasticsearch.client.node.NodeClient;
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.settings.IndexScopedSettings;
import org.elasticsearch.common.settings.Settings;
import org.elasticsearch.common.settings.SettingsFilter;
import org.elasticsearch.common.xcontent.ToXContent.Params;
import org.elasticsearch.common.xcontent.XContentBuilder;
import org.elasticsearch.rest.BaseRestHandler;
import org.elasticsearch.rest.BytesRestResponse;
import org.elasticsearch.rest.RestController;
import org.elasticsearch.rest.RestRequest;
import org.elasticsearch.rest.RestResponse;
import org.elasticsearch.rest.action.RestBuilderListener;
import org.elasticsearch.rest.action.RestToXContentListener;
import java.io.IOException;
import java.util.List;
import java.util.Set;
import static org.elasticsearch.rest.RestRequest.Method.GET;
import static org.elasticsearch.rest.RestRequest.Method.HEAD;
import static org.elasticsearch.rest.RestStatus.OK;
/**
* The REST handler for get index and head index APIs.
*/
public class RestGetIndicesAction extends BaseRestHandler {
private final IndexScopedSettings indexScopedSettings;
private final SettingsFilter settingsFilter;
public RestGetIndicesAction(
final Settings settings,
final RestController controller,
final IndexScopedSettings indexScopedSettings,
final SettingsFilter settingsFilter) {
final RestController controller) {
super(settings);
this.indexScopedSettings = indexScopedSettings;
controller.registerHandler(GET, "/{index}", this);
controller.registerHandler(HEAD, "/{index}", this);
this.settingsFilter = settingsFilter;
}
@Override
@ -82,93 +62,10 @@ public class RestGetIndicesAction extends BaseRestHandler {
getIndexRequest.indices(indices);
getIndexRequest.indicesOptions(IndicesOptions.fromRequest(request, getIndexRequest.indicesOptions()));
getIndexRequest.local(request.paramAsBoolean("local", getIndexRequest.local()));
getIndexRequest.masterNodeTimeout(request.paramAsTime("master_timeout", getIndexRequest.masterNodeTimeout()));
getIndexRequest.humanReadable(request.paramAsBoolean("human", false));
final boolean defaults = request.paramAsBoolean("include_defaults", false);
return channel -> client.admin().indices().getIndex(getIndexRequest, new RestBuilderListener<GetIndexResponse>(channel) {
@Override
public RestResponse buildResponse(final GetIndexResponse response, final XContentBuilder builder) throws Exception {
builder.startObject();
{
for (final String index : response.indices()) {
builder.startObject(index);
{
for (final Feature feature : getIndexRequest.features()) {
switch (feature) {
case ALIASES:
writeAliases(response.aliases().get(index), builder, request);
break;
case MAPPINGS:
writeMappings(response.mappings().get(index), builder);
break;
case SETTINGS:
writeSettings(response.settings().get(index), builder, request, defaults);
break;
default:
throw new IllegalStateException("feature [" + feature + "] is not valid");
}
}
}
builder.endObject();
}
}
builder.endObject();
return new BytesRestResponse(OK, builder);
}
private void writeAliases(
final List<AliasMetaData> aliases,
final XContentBuilder builder,
final Params params) throws IOException {
builder.startObject("aliases");
{
if (aliases != null) {
for (final AliasMetaData alias : aliases) {
AliasMetaData.Builder.toXContent(alias, builder, params);
}
}
}
builder.endObject();
}
private void writeMappings(final ImmutableOpenMap<String, MappingMetaData> mappings, final XContentBuilder builder)
throws IOException {
builder.startObject("mappings");
{
if (mappings != null) {
for (final ObjectObjectCursor<String, MappingMetaData> typeEntry : mappings) {
builder.field(typeEntry.key);
builder.map(typeEntry.value.sourceAsMap());
}
}
}
builder.endObject();
}
private void writeSettings(
final Settings settings,
final XContentBuilder builder,
final Params params,
final boolean defaults) throws IOException {
builder.startObject("settings");
{
settings.toXContent(builder, params);
}
builder.endObject();
if (defaults) {
builder.startObject("defaults");
{
settingsFilter
.filter(indexScopedSettings.diff(settings, RestGetIndicesAction.this.settings))
.toXContent(builder, request);
}
builder.endObject();
}
}
});
getIndexRequest.includeDefaults(request.paramAsBoolean("include_defaults", false));
return channel -> client.admin().indices().getIndex(getIndexRequest, new RestToXContentListener<>(channel));
}
@Override

View File

@ -0,0 +1,144 @@
/*
* 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.ActionListener;
import org.elasticsearch.action.IndicesRequest;
import org.elasticsearch.action.support.ActionFilters;
import org.elasticsearch.action.support.replication.ClusterStateCreationUtils;
import org.elasticsearch.cluster.ClusterState;
import org.elasticsearch.cluster.metadata.IndexNameExpressionResolver;
import org.elasticsearch.cluster.service.ClusterService;
import org.elasticsearch.common.settings.IndexScopedSettings;
import org.elasticsearch.common.settings.Settings;
import org.elasticsearch.common.settings.SettingsFilter;
import org.elasticsearch.common.settings.SettingsModule;
import org.elasticsearch.index.Index;
import org.elasticsearch.indices.IndicesService;
import org.elasticsearch.test.ESSingleNodeTestCase;
import org.elasticsearch.test.transport.CapturingTransport;
import org.elasticsearch.threadpool.TestThreadPool;
import org.elasticsearch.threadpool.ThreadPool;
import org.elasticsearch.transport.TransportService;
import org.junit.After;
import org.junit.Before;
import java.util.Collections;
import java.util.concurrent.TimeUnit;
public class GetIndexActionTests extends ESSingleNodeTestCase {
private TransportService transportService;
private ClusterService clusterService;
private IndicesService indicesService;
private ThreadPool threadPool;
private SettingsFilter settingsFilter;
private final String indexName = "test_index";
private TestTransportGetIndexAction getIndexAction;
@Before
public void setUp() throws Exception {
super.setUp();
settingsFilter = new SettingsModule(Settings.EMPTY, Collections.emptyList(), Collections.emptyList()).getSettingsFilter();
threadPool = new TestThreadPool("GetIndexActionTests");
clusterService = getInstanceFromNode(ClusterService.class);
indicesService = getInstanceFromNode(IndicesService.class);
CapturingTransport capturingTransport = new CapturingTransport();
transportService = new TransportService(clusterService.getSettings(), capturingTransport, threadPool,
TransportService.NOOP_TRANSPORT_INTERCEPTOR,
boundAddress -> clusterService.localNode(), null, Collections.emptySet());
transportService.start();
transportService.acceptIncomingRequests();
getIndexAction = new GetIndexActionTests.TestTransportGetIndexAction();
}
@After
public void tearDown() throws Exception {
ThreadPool.terminate(threadPool, 30, TimeUnit.SECONDS);
threadPool = null;
super.tearDown();
}
public void testIncludeDefaults() {
GetIndexRequest defaultsRequest = new GetIndexRequest().indices(indexName).includeDefaults(true);
getIndexAction.execute(null, defaultsRequest, ActionListener.wrap(
defaultsResponse -> {
assertNotNull(
"index.refresh_interval should be set as we are including defaults",
defaultsResponse.getSetting(indexName, "index.refresh_interval")
);
}, exception -> {
throw new AssertionError(exception);
})
);
}
public void testDoNotIncludeDefaults() {
GetIndexRequest noDefaultsRequest = new GetIndexRequest().indices(indexName);
getIndexAction.execute(null, noDefaultsRequest, ActionListener.wrap(
noDefaultsResponse -> {
assertNull(
"index.refresh_interval should be null as it was never set",
noDefaultsResponse.getSetting(indexName, "index.refresh_interval")
);
}, exception -> {
throw new AssertionError(exception);
})
);
}
class TestTransportGetIndexAction extends TransportGetIndexAction {
TestTransportGetIndexAction() {
super(Settings.EMPTY, GetIndexActionTests.this.transportService, GetIndexActionTests.this.clusterService,
GetIndexActionTests.this.threadPool, settingsFilter, new ActionFilters(Collections.emptySet()),
new GetIndexActionTests.Resolver(Settings.EMPTY), indicesService, IndexScopedSettings.DEFAULT_SCOPED_SETTINGS);
}
@Override
protected void doMasterOperation(GetIndexRequest request, String[] concreteIndices, ClusterState state,
ActionListener<GetIndexResponse> listener) {
ClusterState stateWithIndex = ClusterStateCreationUtils.state(indexName, 1, 1);
super.doMasterOperation(request, concreteIndices, stateWithIndex, listener);
}
}
static class Resolver extends IndexNameExpressionResolver {
Resolver(Settings settings) {
super(settings);
}
@Override
public String[] concreteIndexNames(ClusterState state, IndicesRequest request) {
return request.indices();
}
@Override
public Index[] concreteIndices(ClusterState state, IndicesRequest request) {
Index[] out = new Index[request.indices().length];
for (int x = 0; x < out.length; x++) {
out[x] = new Index(request.indices()[x], "_na_");
}
return out;
}
}
}

View File

@ -0,0 +1,194 @@
/*
* 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.apache.lucene.util.CollectionUtil;
import org.elasticsearch.Version;
import org.elasticsearch.action.admin.indices.alias.get.GetAliasesResponseTests;
import org.elasticsearch.action.admin.indices.mapping.get.GetMappingsResponseTests;
import org.elasticsearch.cluster.metadata.AliasMetaData;
import org.elasticsearch.cluster.metadata.MappingMetaData;
import org.elasticsearch.common.bytes.BytesReference;
import org.elasticsearch.common.collect.ImmutableOpenMap;
import org.elasticsearch.common.io.stream.BytesStreamOutput;
import org.elasticsearch.common.io.stream.StreamInput;
import org.elasticsearch.common.settings.IndexScopedSettings;
import org.elasticsearch.common.settings.Settings;
import org.elasticsearch.common.xcontent.XContentParser;
import org.elasticsearch.index.RandomCreateIndexGenerator;
import org.elasticsearch.test.AbstractStreamableXContentTestCase;
import org.junit.Assert;
import java.io.IOException;
import java.io.UncheckedIOException;
import java.util.ArrayList;
import java.util.Base64;
import java.util.Collections;
import java.util.Comparator;
import java.util.List;
import java.util.function.Predicate;
import static org.elasticsearch.cluster.metadata.IndexMetaData.SETTING_NUMBER_OF_REPLICAS;
import static org.elasticsearch.cluster.metadata.IndexMetaData.SETTING_NUMBER_OF_SHARDS;
import static org.elasticsearch.index.IndexSettings.INDEX_REFRESH_INTERVAL_SETTING;
public class GetIndexResponseTests extends AbstractStreamableXContentTestCase<GetIndexResponse> {
/**
* The following byte response was generated from the v6.3.0 tag
*/
private static final String TEST_6_3_0_RESPONSE_BYTES =
"AQhteV9pbmRleAEIbXlfaW5kZXgBA2RvYwNkb2OePID6KURGTACqVkrLTM1JiTdUsqpWKqksSFWyUiouKcrMS1eqrQUAAAD//" +
"wMAAAABCG15X2luZGV4AgZhbGlhczEAAQJyMQECcjEGYWxpYXMyAX8jNXYiREZMAKpWKkktylWyqlaqTE0sUrIyMjA0q60FAAAA//" +
"8DAAAAAQhteV9pbmRleAIYaW5kZXgubnVtYmVyX29mX3JlcGxpY2FzAAExFmluZGV4Lm51bWJlcl9vZl9zaGFyZHMAATI=";
private static final GetIndexResponse TEST_6_3_0_RESPONSE_INSTANCE = getExpectedTest630Response();
@Override
protected GetIndexResponse doParseInstance(XContentParser parser) throws IOException {
return GetIndexResponse.fromXContent(parser);
}
@Override
protected GetIndexResponse createBlankInstance() {
return new GetIndexResponse();
}
@Override
protected GetIndexResponse createTestInstance() {
String[] indices = generateRandomStringArray(5, 5, false, false);
ImmutableOpenMap.Builder<String, ImmutableOpenMap<String, MappingMetaData>> mappings = ImmutableOpenMap.builder();
ImmutableOpenMap.Builder<String, List<AliasMetaData>> aliases = ImmutableOpenMap.builder();
ImmutableOpenMap.Builder<String, Settings> settings = ImmutableOpenMap.builder();
ImmutableOpenMap.Builder<String, Settings> defaultSettings = ImmutableOpenMap.builder();
IndexScopedSettings indexScopedSettings = IndexScopedSettings.DEFAULT_SCOPED_SETTINGS;
boolean includeDefaults = randomBoolean();
for (String index: indices) {
mappings.put(index, GetMappingsResponseTests.createMappingsForIndex());
List<AliasMetaData> aliasMetaDataList = new ArrayList<>();
int aliasesNum = randomIntBetween(0, 3);
for (int i=0; i<aliasesNum; i++) {
aliasMetaDataList.add(GetAliasesResponseTests.createAliasMetaData());
}
CollectionUtil.timSort(aliasMetaDataList, Comparator.comparing(AliasMetaData::alias));
aliases.put(index, Collections.unmodifiableList(aliasMetaDataList));
Settings.Builder builder = Settings.builder();
builder.put(RandomCreateIndexGenerator.randomIndexSettings());
settings.put(index, builder.build());
if (includeDefaults) {
defaultSettings.put(index, indexScopedSettings.diff(settings.get(index), Settings.EMPTY));
}
}
return new GetIndexResponse(
indices, mappings.build(), aliases.build(), settings.build(), defaultSettings.build()
);
}
@Override
protected Predicate<String> getRandomFieldsExcludeFilter() {
//we do not want to add new fields at the root (index-level), or inside the blocks
return
f -> f.equals("") || f.contains(".settings") || f.contains(".defaults") || f.contains(".mappings") ||
f.contains(".aliases");
}
private static ImmutableOpenMap<String, List<AliasMetaData>> getTestAliases(String indexName) {
ImmutableOpenMap.Builder<String, List<AliasMetaData>> aliases = ImmutableOpenMap.builder();
List<AliasMetaData> indexAliases = new ArrayList<>();
indexAliases.add(new AliasMetaData.Builder("alias1").routing("r1").build());
indexAliases.add(new AliasMetaData.Builder("alias2").filter("{\"term\": {\"year\": 2016}}").build());
aliases.put(indexName, Collections.unmodifiableList(indexAliases));
return aliases.build();
}
private static ImmutableOpenMap<String, ImmutableOpenMap<String, MappingMetaData>> getTestMappings(String indexName) {
ImmutableOpenMap.Builder<String, ImmutableOpenMap<String, MappingMetaData>> mappings = ImmutableOpenMap.builder();
ImmutableOpenMap.Builder<String, MappingMetaData> indexMappings = ImmutableOpenMap.builder();
try {
indexMappings.put(
"doc",
new MappingMetaData("doc",
Collections.singletonMap("field_1", Collections.singletonMap("type", "string"))
)
);
} catch (IOException e) {
throw new UncheckedIOException(e);
}
mappings.put(indexName, indexMappings.build());
return mappings.build();
}
private static ImmutableOpenMap<String, Settings> getTestSettings(String indexName) {
ImmutableOpenMap.Builder<String, Settings> settings = ImmutableOpenMap.builder();
Settings.Builder indexSettings = Settings.builder();
indexSettings.put(SETTING_NUMBER_OF_SHARDS, 2);
indexSettings.put(SETTING_NUMBER_OF_REPLICAS, 1);
settings.put(indexName, indexSettings.build());
return settings.build();
}
private static GetIndexResponse getExpectedTest630Response() {
// The only difference between this snippet and the one used for generation TEST_6_3_0_RESPONSE_BYTES is the
// constructor for GetIndexResponse which also takes defaultSettings now.
String indexName = "my_index";
String indices[] = { indexName };
return
new GetIndexResponse(
indices, getTestMappings(indexName), getTestAliases(indexName), getTestSettings(indexName),
ImmutableOpenMap.of()
);
}
private static GetIndexResponse getResponseWithDefaultSettings() {
String indexName = "my_index";
String indices[] = { indexName };
ImmutableOpenMap.Builder<String, Settings> defaultSettings = ImmutableOpenMap.builder();
Settings.Builder indexDefaultSettings = Settings.builder();
indexDefaultSettings.put(INDEX_REFRESH_INTERVAL_SETTING.getKey(), "1s");
defaultSettings.put(indexName, indexDefaultSettings.build());
return
new GetIndexResponse(
indices, getTestMappings(indexName), getTestAliases(indexName), getTestSettings(indexName),
defaultSettings.build()
);
}
public void testCanDecode622Response() throws IOException {
StreamInput si = StreamInput.wrap(Base64.getDecoder().decode(TEST_6_3_0_RESPONSE_BYTES));
si.setVersion(Version.V_6_3_0);
GetIndexResponse response = new GetIndexResponse();
response.readFrom(si);
Assert.assertEquals(TEST_6_3_0_RESPONSE_INSTANCE, response);
}
public void testCanOutput622Response() throws IOException {
GetIndexResponse responseWithExtraFields = getResponseWithDefaultSettings();
BytesStreamOutput bso = new BytesStreamOutput();
bso.setVersion(Version.V_6_3_0);
responseWithExtraFields.writeTo(bso);
String base64OfResponse = Base64.getEncoder().encodeToString(BytesReference.toBytes(bso.bytes()));
Assert.assertEquals(TEST_6_3_0_RESPONSE_BYTES, base64OfResponse);
}
}

View File

@ -80,8 +80,7 @@ public class GetMappingsResponseTests extends AbstractStreamableXContentTestCase
return mutate(instance);
}
@Override
protected GetMappingsResponse createTestInstance() {
public static ImmutableOpenMap<String, MappingMetaData> createMappingsForIndex() {
// rarely have no types
int typeCount = rarely() ? 0 : scaledRandomIntBetween(1, 3);
List<MappingMetaData> typeMappings = new ArrayList<>(typeCount);
@ -104,8 +103,13 @@ public class GetMappingsResponseTests extends AbstractStreamableXContentTestCase
}
ImmutableOpenMap.Builder<String, MappingMetaData> typeBuilder = ImmutableOpenMap.builder();
typeMappings.forEach(mmd -> typeBuilder.put(mmd.type(), mmd));
return typeBuilder.build();
}
@Override
protected GetMappingsResponse createTestInstance() {
ImmutableOpenMap.Builder<String, ImmutableOpenMap<String, MappingMetaData>> indexBuilder = ImmutableOpenMap.builder();
indexBuilder.put("index-" + randomAlphaOfLength(5), typeBuilder.build());
indexBuilder.put("index-" + randomAlphaOfLength(5), createMappingsForIndex());
GetMappingsResponse resp = new GetMappingsResponse(indexBuilder.build());
logger.debug("--> created: {}", resp);
return resp;