Includes the index UUID in the _cat/indices API and adds tests
for the _cat/indices functionality. Closes #19204 Closes #19132
This commit is contained in:
parent
ff42d7cfc6
commit
cb20776439
|
@ -38,6 +38,7 @@ import org.elasticsearch.common.Strings;
|
||||||
import org.elasticsearch.common.Table;
|
import org.elasticsearch.common.Table;
|
||||||
import org.elasticsearch.common.inject.Inject;
|
import org.elasticsearch.common.inject.Inject;
|
||||||
import org.elasticsearch.common.settings.Settings;
|
import org.elasticsearch.common.settings.Settings;
|
||||||
|
import org.elasticsearch.index.Index;
|
||||||
import org.elasticsearch.rest.RestChannel;
|
import org.elasticsearch.rest.RestChannel;
|
||||||
import org.elasticsearch.rest.RestController;
|
import org.elasticsearch.rest.RestController;
|
||||||
import org.elasticsearch.rest.RestRequest;
|
import org.elasticsearch.rest.RestRequest;
|
||||||
|
@ -84,7 +85,7 @@ public class RestIndicesAction extends AbstractCatAction {
|
||||||
@Override
|
@Override
|
||||||
public void processResponse(final ClusterStateResponse clusterStateResponse) {
|
public void processResponse(final ClusterStateResponse clusterStateResponse) {
|
||||||
final ClusterState state = clusterStateResponse.getState();
|
final ClusterState state = clusterStateResponse.getState();
|
||||||
final String[] concreteIndices = indexNameExpressionResolver.concreteIndexNames(state, strictExpandIndicesOptions, indices);
|
final Index[] concreteIndices = indexNameExpressionResolver.concreteIndices(state, strictExpandIndicesOptions, indices);
|
||||||
// concreteIndices should contain exactly the indices in state.metaData() that were selected by clusterStateRequest using
|
// concreteIndices should contain exactly the indices in state.metaData() that were selected by clusterStateRequest using
|
||||||
// IndicesOptions.strictExpand(). We select the indices again here so that they can be displayed in the resulting table
|
// IndicesOptions.strictExpand(). We select the indices again here so that they can be displayed in the resulting table
|
||||||
// in the requesting order.
|
// in the requesting order.
|
||||||
|
@ -129,6 +130,7 @@ public class RestIndicesAction extends AbstractCatAction {
|
||||||
table.addCell("health", "alias:h;desc:current health status");
|
table.addCell("health", "alias:h;desc:current health status");
|
||||||
table.addCell("status", "alias:s;desc:open/close status");
|
table.addCell("status", "alias:s;desc:open/close status");
|
||||||
table.addCell("index", "alias:i,idx;desc:index name");
|
table.addCell("index", "alias:i,idx;desc:index name");
|
||||||
|
table.addCell("uuid", "alias:id,uuid;desc:index uuid");
|
||||||
table.addCell("pri", "alias:p,shards.primary,shardsPrimary;text-align:right;desc:number of primary shards");
|
table.addCell("pri", "alias:p,shards.primary,shardsPrimary;text-align:right;desc:number of primary shards");
|
||||||
table.addCell("rep", "alias:r,shards.replica,shardsReplica;text-align:right;desc:number of replica shards");
|
table.addCell("rep", "alias:r,shards.replica,shardsReplica;text-align:right;desc:number of replica shards");
|
||||||
table.addCell("docs.count", "alias:dc,docsCount;text-align:right;desc:available docs");
|
table.addCell("docs.count", "alias:dc,docsCount;text-align:right;desc:available docs");
|
||||||
|
@ -312,19 +314,22 @@ public class RestIndicesAction extends AbstractCatAction {
|
||||||
return table;
|
return table;
|
||||||
}
|
}
|
||||||
|
|
||||||
private Table buildTable(RestRequest request, String[] indices, ClusterHealthResponse health, IndicesStatsResponse stats, MetaData indexMetaDatas) {
|
// package private for testing
|
||||||
|
Table buildTable(RestRequest request, Index[] indices, ClusterHealthResponse health, IndicesStatsResponse stats, MetaData indexMetaDatas) {
|
||||||
Table table = getTableWithHeader(request);
|
Table table = getTableWithHeader(request);
|
||||||
|
|
||||||
for (String index : indices) {
|
for (final Index index : indices) {
|
||||||
ClusterIndexHealth indexHealth = health.getIndices().get(index);
|
final String indexName = index.getName();
|
||||||
IndexStats indexStats = stats.getIndices().get(index);
|
ClusterIndexHealth indexHealth = health.getIndices().get(indexName);
|
||||||
IndexMetaData indexMetaData = indexMetaDatas.getIndices().get(index);
|
IndexStats indexStats = stats.getIndices().get(indexName);
|
||||||
|
IndexMetaData indexMetaData = indexMetaDatas.getIndices().get(indexName);
|
||||||
IndexMetaData.State state = indexMetaData.getState();
|
IndexMetaData.State state = indexMetaData.getState();
|
||||||
|
|
||||||
table.startRow();
|
table.startRow();
|
||||||
table.addCell(state == IndexMetaData.State.OPEN ? (indexHealth == null ? "red*" : indexHealth.getStatus().toString().toLowerCase(Locale.ROOT)) : null);
|
table.addCell(state == IndexMetaData.State.OPEN ? (indexHealth == null ? "red*" : indexHealth.getStatus().toString().toLowerCase(Locale.ROOT)) : null);
|
||||||
table.addCell(state.toString().toLowerCase(Locale.ROOT));
|
table.addCell(state.toString().toLowerCase(Locale.ROOT));
|
||||||
table.addCell(index);
|
table.addCell(indexName);
|
||||||
|
table.addCell(index.getUUID());
|
||||||
table.addCell(indexHealth == null ? null : indexHealth.getNumberOfShards());
|
table.addCell(indexHealth == null ? null : indexHealth.getNumberOfShards());
|
||||||
table.addCell(indexHealth == null ? null : indexHealth.getNumberOfReplicas());
|
table.addCell(indexHealth == null ? null : indexHealth.getNumberOfReplicas());
|
||||||
table.addCell(indexStats == null ? null : indexStats.getPrimaries().getDocs().getCount());
|
table.addCell(indexStats == null ? null : indexStats.getPrimaries().getDocs().getCount());
|
||||||
|
|
|
@ -19,6 +19,7 @@
|
||||||
|
|
||||||
package org.elasticsearch.action.admin.indices.stats;
|
package org.elasticsearch.action.admin.indices.stats;
|
||||||
|
|
||||||
|
import org.elasticsearch.action.ShardOperationFailedException;
|
||||||
import org.elasticsearch.common.xcontent.XContentBuilder;
|
import org.elasticsearch.common.xcontent.XContentBuilder;
|
||||||
import org.elasticsearch.common.xcontent.XContentFactory;
|
import org.elasticsearch.common.xcontent.XContentFactory;
|
||||||
import org.elasticsearch.index.engine.CommitStats;
|
import org.elasticsearch.index.engine.CommitStats;
|
||||||
|
@ -26,6 +27,8 @@ import org.elasticsearch.index.engine.SegmentsStats;
|
||||||
import org.elasticsearch.index.translog.Translog;
|
import org.elasticsearch.index.translog.Translog;
|
||||||
import org.elasticsearch.test.ESSingleNodeTestCase;
|
import org.elasticsearch.test.ESSingleNodeTestCase;
|
||||||
|
|
||||||
|
import java.util.List;
|
||||||
|
|
||||||
import static org.elasticsearch.test.hamcrest.ElasticsearchAssertions.assertAcked;
|
import static org.elasticsearch.test.hamcrest.ElasticsearchAssertions.assertAcked;
|
||||||
import static org.hamcrest.Matchers.greaterThan;
|
import static org.hamcrest.Matchers.greaterThan;
|
||||||
import static org.hamcrest.Matchers.hasKey;
|
import static org.hamcrest.Matchers.hasKey;
|
||||||
|
@ -108,4 +111,12 @@ public class IndicesStatsTests extends ESSingleNodeTestCase {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Gives access to package private IndicesStatsResponse constructor for test purpose.
|
||||||
|
**/
|
||||||
|
public static IndicesStatsResponse newIndicesStatsResponse(ShardStats[] shards, int totalShards, int successfulShards,
|
||||||
|
int failedShards, List<ShardOperationFailedException> shardFailures) {
|
||||||
|
return new IndicesStatsResponse(shards, totalShards, successfulShards, failedShards, shardFailures);
|
||||||
|
}
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
|
@ -0,0 +1,162 @@
|
||||||
|
/*
|
||||||
|
* Licensed to Elasticsearch under one or more contributor
|
||||||
|
* license agreements. See the NOTICE file distributed with
|
||||||
|
* this work for additional information regarding copyright
|
||||||
|
* ownership. Elasticsearch licenses this file to you under
|
||||||
|
* the Apache License, Version 2.0 (the "License"); you may
|
||||||
|
* not use this file except in compliance with the License.
|
||||||
|
* You may obtain a copy of the License at
|
||||||
|
*
|
||||||
|
* http://www.apache.org/licenses/LICENSE-2.0
|
||||||
|
*
|
||||||
|
* Unless required by applicable law or agreed to in writing,
|
||||||
|
* software distributed under the License is distributed on an
|
||||||
|
* "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
|
||||||
|
* KIND, either express or implied. See the License for the
|
||||||
|
* specific language governing permissions and limitations
|
||||||
|
* under the License.
|
||||||
|
*/
|
||||||
|
|
||||||
|
package org.elasticsearch.rest.action.cat;
|
||||||
|
|
||||||
|
import org.elasticsearch.Version;
|
||||||
|
import org.elasticsearch.action.admin.cluster.health.ClusterHealthResponse;
|
||||||
|
import org.elasticsearch.action.admin.indices.stats.CommonStats;
|
||||||
|
import org.elasticsearch.action.admin.indices.stats.IndicesStatsResponse;
|
||||||
|
import org.elasticsearch.action.admin.indices.stats.IndicesStatsTests;
|
||||||
|
import org.elasticsearch.action.admin.indices.stats.ShardStats;
|
||||||
|
import org.elasticsearch.cluster.ClusterName;
|
||||||
|
import org.elasticsearch.cluster.ClusterState;
|
||||||
|
import org.elasticsearch.cluster.metadata.IndexMetaData;
|
||||||
|
import org.elasticsearch.cluster.metadata.IndexNameExpressionResolver;
|
||||||
|
import org.elasticsearch.cluster.metadata.MetaData;
|
||||||
|
import org.elasticsearch.cluster.routing.ShardRouting;
|
||||||
|
import org.elasticsearch.cluster.routing.UnassignedInfo;
|
||||||
|
import org.elasticsearch.common.Table;
|
||||||
|
import org.elasticsearch.common.UUIDs;
|
||||||
|
import org.elasticsearch.common.settings.Settings;
|
||||||
|
import org.elasticsearch.common.unit.TimeValue;
|
||||||
|
import org.elasticsearch.index.Index;
|
||||||
|
import org.elasticsearch.index.cache.query.QueryCacheStats;
|
||||||
|
import org.elasticsearch.index.cache.request.RequestCacheStats;
|
||||||
|
import org.elasticsearch.index.engine.SegmentsStats;
|
||||||
|
import org.elasticsearch.index.fielddata.FieldDataStats;
|
||||||
|
import org.elasticsearch.index.flush.FlushStats;
|
||||||
|
import org.elasticsearch.index.get.GetStats;
|
||||||
|
import org.elasticsearch.index.merge.MergeStats;
|
||||||
|
import org.elasticsearch.index.refresh.RefreshStats;
|
||||||
|
import org.elasticsearch.index.search.stats.SearchStats;
|
||||||
|
import org.elasticsearch.index.shard.DocsStats;
|
||||||
|
import org.elasticsearch.index.shard.IndexingStats;
|
||||||
|
import org.elasticsearch.index.shard.ShardId;
|
||||||
|
import org.elasticsearch.index.shard.ShardPath;
|
||||||
|
import org.elasticsearch.index.store.StoreStats;
|
||||||
|
import org.elasticsearch.index.warmer.WarmerStats;
|
||||||
|
import org.elasticsearch.rest.RestController;
|
||||||
|
import org.elasticsearch.search.suggest.completion.CompletionStats;
|
||||||
|
import org.elasticsearch.test.ESTestCase;
|
||||||
|
|
||||||
|
import java.nio.file.Path;
|
||||||
|
import java.util.ArrayList;
|
||||||
|
import java.util.List;
|
||||||
|
|
||||||
|
import static java.util.Collections.emptyList;
|
||||||
|
import static org.hamcrest.Matchers.equalTo;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Tests for {@link RestIndicesAction}
|
||||||
|
*/
|
||||||
|
public class RestIndicesActionTests extends ESTestCase {
|
||||||
|
|
||||||
|
public void testBuildTable() {
|
||||||
|
final Settings settings = Settings.EMPTY;
|
||||||
|
final RestController restController = new RestController(settings);
|
||||||
|
final RestIndicesAction action = new RestIndicesAction(settings, restController, new IndexNameExpressionResolver(settings));
|
||||||
|
|
||||||
|
// build a (semi-)random table
|
||||||
|
final int numIndices = randomIntBetween(0, 5);
|
||||||
|
Index[] indices = new Index[numIndices];
|
||||||
|
for (int i = 0; i < numIndices; i++) {
|
||||||
|
indices[i] = new Index(randomAsciiOfLength(5), UUIDs.randomBase64UUID());
|
||||||
|
}
|
||||||
|
|
||||||
|
final MetaData.Builder metaDataBuilder = MetaData.builder();
|
||||||
|
for (final Index index : indices) {
|
||||||
|
metaDataBuilder.put(IndexMetaData.builder(index.getName())
|
||||||
|
.settings(Settings.builder()
|
||||||
|
.put(IndexMetaData.SETTING_VERSION_CREATED, Version.CURRENT)
|
||||||
|
.put(IndexMetaData.SETTING_INDEX_UUID, index.getUUID()))
|
||||||
|
.creationDate(System.currentTimeMillis())
|
||||||
|
.numberOfShards(1)
|
||||||
|
.numberOfReplicas(1)
|
||||||
|
.state(IndexMetaData.State.OPEN));
|
||||||
|
}
|
||||||
|
final MetaData metaData = metaDataBuilder.build();
|
||||||
|
|
||||||
|
final ClusterState clusterState = ClusterState.builder(ClusterName.CLUSTER_NAME_SETTING.getDefault(Settings.EMPTY))
|
||||||
|
.metaData(metaData)
|
||||||
|
.build();
|
||||||
|
final String[] indicesStr = new String[indices.length];
|
||||||
|
for (int i = 0; i < indices.length; i++) {
|
||||||
|
indicesStr[i] = indices[i].getName();
|
||||||
|
}
|
||||||
|
final ClusterHealthResponse clusterHealth = new ClusterHealthResponse(
|
||||||
|
clusterState.getClusterName().value(), indicesStr, clusterState, 0, 0, 0, TimeValue.timeValueMillis(1000L)
|
||||||
|
);
|
||||||
|
|
||||||
|
final Table table = action.buildTable(null, indices, clusterHealth, randomIndicesStatsResponse(indices), metaData);
|
||||||
|
|
||||||
|
// now, verify the table is correct
|
||||||
|
int count = 0;
|
||||||
|
List<Table.Cell> headers = table.getHeaders();
|
||||||
|
assertThat(headers.get(count++).value, equalTo("health"));
|
||||||
|
assertThat(headers.get(count++).value, equalTo("status"));
|
||||||
|
assertThat(headers.get(count++).value, equalTo("index"));
|
||||||
|
assertThat(headers.get(count++).value, equalTo("uuid"));
|
||||||
|
|
||||||
|
List<List<Table.Cell>> rows = table.getRows();
|
||||||
|
assertThat(rows.size(), equalTo(indices.length));
|
||||||
|
// TODO: more to verify (e.g. randomize cluster health, num primaries, num replicas, etc)
|
||||||
|
for (int i = 0; i < rows.size(); i++) {
|
||||||
|
count = 0;
|
||||||
|
final List<Table.Cell> row = rows.get(i);
|
||||||
|
assertThat(row.get(count++).value, equalTo("red*")); // all are red because cluster state doesn't have routing entries
|
||||||
|
assertThat(row.get(count++).value, equalTo("open")); // all are OPEN for now
|
||||||
|
assertThat(row.get(count++).value, equalTo(indices[i].getName()));
|
||||||
|
assertThat(row.get(count++).value, equalTo(indices[i].getUUID()));
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
private IndicesStatsResponse randomIndicesStatsResponse(final Index[] indices) {
|
||||||
|
List<ShardStats> shardStats = new ArrayList<>();
|
||||||
|
for (final Index index : indices) {
|
||||||
|
for (int i = 0; i < 2; i++) {
|
||||||
|
ShardId shardId = new ShardId(index, i);
|
||||||
|
Path path = createTempDir().resolve("indices").resolve(index.getUUID()).resolve(String.valueOf(i));
|
||||||
|
ShardRouting shardRouting = ShardRouting.newUnassigned(shardId, null, i == 0,
|
||||||
|
new UnassignedInfo(UnassignedInfo.Reason.INDEX_CREATED, null));
|
||||||
|
shardRouting = shardRouting.initialize("node-0", null, ShardRouting.UNAVAILABLE_EXPECTED_SHARD_SIZE);
|
||||||
|
shardRouting = shardRouting.moveToStarted();
|
||||||
|
CommonStats stats = new CommonStats();
|
||||||
|
stats.fieldData = new FieldDataStats();
|
||||||
|
stats.queryCache = new QueryCacheStats();
|
||||||
|
stats.docs = new DocsStats();
|
||||||
|
stats.store = new StoreStats();
|
||||||
|
stats.indexing = new IndexingStats();
|
||||||
|
stats.search = new SearchStats();
|
||||||
|
stats.segments = new SegmentsStats();
|
||||||
|
stats.merge = new MergeStats();
|
||||||
|
stats.refresh = new RefreshStats();
|
||||||
|
stats.completion = new CompletionStats();
|
||||||
|
stats.requestCache = new RequestCacheStats();
|
||||||
|
stats.get = new GetStats();
|
||||||
|
stats.flush = new FlushStats();
|
||||||
|
stats.warmer = new WarmerStats();
|
||||||
|
shardStats.add(new ShardStats(shardRouting, new ShardPath(false, path, path, shardId), stats, null));
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return IndicesStatsTests.newIndicesStatsResponse(
|
||||||
|
shardStats.toArray(new ShardStats[shardStats.size()]), shardStats.size(), shardStats.size(), 0, emptyList()
|
||||||
|
);
|
||||||
|
}
|
||||||
|
}
|
|
@ -26,6 +26,7 @@
|
||||||
/^(green \s+
|
/^(green \s+
|
||||||
open \s+
|
open \s+
|
||||||
index1 \s+
|
index1 \s+
|
||||||
|
([a-zA-Z0-9=/_+]|[\\\-]){22} \s+
|
||||||
1 \s+
|
1 \s+
|
||||||
0 \s+
|
0 \s+
|
||||||
0 \s+
|
0 \s+
|
||||||
|
@ -62,6 +63,7 @@
|
||||||
/^( \s+
|
/^( \s+
|
||||||
close \s+
|
close \s+
|
||||||
index1 \s+
|
index1 \s+
|
||||||
|
([a-zA-Z0-9=/_+]|[\\\-]){22} \s+
|
||||||
\s+
|
\s+
|
||||||
\s+
|
\s+
|
||||||
\s+
|
\s+
|
||||||
|
|
Loading…
Reference in New Issue