-
Notifications
You must be signed in to change notification settings - Fork 25k
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
GET aliases should 404 if aliases are missing #25043
Changes from 5 commits
af8cf64
aca1a4f
e52f4bd
0e6d1f7
e13b5d8
af53623
23e50a9
90022ae
6917440
File filter
Filter by extension
Conversations
Jump to
Diff view
Diff view
There are no files selected for viewing
Original file line number | Diff line number | Diff line change |
---|---|---|
|
@@ -20,14 +20,16 @@ | |
package org.elasticsearch.rest.action.admin.indices; | ||
|
||
import com.carrotsearch.hppc.cursors.ObjectObjectCursor; | ||
|
||
import org.elasticsearch.action.admin.indices.alias.get.GetAliasesRequest; | ||
import org.elasticsearch.action.admin.indices.alias.get.GetAliasesResponse; | ||
import org.elasticsearch.action.support.IndicesOptions; | ||
import org.elasticsearch.client.node.NodeClient; | ||
import org.elasticsearch.cluster.metadata.AliasMetaData; | ||
import org.elasticsearch.common.Strings; | ||
import org.elasticsearch.common.collect.ImmutableOpenMap; | ||
import org.elasticsearch.common.regex.Regex; | ||
import org.elasticsearch.common.settings.Settings; | ||
import org.elasticsearch.common.util.set.Sets; | ||
import org.elasticsearch.common.xcontent.ToXContent; | ||
import org.elasticsearch.common.xcontent.XContentBuilder; | ||
import org.elasticsearch.rest.BaseRestHandler; | ||
|
@@ -39,9 +41,13 @@ | |
import org.elasticsearch.rest.action.RestBuilderListener; | ||
|
||
import java.io.IOException; | ||
import java.util.ArrayList; | ||
import java.util.Arrays; | ||
import java.util.HashSet; | ||
import java.util.List; | ||
import java.util.Locale; | ||
import java.util.Set; | ||
import java.util.SortedSet; | ||
import java.util.stream.Collectors; | ||
|
||
import static org.elasticsearch.rest.RestRequest.Method.GET; | ||
|
@@ -80,41 +86,68 @@ public RestChannelConsumer prepareRequest(final RestRequest request, final NodeC | |
return channel -> client.admin().indices().getAliases(getAliasesRequest, new RestBuilderListener<GetAliasesResponse>(channel) { | ||
@Override | ||
public RestResponse buildResponse(GetAliasesResponse response, XContentBuilder builder) throws Exception { | ||
if (response.getAliases().isEmpty()) { | ||
// empty body if indices were specified but no matching aliases exist | ||
if (indices.length > 0) { | ||
return new BytesRestResponse(OK, builder.startObject().endObject()); | ||
} else { | ||
final String message = String.format(Locale.ROOT, "alias [%s] missing", toNamesString(getAliasesRequest.aliases())); | ||
builder.startObject(); | ||
{ | ||
builder.field("error", message); | ||
builder.field("status", RestStatus.NOT_FOUND.getStatus()); | ||
final ImmutableOpenMap<String, List<AliasMetaData>> aliasMap = response.getAliases(); | ||
|
||
final Set<String> aliasNames = new HashSet<>(); | ||
for (final ObjectObjectCursor<String, List<AliasMetaData>> cursor : aliasMap) { | ||
for (final AliasMetaData aliasMetaData : cursor.value) { | ||
aliasNames.add(aliasMetaData.alias()); | ||
} | ||
} | ||
|
||
// first remove requested aliases that are exact matches | ||
final SortedSet<String> difference = Sets.sortedDifference(Arrays.stream(aliases).collect(Collectors.toSet()), aliasNames); | ||
|
||
// now remove requested aliases that contain wildcards that are simple matches | ||
final List<String> matches = new ArrayList<>(); | ||
outer: | ||
for (final String pattern : difference) { | ||
if (pattern.contains("*")) { | ||
for (final String aliasName : aliasNames) { | ||
if (Regex.simpleMatch(pattern, aliasName)) { | ||
matches.add(pattern); | ||
continue outer; | ||
} | ||
} | ||
builder.endObject(); | ||
return new BytesRestResponse(RestStatus.NOT_FOUND, builder); | ||
} | ||
} else { | ||
builder.startObject(); | ||
{ | ||
for (final ObjectObjectCursor<String, List<AliasMetaData>> entry : response.getAliases()) { | ||
builder.startObject(entry.key); | ||
} | ||
difference.removeAll(matches); | ||
|
||
final RestStatus status; | ||
builder.startObject(); | ||
{ | ||
if (!difference.isEmpty()) { | ||
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. We can remove the if (difference.isEmpty()) {
status = RestStatus.OK;
} else {
... the error stuff ...
} There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. Okay. |
||
status = RestStatus.NOT_FOUND; | ||
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. Personally I think we should return There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. 206 is wrong, it's for range requests only. Also, 2xx is often not seen as an error client side while 4xx is. |
||
final String message; | ||
if (difference.size() == 1) { | ||
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. I think we should have a consistent message regardless of the number of aliases, I know it's bad form for people to write tests against error messages, but that doesn't mean people don't. So, I think we should stick with just There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. I disagree that it's bad form, and I have a test for both cases. It's a pet peeve of mine to see messages like "error(s) were encountered while processing"; the information to determine whether "an error was encountered while processing" or "errors were encountered while processing" should be provided is available, the programmer just needs to write some simple code to give a correct error message. Why do you think it should be consistent instead of correct in every case? There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more.
As I mentioned above, mostly for users wrapping ES in their own application, anyone that wants to "wrap" this error needs to change parsing Like I said above though, I'm only +0 on it, if you don't agree we don't have to change it. There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. @dakrone Yeah I'm not sure about that concern since I do not think we offer any guarantees on these error messages. |
||
message = String.format(Locale.ROOT, "alias [%s] missing", toNamesString(difference.iterator().next())); | ||
} else { | ||
message = String.format(Locale.ROOT, "aliases [%s] missing", toNamesString(difference.toArray(new String[0]))); | ||
} | ||
builder.field("error", message); | ||
builder.field("status", RestStatus.NOT_FOUND.getStatus()); | ||
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. could be |
||
} else { | ||
status = RestStatus.OK; | ||
} | ||
|
||
for (final ObjectObjectCursor<String, List<AliasMetaData>> entry : response.getAliases()) { | ||
builder.startObject(entry.key); | ||
{ | ||
builder.startObject("aliases"); | ||
{ | ||
builder.startObject("aliases"); | ||
{ | ||
for (final AliasMetaData alias : entry.value) { | ||
AliasMetaData.Builder.toXContent(alias, builder, ToXContent.EMPTY_PARAMS); | ||
} | ||
for (final AliasMetaData alias : entry.value) { | ||
AliasMetaData.Builder.toXContent(alias, builder, ToXContent.EMPTY_PARAMS); | ||
} | ||
builder.endObject(); | ||
} | ||
builder.endObject(); | ||
} | ||
builder.endObject(); | ||
} | ||
builder.endObject(); | ||
return new BytesRestResponse(OK, builder); | ||
} | ||
builder.endObject(); | ||
return new BytesRestResponse(status, builder); | ||
} | ||
|
||
}); | ||
} | ||
|
||
|
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -1,5 +1,8 @@ | ||
--- | ||
"Basic test for delete alias": | ||
- skip: | ||
version: " - 5.99.99" | ||
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. I think this should be There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. I disagree, see my top-level comment. |
||
reason: Previous versions did not 404 on missing aliases | ||
|
||
- do: | ||
indices.create: | ||
|
@@ -25,8 +28,10 @@ | |
name: testali | ||
|
||
- do: | ||
catch: missing | ||
indices.get_alias: | ||
index: testind | ||
name: testali | ||
|
||
- match: { '': {}} | ||
- match: { 'status': 404 } | ||
- match: { 'error': 'alias [testali] missing' } |
Original file line number | Diff line number | Diff line change |
---|---|---|
|
@@ -78,7 +78,6 @@ setup: | |
|
||
--- | ||
"Get aliases via /{index}/_alias/prefix*": | ||
|
||
- do: | ||
indices.get_alias: | ||
index: test_index | ||
|
@@ -166,25 +165,51 @@ setup: | |
|
||
|
||
--- | ||
"Non-existent alias on an existing index returns an empty body": | ||
"Non-existent alias on an existing index returns 404": | ||
- skip: | ||
version: " - 5.99.99" | ||
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. Same here about version There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. I disagree, see my top-level comment. |
||
reason: Previous versions did not 404 on missing aliases | ||
|
||
- do: | ||
catch: missing | ||
indices.get_alias: | ||
index: test_index | ||
name: non-existent | ||
|
||
- match: { '': {}} | ||
- match: { 'status': 404} | ||
- match: { 'error': 'alias [non-existent] missing' } | ||
|
||
--- | ||
"Existent and non-existent alias returns just the existing": | ||
"Existent and non-existent alias returns 404 and the existing alias": | ||
- skip: | ||
version: " - 5.99.99" | ||
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. Same here for version There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. I disagree, see my top-level comment. |
||
reason: Previous versions did not 404 on missing aliases | ||
|
||
- do: | ||
catch: missing | ||
indices.get_alias: | ||
index: test_index | ||
name: test_alias,non-existent | ||
|
||
- match: {test_index.aliases.test_alias: {}} | ||
- is_false: test_index.aliases.non-existent | ||
- match: { 'status': 404 } | ||
- match: { 'error': 'alias [non-existent] missing' } | ||
- match: { test_index.aliases.test_alias: { } } | ||
|
||
--- | ||
"Existent and non-existent aliases returns 404 and the existing alias": | ||
- skip: | ||
version: " - 5.99.99" | ||
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. And same here for version There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. I disagree, see my top-level comment. |
||
reason: Previous versions did not 404 on missing aliases | ||
|
||
- do: | ||
catch: missing | ||
indices.get_alias: | ||
index: test_index | ||
name: test_alias,non-existent,another-non-existent | ||
|
||
- match: { 'status': 404 } | ||
- match: { 'error': 'aliases [another-non-existent,non-existent] missing' } | ||
- match: { test_index.aliases.test_alias: { } } | ||
|
||
--- | ||
"Getting alias on an non-existent index should return 404": | ||
|
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
You can probably use
aliasMap.values()
since you don't need the key for anything right? I don't think it's necessarily any better though, so either way is fine.There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Okay.