Skip to content

Get Aliases with wildcard exclusion expression #34230

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

Merged
merged 13 commits into from
Jan 29, 2019
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 @@ -59,7 +59,7 @@ setup:

- do:
indices.get_alias:
name: _all
name: '*'

- match: {test_index.aliases.test_alias: {}}
- match: {test_index.aliases.test_blias: {}}
Expand Down Expand Up @@ -220,7 +220,7 @@ setup:
- is_false: test_index_2.aliases.test_blias

---
"Get aliases via /pref*/_alias/{name}":
"Get aliases via /*suf/_alias/{name}":

- do:
indices.get_alias:
Expand Down
Original file line number Diff line number Diff line change
@@ -0,0 +1,140 @@
---
setup:

- do:
indices.create:
index: test_index
body:
aliases:
test_alias_1: {}
test_alias_2: {}
test_blias_1: {}
test_blias_2: {}
test: {}

---
"Get aliases wildcard and inclusion":
- do:
indices.get_alias:
name: test_alias*,test_blias_1

- match: {test_index.aliases.test_alias_1: {}}
- match: {test_index.aliases.test_alias_2: {}}
- match: {test_index.aliases.test_blias_1: {}}
- is_false: test_index.aliases.test_blias_2
- is_false: test_index.aliases.test

---
"Get aliases wildcard and simple exclusion":
- skip:
version: " - 6.99.99"
reason: Exclusions in the alias expression are not handled
- do:
indices.get_alias:
name: test_blias_2,test_alias*,-test_alias_1

- is_false: test_index.aliases.test_alias_1
- match: {test_index.aliases.test_alias_2: {}}
- is_false: test_index.aliases.test_blias_1
- match: {test_index.aliases.test_blias_2: {}}
- is_false: test_index.aliases.test

---
"Get aliases and wildcard exclusion":
- skip:
version: " - 6.99.99"
reason: Exclusions in the alias expression are not handled
- do:
indices.get_alias:
name: test_alias_1,test_blias_1,-test_alias*

- is_false: test_index.aliases.test_alias_1
- is_false: test_index.aliases.test_alias_2
- match: {test_index.aliases.test_blias_1: {}}
- is_false: test_index.aliases.test_blias_2
- is_false: test_index.aliases.test

- do:
indices.get_alias:
name: test_blias_2,tes*,-test_alias*

- is_false: test_index.aliases.test_alias_1
- is_false: test_index.aliases.test_alias_2
- match: {test_index.aliases.test_blias_1: {}}
- match: {test_index.aliases.test_blias_2: {}}
- match: {test_index.aliases.test: {}}

---
"Non-existent exclusion alias before wildcard returns 404":
- skip:
version: " - 6.99.99"
reason: Exclusions in the alias expression are not handled
- do:
catch: missing
indices.get_alias:
name: -test_alias_1,test_alias*,-test_alias_2

- match: { 'status': 404}
- match: { 'error': 'alias [-test_alias_1] missing' }
- match: {test_index.aliases.test_alias_1: {}}
- is_false: test_index.aliases.test_alias_2
- is_false: test_index.aliases.test_blias_1
- is_false: test_index.aliases.test_blias_2
- is_false: test_index.aliases.test

- do:
catch: missing
indices.get_alias:
name: -test_alias_1,-non-existing,test_alias*,-test

- match: { 'status': 404}
- match: { 'error': 'aliases [-non-existing,-test_alias_1] missing' }
- match: {test_index.aliases.test_alias_1: {}}
- match: {test_index.aliases.test_alias_2: {}}
- is_false: test_index.aliases.test_blias_1
- is_false: test_index.aliases.test_blias_2
- is_false: test_index.aliases.test

---
"Missing exclusions does not fire 404":
- skip:
version: " - 6.99.99"
reason: Exclusions in the alias expression are not handled
- do:
indices.get_alias:
name: test_alias*,-non-existent,test_blias*,-test

- match: {test_index.aliases.test_alias_1: {}}
- match: {test_index.aliases.test_alias_2: {}}
- match: {test_index.aliases.test_blias_1: {}}
- match: {test_index.aliases.test_blias_2: {}}
- is_false: test_index.aliases.test

---
"Exclusion of non wildcarded aliases":
- skip:
version: " - 6.99.99"
reason: Exclusions in the alias expression are not handled
- do:
indices.get_alias:
name: test_alias_1,test_blias_2,-test_alias*,-test_blias_2

- match: { '': {}}

---
"Wildcard exclusions does not trigger 404":
- skip:
version: " - 6.99.99"
reason: Exclusions in the alias expression are not handled
- do:
catch: missing
indices.get_alias:
name: -non-existent,-non-existent*,-another

- match: { 'status': 404}
- match: { 'error': 'alias [-non-existent] missing' }
- is_false: test_index.aliases.test_alias_1
- is_false: test_index.aliases.test_alias_2
- is_false: test_index.aliases.test_blias_1
- is_false: test_index.aliases.test_blias_2
- is_false: test_index.aliases.test
Original file line number Diff line number Diff line change
Expand Up @@ -25,11 +25,11 @@
import org.elasticsearch.action.support.IndicesOptions;
import org.elasticsearch.client.node.NodeClient;
import org.elasticsearch.cluster.metadata.AliasMetaData;
import org.elasticsearch.cluster.metadata.MetaData;
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;
Expand All @@ -41,14 +41,12 @@
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 java.util.TreeSet;

import static org.elasticsearch.rest.RestRequest.Method.GET;
import static org.elasticsearch.rest.RestRequest.Method.HEAD;
Expand All @@ -75,6 +73,94 @@ public String getName() {
return "get_aliases_action";
}

static RestResponse buildRestResponse(boolean aliasesExplicitlyRequested, String[] requestedAliases,
ImmutableOpenMap<String, List<AliasMetaData>> responseAliasMap, XContentBuilder builder) throws Exception {
final Set<String> indicesToDisplay = new HashSet<>();
final Set<String> returnedAliasNames = new HashSet<>();
for (final ObjectObjectCursor<String, List<AliasMetaData>> cursor : responseAliasMap) {
for (final AliasMetaData aliasMetaData : cursor.value) {
if (aliasesExplicitlyRequested) {
// only display indices that have aliases
indicesToDisplay.add(cursor.key);
}
returnedAliasNames.add(aliasMetaData.alias());
}
}
// compute explicitly requested aliases that have are not returned in the result
final SortedSet<String> missingAliases = new TreeSet<>();
// first wildcard index, leading "-" as an alias name after this index means
// that it is an exclusion
int firstWildcardIndex = requestedAliases.length;
for (int i = 0; i < requestedAliases.length; i++) {
if (Regex.isSimpleMatchPattern(requestedAliases[i])) {
firstWildcardIndex = i;
break;
}
}
for (int i = 0; i < requestedAliases.length; i++) {
if (MetaData.ALL.equals(requestedAliases[i]) || Regex.isSimpleMatchPattern(requestedAliases[i])
|| (i > firstWildcardIndex && requestedAliases[i].charAt(0) == '-')) {
// only explicitly requested aliases will be called out as missing (404)
continue;
}
// check if aliases[i] is subsequently excluded
int j = Math.max(i + 1, firstWildcardIndex);
for (; j < requestedAliases.length; j++) {
if (requestedAliases[j].charAt(0) == '-') {
// this is an exclude pattern
if (Regex.simpleMatch(requestedAliases[j].substring(1), requestedAliases[i])
|| MetaData.ALL.equals(requestedAliases[j].substring(1))) {
// aliases[i] is excluded by aliases[j]
break;
}
}
}
if (j == requestedAliases.length) {
// explicitly requested aliases[i] is not excluded by any subsequent "-" wildcard in expression
if (false == returnedAliasNames.contains(requestedAliases[i])) {
// aliases[i] is not in the result set
missingAliases.add(requestedAliases[i]);
}
}
}

final RestStatus status;
builder.startObject();
{
if (missingAliases.isEmpty()) {
status = RestStatus.OK;
} else {
status = RestStatus.NOT_FOUND;
final String message;
if (missingAliases.size() == 1) {
message = String.format(Locale.ROOT, "alias [%s] missing", Strings.collectionToCommaDelimitedString(missingAliases));
} else {
message = String.format(Locale.ROOT, "aliases [%s] missing", Strings.collectionToCommaDelimitedString(missingAliases));
}
builder.field("error", message);
builder.field("status", status.getStatus());
}

for (final ObjectObjectCursor<String, List<AliasMetaData>> entry : responseAliasMap) {
if (aliasesExplicitlyRequested == false || (aliasesExplicitlyRequested && indicesToDisplay.contains(entry.key))) {
builder.startObject(entry.key);
{
builder.startObject("aliases");
{
for (final AliasMetaData alias : entry.value) {
AliasMetaData.Builder.toXContent(alias, builder, ToXContent.EMPTY_PARAMS);
}
}
builder.endObject();
}
builder.endObject();
}
}
}
builder.endObject();
return new BytesRestResponse(status, builder);
}

@Override
public RestChannelConsumer prepareRequest(final RestRequest request, final NodeClient client) throws IOException {
// The TransportGetAliasesAction was improved do the same post processing as is happening here.
Expand All @@ -94,76 +180,8 @@ 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 {
final ImmutableOpenMap<String, List<AliasMetaData>> aliasMap = response.getAliases();

final Set<String> aliasNames = new HashSet<>();
final Set<String> indicesToDisplay = new HashSet<>();
for (final ObjectObjectCursor<String, List<AliasMetaData>> cursor : aliasMap) {
for (final AliasMetaData aliasMetaData : cursor.value) {
aliasNames.add(aliasMetaData.alias());
if (namesProvided) {
indicesToDisplay.add(cursor.key);
}
}
}

// 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;
}
}
}
}
difference.removeAll(matches);

final RestStatus status;
builder.startObject();
{
if (difference.isEmpty()) {
status = RestStatus.OK;
} else {
status = RestStatus.NOT_FOUND;
final String message;
if (difference.size() == 1) {
message = String.format(Locale.ROOT, "alias [%s] missing",
Strings.collectionToCommaDelimitedString(difference));
} else {
message = String.format(Locale.ROOT, "aliases [%s] missing",
Strings.collectionToCommaDelimitedString(difference));
}
builder.field("error", message);
builder.field("status", status.getStatus());
}

for (final ObjectObjectCursor<String, List<AliasMetaData>> entry : response.getAliases()) {
if (namesProvided == false || (namesProvided && indicesToDisplay.contains(entry.key))) {
builder.startObject(entry.key);
{
builder.startObject("aliases");
{
for (final AliasMetaData alias : entry.value) {
AliasMetaData.Builder.toXContent(alias, builder, ToXContent.EMPTY_PARAMS);
}
}
builder.endObject();
}
builder.endObject();
}
}
}
builder.endObject();
return new BytesRestResponse(status, builder);
return buildRestResponse(namesProvided, aliases, response.getAliases(), builder);
}

});
}

Expand Down
Loading