Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
Original file line number Diff line number Diff line change
Expand Up @@ -731,19 +731,6 @@ static void resolveIndices(
);
}

// Shortcut for tests that don't need index mode filtering
static void resolveIndices(
String[] names,
IndicesOptions indicesOptions,
ProjectState projectState,
IndexNameExpressionResolver resolver,
List<ResolvedIndex> indices,
List<ResolvedAlias> aliases,
List<ResolvedDataStream> dataStreams
) {
resolveIndices(names, indicesOptions, projectState, resolver, indices, aliases, dataStreams, Collections.emptySet());
}
Copy link
Copy Markdown
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Inlined method used only in test. We should not have test only code in production


/**
* Resolves the specified names and/or wildcard expressions to index abstractions. Returns results in the supplied lists.
*
Expand Down Expand Up @@ -779,6 +766,7 @@ static void resolveIndices(
if (names.length == 1 && (Metadata.ALL.equals(names[0]) || Regex.isMatchAllPattern(names[0]))) {
names = new String[] { "**" };
}
assert indicesOptions.wildcardOptions().resolveViews() == false : "Views are not supported in ResolveIndexAction";
Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

👍

Set<ResolvedExpression> resolvedIndexAbstractions = resolver.resolveExpressions(
projectState.metadata(),
indicesOptions,
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -45,6 +45,7 @@
import java.util.ArrayList;
import java.util.List;
import java.util.Map;
import java.util.Set;
import java.util.concurrent.ConcurrentHashMap;
import java.util.concurrent.Executor;
import java.util.concurrent.atomic.AtomicBoolean;
Expand Down Expand Up @@ -387,7 +388,8 @@ private boolean hasMatchingIndices(OriginalIndices localIndices, IndicesOptions
indexNameExpressionResolver,
indices,
aliases,
dataStreams
dataStreams,
Set.of()
);

/*
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -359,8 +359,6 @@ public IndexAbstraction resolveWriteIndexAbstraction(ProjectMetadata project, Do
+ " indices without one being designated as a write index"
);
}
} else if (ia.getType() == Type.VIEW) {
throw new IllegalArgumentException("an ESQL view [" + ia.getName() + "] may not be the target of an index operation");
}
SystemResourceAccess.checkSystemIndexAccess(context, threadContext, ia.getWriteIndex());
return ia;
Expand Down Expand Up @@ -1524,6 +1522,13 @@ private static boolean ensureAliasOrIndexExists(Context context, String name, In
throw infe;
}
}
if (indexAbstraction.getType() == Type.VIEW && context.getOptions().wildcardOptions().resolveViews() == false) {
Copy link
Copy Markdown
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

This skips view when targeted directly by name.
Ideally we should not rely on a wildcard option for this.
For now I would like to merge fix as is to fix affected api.

Eventually (but before it is released) we should replace options.wildcardOptions.resolveViews with something related to concrete views, not just patterns.
cc @n1v0lg

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Something to note is that resolveAliases also only exists in the WildcardOptions, so if we add some new IndicesOptions subcategory it should probably be migrated there too. Unclear if it's worth the effort, but that's for a different investigation.

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Opened this PR to move them: #143741

if (ignoreUnavailable) {
return false;
} else {
throw notFoundException(name);
}
}
if (context.options.allowSelectors()) {
// Ensure that the selectors are present and that they are compatible with the abstractions they are used with
assert selector != null : "Earlier logic should have parsed selectors or added the default selectors already";
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -121,7 +121,7 @@ public void testResolveStarWithDefaultOptions() {
List<ResolvedAlias> aliases = new ArrayList<>();
List<ResolvedDataStream> dataStreams = new ArrayList<>();

TransportAction.resolveIndices(names, indicesOptions, projectState, resolver, indices, aliases, dataStreams);
TransportAction.resolveIndices(names, indicesOptions, projectState, resolver, indices, aliases, dataStreams, Set.of());

validateIndices(
indices,
Expand All @@ -148,7 +148,7 @@ public void testResolveStarWithAllOptions() {
List<ResolvedAlias> aliases = new ArrayList<>();
List<ResolvedDataStream> dataStreams = new ArrayList<>();

TransportAction.resolveIndices(names, indicesOptions, projectState, resolver, indices, aliases, dataStreams);
TransportAction.resolveIndices(names, indicesOptions, projectState, resolver, indices, aliases, dataStreams, Set.of());
validateIndices(
indices,
".ds-logs-mysql-prod-" + dateString + "-000001",
Expand Down Expand Up @@ -256,7 +256,7 @@ public void testResolveWithPattern() {
List<ResolvedAlias> aliases = new ArrayList<>();
List<ResolvedDataStream> dataStreams = new ArrayList<>();

TransportAction.resolveIndices(names, indicesOptions, projectState, resolver, indices, aliases, dataStreams);
TransportAction.resolveIndices(names, indicesOptions, projectState, resolver, indices, aliases, dataStreams, Set.of());

validateIndices(
indices,
Expand All @@ -283,7 +283,7 @@ public void testResolveWithMultipleNames() {
List<ResolvedAlias> aliases = new ArrayList<>();
List<ResolvedDataStream> dataStreams = new ArrayList<>();

TransportAction.resolveIndices(names, indicesOptions, projectState, resolver, indices, aliases, dataStreams);
TransportAction.resolveIndices(names, indicesOptions, projectState, resolver, indices, aliases, dataStreams, Set.of());
validateIndices(indices, ".ds-logs-mysql-prod-" + dateString + "-000003", "logs-pgsql-test-20200102");
validateAliases(aliases, "one-off-alias");
validateDataStreams(dataStreams, "logs-mysql-test");
Expand All @@ -308,7 +308,16 @@ public void testResolvePreservesBackingIndexOrdering() {
List<ResolvedIndex> indices = new ArrayList<>();
List<ResolvedAlias> aliases = new ArrayList<>();
List<ResolvedDataStream> dataStreams = new ArrayList<>();
TransportAction.resolveIndices(new String[] { "*" }, indicesOptions, projectState, resolver, indices, aliases, dataStreams);
TransportAction.resolveIndices(
new String[] { "*" },
indicesOptions,
projectState,
resolver,
indices,
aliases,
dataStreams,
Set.of()
);

assertThat(dataStreams.size(), equalTo(1));
assertThat(dataStreams.get(0).getBackingIndices(), arrayContaining(names));
Expand Down Expand Up @@ -368,7 +377,8 @@ public void testSystemIndexAccess() {
resolver,
indices,
aliases,
dataStreams
dataStreams,
Set.of()
);
// non net-new system indices are allowed even when no system indices are allowed
assertThat(indices.stream().map(ResolvedIndex::getName).collect(Collectors.toList()), hasItem(is(".test-system-1")));
Expand All @@ -387,7 +397,8 @@ public void testSystemIndexAccess() {
resolver,
indices,
aliases,
dataStreams
dataStreams,
Set.of()
);
assertThat(indices.stream().map(ResolvedIndex::getName).collect(Collectors.toList()), hasItem(is(".test-system-1")));
assertThat(indices.stream().map(ResolvedIndex::getName).collect(Collectors.toList()), hasItem(is(".test-net-new-system-1")));
Expand All @@ -399,7 +410,8 @@ public void testSystemIndexAccess() {
resolver,
indices,
aliases,
dataStreams
dataStreams,
Set.of()
);
assertThat(indices.stream().map(ResolvedIndex::getName).collect(Collectors.toList()), not(hasItem(is(".test-system-1"))));
assertThat(indices.stream().map(ResolvedIndex::getName).collect(Collectors.toList()), hasItem(is(".test-net-new-system-1")));
Expand All @@ -414,7 +426,7 @@ public void testIgnoreUnavailableFalse() {
List<ResolvedDataStream> dataStreams = new ArrayList<>();
IndexNotFoundException infe = expectThrows(
IndexNotFoundException.class,
() -> TransportAction.resolveIndices(names, indicesOptions, projectState, resolver, indices, aliases, dataStreams)
() -> TransportAction.resolveIndices(names, indicesOptions, projectState, resolver, indices, aliases, dataStreams, Set.of())
);
assertThat(infe.getMessage(), containsString("no such index [missing]"));
}
Expand All @@ -427,7 +439,7 @@ public void testAllowNoIndicesFalse() {
List<ResolvedDataStream> dataStreams = new ArrayList<>();
IndexNotFoundException infe = expectThrows(
IndexNotFoundException.class,
() -> TransportAction.resolveIndices(names, indicesOptions, projectState, resolver, indices, aliases, dataStreams)
() -> TransportAction.resolveIndices(names, indicesOptions, projectState, resolver, indices, aliases, dataStreams, Set.of())
);
assertThat(infe.getMessage(), containsString("no such index [missing*]"));
}
Expand Down
Original file line number Diff line number Diff line change
@@ -0,0 +1,83 @@
/*
* 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; you may not use this file except in compliance with the Elastic License
* 2.0.
*/

package org.elasticsearch.xpack.esql.action;

import org.elasticsearch.action.admin.indices.create.CreateIndexRequest;
import org.elasticsearch.action.admin.indices.resolve.ResolveIndexAction;
import org.elasticsearch.cluster.metadata.View;
import org.elasticsearch.index.IndexNotFoundException;
import org.elasticsearch.xpack.esql.view.PutViewAction;
import org.hamcrest.Matcher;

import java.util.List;

import static org.elasticsearch.test.hamcrest.ElasticsearchAssertions.assertAcked;
import static org.hamcrest.Matchers.containsInAnyOrder;
import static org.hamcrest.Matchers.containsString;
import static org.hamcrest.Matchers.emptyIterable;

public class ResolveIndexActionIT extends AbstractEsqlIntegTestCase {

public void testResolveIndex() {
assertAcked(client().admin().indices().create(new CreateIndexRequest("my-index-1")));
assertAcked(client().admin().indices().create(new CreateIndexRequest("other-index-2")));

assertAcked(
client().execute(
PutViewAction.INSTANCE,
new PutViewAction.Request(TEST_REQUEST_TIMEOUT, TEST_REQUEST_TIMEOUT, new View("my-view-1", "ROW r=1"))
)
);

verifyResolvedIndices(
new ResolveIndexAction.Request(new String[] { "my-index-1" }),
containsInAnyOrder("my-index-1"),
emptyIterable(),
emptyIterable()
);
verifyResolvedIndices(
new ResolveIndexAction.Request(new String[] { "my-index-*" }),
containsInAnyOrder("my-index-1"),
emptyIterable(),
emptyIterable()
);

// matched view is not returned, but it does not fail request
Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Should this comment move a few lines down and a new comment be here, since we are indeed failing the request when an explicit view name is used.

expectThrows(
IndexNotFoundException.class,
containsString("no such index [my-view-1]"),
() -> resolveIndices(new ResolveIndexAction.Request(new String[] { "my-view-1" }))
);
verifyResolvedIndices(
new ResolveIndexAction.Request(new String[] { "my-*" }),
containsInAnyOrder("my-index-1"),
emptyIterable(),
emptyIterable()
);
}

private ResolveIndexAction.Response resolveIndices(ResolveIndexAction.Request request) {
return client().admin().indices().resolveIndex(request).actionGet();
}

private void verifyResolvedIndices(
ResolveIndexAction.Request request,
Matcher<Iterable<? extends String>> indicesMatcher,
Matcher<Iterable<? extends String>> aliasesMatcher,
Matcher<Iterable<? extends String>> dataStreamsMatcher
) {
var response = resolveIndices(request);
assertThat(toStringList(response.getIndices()), indicesMatcher);
assertThat(toStringList(response.getAliases()), aliasesMatcher);
assertThat(toStringList(response.getDataStreams()), dataStreamsMatcher);
}

private static List<String> toStringList(List<? extends ResolveIndexAction.ResolvedIndexAbstraction> list) {
return list.stream().map(ResolveIndexAction.ResolvedIndexAbstraction::getName).toList();
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -272,14 +272,13 @@ setup:
query: 'FROM test | WHERE animal == "dog"'

- do:
catch: /no such index \[myview\]/
search:
index: myview
body: { query: { match_all: {} } }

- length: { hits.hits: 0 }
Copy link
Copy Markdown
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

This change also causes a _search query to fail rather than pass with 0 results.
I think this is less surprising, but maybe @craigtaverner could confirm if this is desired.

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I think the change in behaviour makes sense.


- do:
catch: /an ESQL view \[myview\] may not be the target of an index operation/
catch: /no such index \[myview\]/
Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I think the change in behaviour makes sense. But I also note that we should get the old error message if we write to write to a view, and there is no test for that. We could add such a test in a separate PR, or here.

index:
index: myview
id: "1"
Expand Down