Skip to content
Merged
Show file tree
Hide file tree
Changes from 1 commit
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
36 changes: 25 additions & 11 deletions server/src/main/java/org/elasticsearch/action/IndicesRequest.java
Original file line number Diff line number Diff line change
Expand Up @@ -43,7 +43,30 @@ default boolean includeDataStreams() {
return false;
}

interface Replaceable extends IndicesRequest {
/**
* Close PIT, Clear Scroll are LegacyActionRequest
* Reindex is essentially a LegacyActionRequest as well as CompositeIndicesRequest
* EsqlQueryRequest also a LegacyActionRequest and CompositeIndicesRequest
* SQL query request is similar to ESQL
* Painless execute request is SingleIndexNoWildcards which is an IndicesRequest
* Project tags is a LegacyActionRequest. This one does not need action filter work
*/
interface CrossProjectCandidate {

/**
* Determines whether the request type can support cross-project processing. Cross-project processing entails
* 1. UIAM authentication and authorization projects resolution.
* 2. Cross-project flat-world index resolution and error handling if applicable.
* Note: this method only determines in the request _supports_ cross-project. Whether cross-project processing
* is actually performed depends on other factors such is whether CPS is enabled and {@link IndicesOptions} if
* the request is an {@link IndicesRequest}, see also {@link org.elasticsearch.search.crossproject.CrossProjectModeDecider}.
*/
default boolean allowsCrossProject() {
return false;
}
}

interface Replaceable extends IndicesRequest, CrossProjectCandidate {
/**
* Sets the indices that the action relates to.
*/
Expand Down Expand Up @@ -81,15 +104,6 @@ default boolean allowsRemoteIndices() {
return false;
}

/**
* Determines whether the request type allows cross-project processing. Cross-project processing entails cross-project search
* index resolution and error handling. Note: this method only determines in the request _supports_ cross-project.
* Whether cross-project processing is actually performed is determined by {@link IndicesOptions}.
*/
default boolean allowsCrossProject() {
return false;
}

@Nullable // if no routing is specified
default String getProjectRouting() {
return null;
Expand All @@ -103,7 +117,7 @@ default String getProjectRouting() {
*
* This may change with https://github.com/elastic/elasticsearch/issues/105598
*/
interface SingleIndexNoWildcards extends IndicesRequest {
interface SingleIndexNoWildcards extends IndicesRequest, CrossProjectCandidate {
default boolean allowsRemoteIndices() {
return true;
}
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -44,11 +44,18 @@ public boolean crossProjectEnabled() {
return crossProjectEnabled;
}

public boolean resolvesCrossProject(IndicesRequest.Replaceable request) {
public boolean resolvesCrossProject(IndicesRequest.CrossProjectCandidate request) {
if (crossProjectEnabled == false) {
return false;
}

// TODO: The following check can be an method on the request itself
return request.allowsCrossProject() && request.indicesOptions().resolveCrossProjectIndexExpression();
if (request.allowsCrossProject() == false) {
return false;
}
if (request instanceof IndicesRequest indicesRequest) {
return indicesRequest.indicesOptions().resolveCrossProjectIndexExpression();
}
return true;
}
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,91 @@
/*
* ELASTICSEARCH CONFIDENTIAL
* __________________
*
* Copyright Elasticsearch B.V. All rights reserved.
*
* NOTICE: All information contained herein is, and remains
* the property of Elasticsearch B.V. and its suppliers, if any.
* The intellectual and technical concepts contained herein
* are proprietary to Elasticsearch B.V. and its suppliers and
* may be covered by U.S. and Foreign Patents, patents in
* process, and are protected by trade secret or copyright
* law. Dissemination of this information or reproduction of
* this material is strictly forbidden unless prior written
* permission is obtained from Elasticsearch B.V.
*/

package org.elasticsearch.search.crossproject;

import org.elasticsearch.action.IndicesRequest;
import org.elasticsearch.action.support.IndicesOptions;
import org.elasticsearch.common.settings.Settings;
import org.elasticsearch.test.ESTestCase;

import static org.hamcrest.Matchers.is;

public class CrossProjectModeDeciderTests extends ESTestCase {

public void testResolvesCrossProject() {
doTestResolvesCrossProject(new CrossProjectModeDecider(Settings.builder().build()), false);
doTestResolvesCrossProject(
new CrossProjectModeDecider(Settings.builder().put("serverless.cross_project.enabled", true).build()),
true
);
}

private void doTestResolvesCrossProject(CrossProjectModeDecider crossProjectModeDecider, boolean expected) {
final var cpsIndicesOptions = IndicesOptions.builder(org.elasticsearch.action.support.IndicesOptions.DEFAULT)
.crossProjectModeOptions(new IndicesOptions.CrossProjectModeOptions(true))
.build();

final var candidateButNotAllowed = randomFrom(
new CrossProjectCandidateImpl(false),
new IndicesRequestImpl(false, randomFrom(IndicesOptions.DEFAULT, cpsIndicesOptions))
);
final var candidateAndAllowed = new CrossProjectCandidateImpl(true);

final var indicesRequestNoCpsOption = new IndicesRequestImpl(true, IndicesOptions.DEFAULT);
final var indicesRequestWithCpsOption = new IndicesRequestImpl(true, cpsIndicesOptions);

assertFalse(crossProjectModeDecider.resolvesCrossProject(candidateButNotAllowed));
assertFalse(crossProjectModeDecider.resolvesCrossProject(indicesRequestNoCpsOption));

assertThat(crossProjectModeDecider.resolvesCrossProject(candidateAndAllowed), is(expected));
assertThat(crossProjectModeDecider.resolvesCrossProject(indicesRequestWithCpsOption), is(expected));
}

private static class CrossProjectCandidateImpl implements IndicesRequest.CrossProjectCandidate {

private boolean allowsCrossProject;

CrossProjectCandidateImpl(boolean allowsCrossProject) {
this.allowsCrossProject = allowsCrossProject;
}

@Override
public boolean allowsCrossProject() {
return allowsCrossProject;
}
}

private static class IndicesRequestImpl extends CrossProjectCandidateImpl implements IndicesRequest {

private IndicesOptions indicesOptions;

IndicesRequestImpl(boolean allowsCrossProject, IndicesOptions indicesOptions) {
super(allowsCrossProject);
this.indicesOptions = indicesOptions;
}

@Override
public String[] indices() {
return new String[0];
}

@Override
public IndicesOptions indicesOptions() {
return indicesOptions;
}
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -167,7 +167,8 @@ ResolvedIndices tryResolveWithoutWildcards(String action, TransportRequest trans
}

boolean resolvesCrossProject(TransportRequest request) {
return request instanceof IndicesRequest.Replaceable replaceable && crossProjectModeDecider.resolvesCrossProject(replaceable);
return request instanceof IndicesRequest.CrossProjectCandidate crossProjectCandidate
&& crossProjectModeDecider.resolvesCrossProject(crossProjectCandidate);
}

private static boolean requiresWildcardExpansion(IndicesRequest indicesRequest) {
Expand Down Expand Up @@ -560,6 +561,7 @@ private static void setResolvedIndexExpressionsIfUnset(IndicesRequest.Replaceabl
+ "]";
logger.debug(message);
// we are excepting `*,-*` below since we've observed this already -- keeping this assertion to catch other cases
// If more exceptions are found, we can add a comment to above linked issue and relax this check further
assert replaceable.indices() == null || isNoneExpression(replaceable.indices()) : message;
Comment on lines +564 to 565
Copy link
Member Author

Choose a reason for hiding this comment

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

Slobodan ran into this assertion failure. But I haven't seen it so far. This is a known issue. So I added a comment to say that we can relax it if it is triggered.

Copy link
Contributor

Choose a reason for hiding this comment

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

I run into this while running a newly added CPS ES|QL test.

}
}
Expand Down