Skip to content
Merged
5 changes: 5 additions & 0 deletions docs/changelog/132858.yaml
Original file line number Diff line number Diff line change
@@ -0,0 +1,5 @@
pr: 132858
summary: Add index mode to resolve index response
area: Indices APIs
type: feature
issues: []
Original file line number Diff line number Diff line change
@@ -0,0 +1,74 @@
---
setup:
- do:
indices.delete:
index: my-std-index
ignore_unavailable: true
- do:
indices.delete:
index: my-ts-index
ignore_unavailable: true

# Only run this test if the cluster supports time series indexing.
# If your project uses a different feature flag name, adjust it here.
---
"resolve index returns mode for standard and time_series indices":
- requires:
cluster_features: ["gte_v8.5.0", "resolve_index_returns_mode"]
reason: "Requires time series indexing support introduced in v8.5.0 & Node must support returning 'mode' in indices.resolve_index response"

# Create a standard index
- do:
indices.create:
index: my-std-index
body:
settings:
number_of_shards: 1
number_of_replicas: 0

# Create a time-series index
- do:
indices.create:
index: my-ts-index
body:
settings:
index.mode: time_series
number_of_shards: 1
number_of_replicas: 0
index.routing_path: ["host"]
mappings:
properties:
"@timestamp":
type: date
host:
type: keyword
time_series_dimension: true
metric:
type: keyword
value:
type: double

# Resolve standard index and verify mode
- do:
indices.resolve_index:
name: my-std-index
- match: { indices.0.name: "my-std-index" }
- match: { indices.0.mode: "standard" }

# Resolve time-series index and verify mode
- do:
indices.resolve_index:
name: my-ts-index
- match: { indices.0.name: "my-ts-index" }
- match: { indices.0.mode: "time_series" }

---
teardown:
- do:
indices.delete:
index: my-std-index
ignore_unavailable: true
- do:
indices.delete:
index: my-ts-index
ignore_unavailable: true
3 changes: 2 additions & 1 deletion server/src/main/java/module-info.java
Original file line number Diff line number Diff line change
Expand Up @@ -434,7 +434,8 @@
org.elasticsearch.script.ScriptFeatures,
org.elasticsearch.search.retriever.RetrieversFeatures,
org.elasticsearch.action.admin.cluster.stats.ClusterStatsFeatures,
org.elasticsearch.ingest.IngestFeatures;
org.elasticsearch.ingest.IngestFeatures,
org.elasticsearch.action.admin.indices.resolve.ResolveIndexFeatures;

uses org.elasticsearch.plugins.internal.SettingsExtension;
uses RestExtension;
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -365,6 +365,7 @@ static TransportVersion def(int id) {
public static final TransportVersion SIMULATE_INGEST_MAPPING_MERGE_TYPE = def(9_138_0_00);
public static final TransportVersion ESQL_LOOKUP_JOIN_ON_MANY_FIELDS = def(9_139_0_00);
public static final TransportVersion SIMULATE_INGEST_EFFECTIVE_MAPPING = def(9_140_0_00);
public static final TransportVersion RESOLVE_INDEX_MODE_ADDED = def(9_141_0_00);

/*
* STOP! READ THIS FIRST! No, really,
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -9,6 +9,7 @@

package org.elasticsearch.action.admin.indices.resolve;

import org.elasticsearch.TransportVersions;
import org.elasticsearch.action.ActionListener;
import org.elasticsearch.action.ActionRequestValidationException;
import org.elasticsearch.action.ActionResponse;
Expand Down Expand Up @@ -39,6 +40,7 @@
import org.elasticsearch.common.util.concurrent.EsExecutors;
import org.elasticsearch.core.Nullable;
import org.elasticsearch.index.Index;
import org.elasticsearch.index.IndexMode;
import org.elasticsearch.injection.guice.Inject;
import org.elasticsearch.search.SearchService;
import org.elasticsearch.tasks.Task;
Expand Down Expand Up @@ -176,27 +178,35 @@ public static class ResolvedIndex extends ResolvedIndexAbstraction implements Wr
static final ParseField ALIASES_FIELD = new ParseField("aliases");
static final ParseField ATTRIBUTES_FIELD = new ParseField("attributes");
static final ParseField DATA_STREAM_FIELD = new ParseField("data_stream");
static final ParseField MODE_FIELD = new ParseField("mode");

private final String[] aliases;
private final String[] attributes;
private final String dataStream;
private final IndexMode mode;

ResolvedIndex(StreamInput in) throws IOException {
setName(in.readString());
this.aliases = in.readStringArray();
this.attributes = in.readStringArray();
this.dataStream = in.readOptionalString();
if (in.getTransportVersion().onOrAfter(TransportVersions.RESOLVE_INDEX_MODE_ADDED)) {
this.mode = IndexMode.readFrom(in);
} else {
this.mode = null;
}
}

ResolvedIndex(String name, String[] aliases, String[] attributes, @Nullable String dataStream) {
ResolvedIndex(String name, String[] aliases, String[] attributes, @Nullable String dataStream, IndexMode mode) {
super(name);
this.aliases = aliases;
this.attributes = attributes;
this.dataStream = dataStream;
this.mode = mode;
}

public ResolvedIndex copy(String newName) {
return new ResolvedIndex(newName, aliases, attributes, dataStream);
return new ResolvedIndex(newName, aliases, attributes, dataStream, mode);
}

public String[] getAliases() {
Expand All @@ -211,12 +221,19 @@ public String getDataStream() {
return dataStream;
}

public IndexMode getMode() {
return mode;
}

@Override
public void writeTo(StreamOutput out) throws IOException {
out.writeString(getName());
out.writeStringArray(aliases);
out.writeStringArray(attributes);
out.writeOptionalString(dataStream);
if (out.getTransportVersion().onOrAfter(TransportVersions.RESOLVE_INDEX_MODE_ADDED)) {
IndexMode.writeTo(mode, out);
}
}

@Override
Expand All @@ -230,6 +247,9 @@ public XContentBuilder toXContent(XContentBuilder builder, Params params) throws
if (Strings.isNullOrEmpty(dataStream) == false) {
builder.field(DATA_STREAM_FIELD.getPreferredName(), dataStream);
}
if (mode != null) {
builder.field(MODE_FIELD.getPreferredName(), mode.toString());
}
builder.endObject();
return builder;
}
Expand All @@ -242,12 +262,14 @@ public boolean equals(Object o) {
return getName().equals(index.getName())
&& Objects.equals(dataStream, index.dataStream)
&& Arrays.equals(aliases, index.aliases)
&& Arrays.equals(attributes, index.attributes);
&& Arrays.equals(attributes, index.attributes)
&& Objects.equals(mode, index.mode);
}

@Override
public int hashCode() {
int result = Objects.hash(getName(), dataStream);
result = 31 * result + Objects.hashCode(mode);
result = 31 * result + Arrays.hashCode(aliases);
result = 31 * result + Arrays.hashCode(attributes);
return result;
Expand Down Expand Up @@ -639,7 +661,8 @@ private static void enrichIndexAbstraction(
ia.getName(),
aliasNames,
attributes.stream().map(Enum::name).map(e -> e.toLowerCase(Locale.ROOT)).toArray(String[]::new),
ia.getParentDataStream() == null ? null : ia.getParentDataStream().getName()
ia.getParentDataStream() == null ? null : ia.getParentDataStream().getName(),
writeIndex.getIndexMode() == null ? IndexMode.STANDARD : writeIndex.getIndexMode()
)
);
}
Expand Down
Original file line number Diff line number Diff line change
@@ -0,0 +1,32 @@
/*
* Copyright Elasticsearch B.V. and/or licensed to Elasticsearch B.V. under one
* or more contributor license agreements. Licensed under the "Elastic License
* 2.0", the "GNU Affero General Public License v3.0 only", and the "Server Side
* Public License v 1"; you may not use this file except in compliance with, at
* your election, the "Elastic License 2.0", the "GNU Affero General Public
* License v3.0 only", or the "Server Side Public License, v 1".
*/

package org.elasticsearch.action.admin.indices.resolve;

import org.elasticsearch.features.FeatureSpecification;
import org.elasticsearch.features.NodeFeature;

import java.util.Set;

public class ResolveIndexFeatures implements FeatureSpecification {

// Feature published by nodes that return "mode" in indices.resolve_index responses.
public static final NodeFeature RESOLVE_INDEX_RETURNS_MODE = new NodeFeature("resolve_index_returns_mode");

@Override
public Set<NodeFeature> getFeatures() {
return Set.of(RESOLVE_INDEX_RETURNS_MODE);
}

@Override
public Set<NodeFeature> getTestFeatures() {
return Set.of(RESOLVE_INDEX_RETURNS_MODE);
}

}
Original file line number Diff line number Diff line change
Expand Up @@ -20,3 +20,4 @@ org.elasticsearch.script.ScriptFeatures
org.elasticsearch.cluster.routing.RoutingFeatures
org.elasticsearch.action.admin.cluster.stats.ClusterStatsFeatures
org.elasticsearch.ingest.IngestFeatures
org.elasticsearch.action.admin.indices.resolve.ResolveIndexFeatures
Original file line number Diff line number Diff line change
Expand Up @@ -15,6 +15,7 @@
import org.elasticsearch.action.admin.indices.resolve.ResolveIndexAction.Response;
import org.elasticsearch.common.Strings;
import org.elasticsearch.common.io.stream.Writeable;
import org.elasticsearch.index.IndexMode;
import org.elasticsearch.test.AbstractXContentSerializingTestCase;
import org.elasticsearch.xcontent.ConstructingObjectParser;
import org.elasticsearch.xcontent.XContentParser;
Expand All @@ -28,6 +29,7 @@
import static org.elasticsearch.action.admin.indices.resolve.ResolveIndexAction.ResolvedIndex.ALIASES_FIELD;
import static org.elasticsearch.action.admin.indices.resolve.ResolveIndexAction.ResolvedIndex.ATTRIBUTES_FIELD;
import static org.elasticsearch.action.admin.indices.resolve.ResolveIndexAction.ResolvedIndex.DATA_STREAM_FIELD;
import static org.elasticsearch.action.admin.indices.resolve.ResolveIndexAction.ResolvedIndex.MODE_FIELD;
import static org.elasticsearch.action.admin.indices.resolve.ResolveIndexAction.ResolvedIndexAbstraction.NAME_FIELD;
import static org.elasticsearch.action.admin.indices.resolve.ResolveIndexAction.Response.DATA_STREAMS_FIELD;
import static org.elasticsearch.action.admin.indices.resolve.ResolveIndexAction.Response.INDICES_FIELD;
Expand Down Expand Up @@ -76,8 +78,9 @@ private static ResolvedIndex createTestResolvedIndexInstance() {
String[] aliases = randomStringArray(0, 5);
String[] attributes = randomSubsetOf(List.of("open", "hidden", "frozen")).toArray(Strings.EMPTY_ARRAY);
String dataStream = randomBoolean() ? randomAlphaOfLength(6) : null;
IndexMode mode = randomFrom(IndexMode.values());

return new ResolvedIndex(name, aliases, attributes, dataStream);
return new ResolvedIndex(name, aliases, attributes, dataStream, mode);
}

private static ResolvedAlias createTestResolvedAliasInstance() {
Expand Down Expand Up @@ -109,7 +112,8 @@ static String[] randomStringArray(int minLength, int maxLength) {
(String) args[0],
args[1] != null ? ((List<String>) args[1]).toArray(Strings.EMPTY_ARRAY) : new String[0],
((List<String>) args[2]).toArray(Strings.EMPTY_ARRAY),
(String) args[3]
(String) args[3],
IndexMode.fromString((String) args[4])
)
);
@SuppressWarnings("unchecked")
Expand All @@ -133,6 +137,7 @@ static String[] randomStringArray(int minLength, int maxLength) {
INDEX_PARSER.declareStringArray(ConstructingObjectParser.optionalConstructorArg(), ALIASES_FIELD);
INDEX_PARSER.declareStringArray(ConstructingObjectParser.constructorArg(), ATTRIBUTES_FIELD);
INDEX_PARSER.declareString(ConstructingObjectParser.optionalConstructorArg(), DATA_STREAM_FIELD);
INDEX_PARSER.declareString(ConstructingObjectParser.optionalConstructorArg(), MODE_FIELD);
ALIAS_PARSER.declareString(ConstructingObjectParser.constructorArg(), NAME_FIELD);
ALIAS_PARSER.declareStringArray(ConstructingObjectParser.constructorArg(), INDICES_FIELD);
RESPONSE_PARSER.declareObjectArray(ConstructingObjectParser.constructorArg(), (p, c) -> indexFromXContent(p), INDICES_FIELD);
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -32,6 +32,7 @@
import org.elasticsearch.common.settings.Settings;
import org.elasticsearch.common.time.DateFormatter;
import org.elasticsearch.common.util.concurrent.ThreadContext;
import org.elasticsearch.index.IndexMode;
import org.elasticsearch.index.IndexNotFoundException;
import org.elasticsearch.index.IndexVersion;
import org.elasticsearch.indices.SystemIndexDescriptor;
Expand Down Expand Up @@ -68,14 +69,22 @@
public class ResolveIndexTests extends ESTestCase {

private final Object[][] indices = new Object[][] {
// name, isClosed, isHidden, isSystem, isFrozen, dataStream, aliases
{ "logs-pgsql-prod-20200101", false, false, false, true, null, new String[] { "logs-pgsql-prod" } },
{ "logs-pgsql-prod-20200102", false, false, false, true, null, new String[] { "logs-pgsql-prod", "one-off-alias" } },
{ "logs-pgsql-prod-20200103", false, false, false, false, null, new String[] { "logs-pgsql-prod" } },
{ "logs-pgsql-test-20200101", true, false, false, false, null, new String[] { "logs-pgsql-test" } },
{ "logs-pgsql-test-20200102", false, false, false, false, null, new String[] { "logs-pgsql-test" } },
{ "logs-pgsql-test-20200103", false, false, false, false, null, new String[] { "logs-pgsql-test" } },
{ ".test-system-index", false, false, true, false, null, new String[] {} } };
// name, isClosed, isHidden, isSystem, isFrozen, dataStream, aliases, mode
{ "logs-pgsql-prod-20200101", false, false, false, true, null, new String[] { "logs-pgsql-prod" }, IndexMode.STANDARD },
{
"logs-pgsql-prod-20200102",
false,
false,
false,
true,
null,
new String[] { "logs-pgsql-prod", "one-off-alias" },
IndexMode.TIME_SERIES },
{ "logs-pgsql-prod-20200103", false, false, false, false, null, new String[] { "logs-pgsql-prod" }, IndexMode.STANDARD },
{ "logs-pgsql-test-20200101", true, false, false, false, null, new String[] { "logs-pgsql-test" }, IndexMode.STANDARD },
{ "logs-pgsql-test-20200102", false, false, false, false, null, new String[] { "logs-pgsql-test" }, IndexMode.STANDARD },
{ "logs-pgsql-test-20200103", false, false, false, false, null, new String[] { "logs-pgsql-test" }, IndexMode.STANDARD },
{ ".test-system-index", false, false, true, false, null, new String[] {}, IndexMode.STANDARD } };

private final Object[][] dataStreams = new Object[][] {
// name, numBackingIndices
Expand Down Expand Up @@ -234,8 +243,8 @@ public void testResolveHiddenProperlyWithDateMath() {
String tomorrowSuffix = dateFormatter.format(now.plus(Duration.ofDays(1L)));
Object[][] indices = new Object[][] {
// name, isClosed, isHidden, isFrozen, dataStream, aliases
{ "logs-pgsql-prod-" + todaySuffix, false, true, false, false, null, Strings.EMPTY_ARRAY },
{ "logs-pgsql-prod-" + tomorrowSuffix, false, true, false, false, null, Strings.EMPTY_ARRAY } };
{ "logs-pgsql-prod-" + todaySuffix, false, true, false, false, null, Strings.EMPTY_ARRAY, IndexMode.STANDARD },
{ "logs-pgsql-prod-" + tomorrowSuffix, false, true, false, false, null, Strings.EMPTY_ARRAY, IndexMode.STANDARD } };
final ProjectMetadata project = buildProjectMetadata(randomProjectIdOrDefault(), new Object[][] {}, indices).build();
String[] requestedIndex = new String[] { "<logs-pgsql-prod-{now/d}>" };
Set<ResolvedExpression> resolvedIndices = resolver.resolveExpressions(
Expand Down Expand Up @@ -356,6 +365,7 @@ private void validateIndices(List<ResolvedIndex> resolvedIndices, String... expe
assertThat(resolvedIndex.getAliases(), is(((String[]) indexInfo[6])));
assertThat(resolvedIndex.getAttributes(), is(flagsToAttributes(indexInfo)));
assertThat(resolvedIndex.getDataStream(), equalTo((String) indexInfo[5]));
assertThat(resolvedIndex.getMode().toString(), equalTo(((IndexMode) indexInfo[7]).toString()));
}
}

Expand Down Expand Up @@ -444,7 +454,8 @@ private ProjectMetadata.Builder buildProjectMetadata(ProjectId projectId, Object
boolean hidden = (boolean) indexInfo[2];
boolean system = (boolean) indexInfo[3];
boolean frozen = (boolean) indexInfo[4];
allIndices.add(createIndexMetadata(indexName, aliases, closed, hidden, system, frozen));
IndexMode mode = (IndexMode) indexInfo[7];
allIndices.add(createIndexMetadata(indexName, aliases, closed, hidden, system, frozen, mode));
}

for (IndexMetadata index : allIndices) {
Expand All @@ -460,12 +471,14 @@ private static IndexMetadata createIndexMetadata(
boolean closed,
boolean hidden,
boolean system,
boolean frozen
boolean frozen,
IndexMode mode
) {
Settings.Builder settingsBuilder = Settings.builder()
.put(IndexMetadata.SETTING_VERSION_CREATED, IndexVersion.current())
.put("index.hidden", hidden)
.put("index.frozen", frozen);
.put("index.frozen", frozen)
.put("index.mode", mode.toString());

IndexMetadata.Builder indexBuilder = IndexMetadata.builder(name)
.settings(settingsBuilder)
Expand All @@ -482,7 +495,7 @@ private static IndexMetadata createIndexMetadata(
}

private static IndexMetadata createIndexMetadata(String name, boolean hidden) {
return createIndexMetadata(name, Strings.EMPTY_ARRAY, false, true, false, false);
return createIndexMetadata(name, Strings.EMPTY_ARRAY, false, true, false, false, IndexMode.STANDARD);
}

private static Object[] findInfo(Object[][] indexSource, String indexName) {
Expand All @@ -507,7 +520,8 @@ private Object[] findBackingIndexInfo(Object[][] dataStreamSource, String indexN
false,
false,
dataStreamName,
Strings.EMPTY_ARRAY };
Strings.EMPTY_ARRAY,
IndexMode.STANDARD };
}
}
}
Expand Down
Loading