Skip to content

Commit 1581480

Browse files
Do not assume we hear back from all linked projects when validating resolved index expressions for CPS
1 parent d5c84af commit 1581480

File tree

2 files changed

+130
-1
lines changed

2 files changed

+130
-1
lines changed

server/src/main/java/org/elasticsearch/search/crossproject/CrossProjectIndexResolutionValidator.java

Lines changed: 10 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -188,7 +188,16 @@ private static ElasticsearchException checkSingleRemoteExpression(
188188
IndicesOptions indicesOptions
189189
) {
190190
ResolvedIndexExpressions resolvedExpressionsInProject = remoteResolvedExpressions.get(projectAlias);
191-
assert resolvedExpressionsInProject != null : "We should always have resolved expressions from linked project";
191+
/*
192+
* We look for an index in the linked projects only after we've ascertained that it does not exist
193+
* on the origin. However, if we couldn't find a valid entry for the same index in the resolved
194+
* expressions `Map<K,V>` from the linked projects, it could mean that we did not hear back from
195+
* the linked project due to some error that occurred on it. In such case, the scenario effectively
196+
* is identical to the one where we could not find an index anywhere.
197+
*/
198+
if (resolvedExpressionsInProject == null) {
199+
return new IndexNotFoundException(remoteExpression);
200+
}
192201

193202
ResolvedIndexExpression.LocalExpressions matchingExpression = findMatchingExpression(resolvedExpressionsInProject, resource);
194203
if (matchingExpression == null) {

server/src/test/java/org/elasticsearch/search/crossproject/CrossProjectIndexResolutionValidatorTests.java

Lines changed: 120 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -133,6 +133,126 @@ public void testMissingFlatExpressionWithStrictIgnoreUnavailable() {
133133
assertThat(e.getMessage(), containsString("no such index [logs]"));
134134
}
135135

136+
public void testMissingResponseFromLinkedProjectsWithStrictIgnoreUnavailable() {
137+
ResolvedIndexExpressions local = new ResolvedIndexExpressions(
138+
List.of(
139+
new ResolvedIndexExpression(
140+
"logs",
141+
new ResolvedIndexExpression.LocalExpressions(
142+
Set.of(),
143+
ResolvedIndexExpression.LocalIndexResolutionResult.CONCRETE_RESOURCE_NOT_VISIBLE,
144+
null
145+
),
146+
Set.of("P1:logs")
147+
)
148+
)
149+
);
150+
151+
// logs does not exist in the remote responses and indices options are strict. We expect an error.
152+
var e = CrossProjectIndexResolutionValidator.validate(getStrictIgnoreUnavailable(), null, local, Map.of());
153+
assertNotNull(e);
154+
assertThat(e, instanceOf(IndexNotFoundException.class));
155+
assertThat(e.getMessage(), containsString("no such index [logs]"));
156+
}
157+
158+
public void testMissingResponseFromLinkedProjectsWithLenientIgnoreUnavailable() {
159+
ResolvedIndexExpressions local = new ResolvedIndexExpressions(
160+
List.of(
161+
new ResolvedIndexExpression(
162+
"logs",
163+
new ResolvedIndexExpression.LocalExpressions(
164+
Set.of(),
165+
ResolvedIndexExpression.LocalIndexResolutionResult.CONCRETE_RESOURCE_NOT_VISIBLE,
166+
null
167+
),
168+
Set.of("P1:logs")
169+
)
170+
)
171+
);
172+
173+
// logs does not exist in the remote responses and ignore_unavailable is set to true. We do not expect an error.
174+
var e = CrossProjectIndexResolutionValidator.validate(getLenientIndicesOptions(), null, local, Map.of());
175+
assertNull(e);
176+
}
177+
178+
public void testMissingResponseFromLinkedProjectsWithStrictAllowNoIndices() {
179+
ResolvedIndexExpressions local = new ResolvedIndexExpressions(
180+
List.of(
181+
new ResolvedIndexExpression(
182+
"logs*",
183+
new ResolvedIndexExpression.LocalExpressions(
184+
Set.of(),
185+
ResolvedIndexExpression.LocalIndexResolutionResult.SUCCESS,
186+
null
187+
),
188+
Set.of("P1:logs*")
189+
)
190+
)
191+
);
192+
193+
// Mimic no response from P1 project.
194+
var remote = Map.of(
195+
"P2",
196+
new ResolvedIndexExpressions(
197+
List.of(
198+
new ResolvedIndexExpression(
199+
"not-logs*",
200+
new ResolvedIndexExpression.LocalExpressions(
201+
Set.of("not-logs"),
202+
ResolvedIndexExpression.LocalIndexResolutionResult.SUCCESS,
203+
null
204+
),
205+
Set.of()
206+
)
207+
)
208+
)
209+
);
210+
211+
// Index expression is a wildcard-ed expression but the indices options are strict. We expect an error.
212+
var e = CrossProjectIndexResolutionValidator.validate(getStrictAllowNoIndices(), null, local, remote);
213+
assertNotNull(e);
214+
assertThat(e, instanceOf(IndexNotFoundException.class));
215+
assertThat(e.getMessage(), containsString("no such index [logs*]"));
216+
}
217+
218+
public void testMissingResponseFromLinkedProjectsWithLenientAllowNoIndices() {
219+
ResolvedIndexExpressions local = new ResolvedIndexExpressions(
220+
List.of(
221+
new ResolvedIndexExpression(
222+
"logs*",
223+
new ResolvedIndexExpression.LocalExpressions(
224+
Set.of(),
225+
ResolvedIndexExpression.LocalIndexResolutionResult.SUCCESS,
226+
null
227+
),
228+
Set.of("P1:logs*")
229+
)
230+
)
231+
);
232+
233+
// Mimic no response from P1 project.
234+
var remote = Map.of(
235+
"P2",
236+
new ResolvedIndexExpressions(
237+
List.of(
238+
new ResolvedIndexExpression(
239+
"not-logs*",
240+
new ResolvedIndexExpression.LocalExpressions(
241+
Set.of("not-logs"),
242+
ResolvedIndexExpression.LocalIndexResolutionResult.SUCCESS,
243+
null
244+
),
245+
Set.of()
246+
)
247+
)
248+
)
249+
);
250+
251+
// Index expression is a wildcard-ed expression but the indices options are lenient. We do not expect an error.
252+
var e = CrossProjectIndexResolutionValidator.validate(getLenientIndicesOptions(), null, local, remote);
253+
assertNull(e);
254+
}
255+
136256
public void testUnauthorizedFlatExpressionWithStrictIgnoreUnavailable() {
137257
final var exception = new ElasticsearchSecurityException("authorization errors while resolving [logs]");
138258
ResolvedIndexExpressions local = new ResolvedIndexExpressions(

0 commit comments

Comments
 (0)